Channel ends

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Channel ends

Post by Folknology »

In XC why can I not place chanends inside structures?

Code: Select all

struct {
  chanend rx;
  chanend tx;
} Mychannel;
The compiler complains :

Code: Select all

ce.xc:2: error: field `rx' has resource type
ce.xc:3: error: field `tx' has resource type
Why does this happen?
how can it be fixed?
I would like to be able to place chanends inside structure please

regards
Al


jhrose
Active Member
Posts: 40
Joined: Mon Dec 14, 2009 11:18 am

Post by jhrose »

Hei,

The Programming XC book describes chanend (ports, timers, cores and clocks) as resource types:
Appendix A.3.2 Basic Types, "Channel ends, ports, timers and cores are collectively referred to as having resource types. Except for cores, which do not reserve storage, an object of resource type refers to a location in storage in which an identifier for the resource is recorded."

Appendix A.7.4 Structure and Union Declarations, "A structure or union may not contain a member of incomplete or resource type, except that a structure may contain a member of type port or timer. If a structure is declared to have a member with one of these types then variables of the structure may be declared only as external declarations"

Appendix A.7.7. Meaning of Declarators, "A port may be declared as an external declaration (see §A.9) or as a parameter only. A channel may be declared as a local variable only and a channel end may be declared as a parameter only. A structure containing a member or, recursively, any submember of resource type may be declared as an external declaration only."

Appendix A.9.2 External Declarations, "The term “external” refers to their location outside functions, and is not directly connected with the extern keyword; the storage class for an externally-declared object may be left empty, or it may be specified as extern or static."

So, the XC language specification allows you to write

Code: Select all

typedef struct{ port p; timer t; } event;
at file-global scope but not a function-level scope. Yet you can't write

Code: Select all

typedef struct{ chanend c; } message;
at any scope. What you kind of want is a "reference to a resource type", except you can't declare a structure with a reference to any type either, e.g. you can't write

Code: Select all

struct { chanend ℞  chanend &tx;} Mychannel;
or even

Code: Select all

typedef struct { int &s } signal;
So, you will have to pass chanend's by reference as parameters in function calls, rather than through structures.
[Even in PiXC only protocols are proposed as types, and chans/chanends as types are only mooted in context as a proper type in 6.2.]
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

Well the whole thing doesn't really make sense from a type point of view consider:

Code: Select all


void f(chanend c);
void g(chanend c);

main(void){
  chan c;
  par {
    f(c);
    g(c);
  }
}

So we create c which is of type chan and pass it to 2 functions which expect type chanend! There is no obvious referencing '&' happening here?

Code: Select all


void f(chanend c);
void g(chanend c);

main(void){
  chan c
  par {
    f(c.ce1);
    g(c.ce2);
  }
}

we may as well write :

Code: Select all


void f(void c);
void g(void c);

main(void){
  chan c;
  par {
    f(c);
    g(c);
  }
}
Why aren't channels structures made of two chanends or an array of chanends?

Code: Select all


void f(chanend c);
void g(chanend c);

main(void){
  chan c;
  par {
    f(c.ce1);
    g(c.ce2);
  }
}

or

Code: Select all


void f(chanend c);
void g(chanend c);

main(void){
  chan c;
  par {
    f(c.ce[0]);
    g(c.ce[1]);
  }
}

Why is it we can add ports/timers to structures as resources but not chanends.
jhrose
Active Member
Posts: 40
Joined: Mon Dec 14, 2009 11:18 am

Post by jhrose »

Hei,

Probably an XC language expert should step in here, but I think your last code snippet is a pretty good illustration.

XCORE XS1 Architecture Tutorial, section 4, "Some of the resources are managed by the XCore, in that it maintains a set of available resources. A resource can be allocated by using the GETR (get resource) instruction. When the resource is no longer needed, it can be released for subsequent use by a FREER (free resource) instruction." A chan is one such resource.

Fixup for a resource is a bit different to binding other types, for example an int to some general purpose memory location or register. When you declare a chan xcc will ensure its chanends are fixed-up during the build; XCORE XS1 Architecture Tutorial, section 5.3.2 describes how a channel is fixed-up using chanend resources.

ports are a little different again because you fix them up, as in

Code: Select all

in port control = XS1_PORT_1K
.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

In XC you can't create a chanend on it own, they are only created when you declare a variable of type chan. For example the following is illegal.

Code: Select all

void f() {
  chanend c;
}
You also can't assign to a chanend variable since the creation of aliases is illegal in XC (two references to the same resource).

If a chanend was allowed as a member of a structure there would be no way of initialising it. You couldn't create a new channel end when the structure is declared since a channel end in XC can only exist as one half of a channel. You couldn't initialise it by assigning from another channel end variable since this would create an alias.
Folknology wrote:Why aren't channels structures made of two chanends or an array of chanends?
We could have done this. When you declare a chan you implicitly create two channel ends. When you reference a chan variable in a parallel thread the compiler implicitly uses one of the two channel ends. Treating chan as a structure or array would have made this explicit. However it is not clear what this would buy us. You still wouldn't be able to declare a channel end on its own and so still wouldn't be able to put it in a structure.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

I am less interested in manipulating the chanends themselves, although this can be done using C or ASM calls from XC of course. My effort here has been focused on trying to crate type safe design patterns for channel usage for larger bodies of code. You might want to take a look at the conversations about protocols on the XOSIG thread to get some more background on the sort of thing we are experimenting with.

By having a more explicit expression of the channel construct/resources one could include it in other structures with the required type information (protocol) and hence engineer safer pattern which would be acceptable even without a protocol feature in XC (This can be added later obviously). In effect we are using C's and thus XC's existing type system which makes sense from a C software engineering background (XC's current target).

Take a look at the examples and the discussion not the mobile stuff at this point just the protocol work then perhaps let us know your thoughts. I think this will show you why I am asking this question, I wouldn't be surprised if you can help us solve this issue in other ways perhaps given your knowledge here.

Thanks Richard, I look forward to your reply.
Regards
Al
TjBordelon
Active Member
Posts: 39
Joined: Mon Jul 29, 2013 4:41 pm

Post by TjBordelon »

I was able to do this, but it required writing my own channel library in Assembly.

I believe the issue of having to declare channels and pass them through functions and NOT through structs is simply the fact the compiler must figure out who's talking to who in order to compile in the destination resource IDs of each channel pair. Now I'm not the guy who wrote this stuff so I *could* be wrong. But in writing my own library to do this, that's the exact problem you run into.

I was able to solve it by simply having a single known master control channel with an ID known to everyone. At runtime when you create/destroy channels I have an extra step where the channel registers itself to the controller so everyone knows it's ID. The assembly code to do the channel stuff is in the Architecture manual and is not very hard at all. I also lifted the handshaking from the disassembly window.

So in a nutshell, you create a channel that has some ID like 0x200010. He connects to the "controller" channel and says "0x20010 reporting sir! I'm endpoint 2". That gets written to an array. Then some other guy who wants to talk to endpoint 2 goes to the control channel, queries for 2 and gets 0x20010. He sets his destination ID and off you go.

I'm now able to pass channels around in structs and do all the stuff I you are talking about.

XC is a bit too restrictive for my tastes. I'm not sure why it doesn't offer this flexibility. Maybe my fix is too special case but it works for me!
Post Reply