Operating System Interest Group for XMOS devices (XOSIG)

Archived group discussions. Please post all group discussions under their relevant XCore group page.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

Hi Julian

I finally got around to reading V0.3 excellent stuff I really like the addition of Protocols, I think this is definitely needed with or without mobile for channels. However I'm not keen on your syntax, not c or xc enough! So how about an alternate approach:

Code: Select all

protocol p
{
  {unsigned char[10],int},
  {int}
}

void tx(chanend c) {
  int i;
  char j;
  c <: {i,j};
}

void rx(chanend c) {
  int i;
  char j;
  c :> {i,j};
}

void ptx(chanend d) {
  int x;
  unsigned char bytes[10];
  d <: {bytes,x};
}

void prx(chanend d) {
  int x;
  unsigned char bytes[10];
  select
    {
    case d :> {x,bytes};
    case d :> x;
    }
}


int main ( void ) {
  chan {int,char} c;
  chan {p} d;
  par {
    tx(c);
    rx(c); 
    ptx(d);
    prx(d);
  }
		    
}
Thoughts?


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

Post by jhrose »

Hei,
However I'm not keen on your syntax, not c or xc enough! So how about an alternate approach
I'm not overkeen on the first draft protocol declaration syntax either. I do like your proposal to use braces for enclosing protocol definitions, with a few thoughts.

You need to be able to write 'chan of type p' and also 'chanend of type p'. One advantage in defining a protocol is to allow re-use over different sources (for example when linking with an object code library), or for communicating with either a remote channel (in a non-local memory system) or a mobile one; for which you need chanend definitions. Another advantage of protocols in chanend definitions is to publish an interface, or a service definition; I explored service definitions using xc and c in the xspi-bus project.

Based on your ideas I would like to suggest a more definitive syntax using braces. In defining a protocol, as before, the case component clearly seperates either elementary types or compound block structure types:

Code: Select all

   protocol p
   {
      case { unsigned char[ 10 ], int }
      case int;
   }
It is more difficult to get the syntax for declaring a 'chan of type p' right. The first draft led to the ':' syntax, which I agree isn't C-like as the type qualifier is written after the name. But I don't think braces work well as a qualifier either - braces in C define a block structure and 'protocol p' is already defined (so expanding 'c {p} d' becomes 'c {{ ... }} d'). How about writing the obvious thing (borrowing 'chan of' from Occam):

Code: Select all

   int main( void )
   {
      chan of { int, char } c;
      chan of p d;

      par
      {
         tx( c );
         rx( c );
         ptx( d );
         prx( d );
      }
   }
This obvious syntax also works for chanend, and shows why defining a protocol is a good thing; see examples below.

For communication events, in sending and receiving, I think you mean to use braces (as in 'c <: {i, j}') to signify something like an 'atomic action'. But the communication of a compound type (as in the first case in p above) will not happen atomically at runtime - rather it will be a sequence of out operations. And there seems no extra clarity achieved by enclosing the elements to be communicated in braces if the protocol case was defined as an elementary type (as in the second case in p above). So I prefer:

Code: Select all

   void tx( chanend of { int, char } c )
   {
      int i;
      char j;

      c <: i, j;
   }

   void rx( chanend of { int, char } c )
   {
      int i;
      char j;

      c :> i, j;
   }

   void ptx( chanend of p d )
   {
      int x;
      unsigned char bytes[ 10 ];

      d <: bytes, x;
   }

   void prx( chanend of p d )
   {
      int x;
      unsigned char bytes[ 10 ];

      select
      {
         case d :> bytes, x;
         case d :> x;
      }
   }
Any thoughts or feedback?
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

I have been thinking about how to make this even more C/XC like and perhaps reuse more what we already have, in particular unions, structures and typedefs see example below :

Code: Select all

# include <platform.h>
# include <stdio.h>

typedef int Signal;

typedef struct {
  unsigned char msg[12];
  Signal sig;
} Message;

typedef chan {
  Message M;
  Signal S;
} Messenger;

void motor_control(chanend c,port control) {
  Message motorStart = {"Starting   ",START};
  Message motorRestart = {"Restarting ",START};
  c <: motorStart;
  while(1) {
  select 
    {
    case control :> when pinseq(0) :> void :
      c <: STOP;
      break;
    case control :> when pinseq(1) :> void :
      c <: motorRestart;
      break;
    }
  }
}

void motor_driver(chanend c,port motor) {
  Message m;
  Signal s;
  while(1) {
  select
    {
    case c :> m;
      printf("Motor %s",m.msg);
      motor <: START;
      break;
    case c :> s
      printf("Motor shutdown");
      motor <: STOP;
    }
  }
}

in port control = XS1_PORT_1K;
out port motor = XSI_PORT_1L;

int main ( void ) {
  Messenger c;
  par {
    motor_controller(c,control);
    motor_driver(c,motor); 
  }
		    
}
Clearly driver and controller could be on separate cores with pins on those cores but I have simplified it to threads on the same core for this example. The points to note here are :

1) I have used typedefs and structures for the typing so it all looks very C like and can lean on that heritage.
2) The new construct here is allowing chan to be defined like a C union, whereby in this case the suggestion is that the channel can house one of a number of different types at any one time.

Just thought I would throw it out there to get some feedback
thoughts?


*Update
I also show type pattern matching in the Motor_driver select, here the correct case is called based on the type use of the channel. In fact if possible it would be even better if we could extend the reach of such pattern matching on select cases to actual values inside the types. I may post an example of this a bit later.
Last edited by Folknology on Tue Jun 22, 2010 5:52 pm, edited 3 times in total.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

Julian,

How would you feel about putting these documents on the newly-created Wiki, or in a repository in source form?

I would find them more user-friendly. If you would rather not, no problem - I totally understand that they represent a substantial body of work.
Image
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

I agree, placing on the wiki would be a really good idea, Julian?
jhrose
Active Member
Posts: 40
Joined: Mon Dec 14, 2009 11:18 am

Post by jhrose »

Hei,
how to make this even more C/XC like and perhaps reuse more what we already have, in particular unions, structures and typedefs
I still prefer the protocol extension. But I tried a few changes to your example, and the code below almost compiles as XC:

Code: Select all

/*
 * main.xc - project typedef_chan
 *
 * 25.june.2010
 *
 * www.xcore.com, forum:Group Discussion, topic: XOSIG, author:Folknology
 *
 * The idea is a variation on the protocol, to 'type' channels using C unions, structures and typedef
 */

# include <platform.h>
# include <stdio.h>

typedef enum
{
    START,
    STOP
} Signal;

typedef struct {
  Signal sig;
  unsigned char msg[12];
} Message;

typedef union {
  Message M;
  Signal S;
  chan c;
} Messenger;


void motor_controller(chanend c, in port control) {
  Message const motorStart = { START, "Starting   " };
  Message const motorRestart = { START, "Restarting " };
  int inp;

  c <: motorStart;
  while(1) {
    control when pinsneq( 0x3 ):> inp;
    {
      if( 0x1 & inp ) {
          c <: STOP;
      }
      else
      if( 0x2 & inp ) {
          c <: motorRestart;
      }
      else
      {
          /* bad input state */
      }
    }
  }
}

void motor_driver(chanend c, out port motor) {
  Messenger m;

  while(1) {
  select
    {
      case c :> m :
      {
        switch( m.S )
        {
          case START :
            printf("Motor %s",m.M.msg);
            motor <: START;
            break;

          case STOP :
            printf("Motor shutdown");
            motor <: STOP;
            break;
        }
      }
      break;
    }
  }
}

in port control = XS1_PORT_1K;
out port motor = XS1_PORT_1L;

int main ( void ) {
  Messenger m;
  par {
    motor_controller( m.c, control);
    motor_driver( m.c, motor);
  }

  return( 0 );
}
The xc compiler whinges about the chan member in Messenger, but the suggestion is to coerce a type through a union.

There remains a problem with having un-typed chanends, in that the compiler only 'knows' the expected type of chanend through the par statement and the channel. Otherwise the compiler doesn't 'know' the type of each chanend within motor_controller and motor_driver. So if you were, for example, to place motor_controller in one source file and motor_driver in another and the par in one or the other, then the compiler cannot type-check the 'protocol' within the other source files. (I think this might be analogous to trying to 'inline' a function over several source files - but maybe I'm wrong.)
How would you feel about putting these documents on the newly-created Wiki
I'm happy for the notes to go on the wiki if it's an appropriate discussion forum. I would need to update the PiXC document and gather the recent postings together in some sort of order.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

Julian,

I was thinking that the forum should remain the medium for discussion, but the PDFs you are currently maintaining - the PiXC and IoI etc - would be on the Wiki.

The Wiki is not as good a place as the forum for interactive discussion - so I propose we continue here.

To have the PDF documents in easily-searchable, up-to-date, editable, indexed, documents with hyperlinks to relevant points of information and discussion points and references would make them much more user-friendly to me.

I more than understand if you would prefer not to.

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

Post by jhrose »

Hei,
...the PiXC and IoI etc - would be on the Wiki
Ok, XOSIG and PiXC sources are now on the wiki, at http://www.xcore.com/wiki/index.php/XMO ... 28XOSIG%29
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

Brilliant work Jullan, an impressive translation onto the wiki.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

I had also been thinking about such issues as dislocation from types in functions. and had been playing about with channel ends, so how about this:

Generic type channel definition, using union to encapsulate the channel's supported types

Code: Select all

typedef struct {
  chanend tx;
  chanend rx;
  union {
    various types
    various types
 } Types;
}
Here is the example rewritten:

Code: Select all

# include <platform.h>
# include <stdio.h>

typedef enum
{
  START,
  STOP
} Signal;

typedef struct {
  unsigned char msg[12];
  Signal sig;
} Message;

typedef struct {
  chanend rx
  chanend tx;
  union {
    Message M;
    Signal S;
  } Types;
} Messenger;

void motor_control(Messenger mc,port control) {
  Message motorStart = {"Starting   ",START};
  Message motorRestart = {"Restarting ",START};
  mc.tx <: motorStart;
  while(1) {
  select 
    {
    case control :> when pinseq(0) :> void :
      mc.tx <: STOP;
      break;
    case control :> when pinseq(1) :> void :
      mc.tx <: motorRestart;
      break;
    }
  }
}

void motor_driver(Messenger mc,port motor) {
  Message m;
  Signal s;
  while(1) {
  select
    {
    case mc.rx :> m;
      printf("Motor %s",m.msg);
      motor <: START;
      break;
    case mc.rx :> s
      printf("Motor shutdown");
      motor <: STOP;
    }
  }
}

in port control = XS1_PORT_1K;
out port motor = XSI_PORT_1L;

int main ( void ) {
  Messenger mc;
  {mc.tx,mc.rx} = new_channel(SYNC);
  par {
    motor_controller(mc,control);
    motor_driver(mc,motor); 
  }
		    
}
Here the entire channel type/structure/definition is passed into the thread an is available for type checking on channel use. In fact it is present at the point of channel usage '"mc.rx :< m" the compiler should be able to work it out from that?

Note this uses a standard XC channel with two endpoints between 2 threads, but teh same idea could also describe other channel patterns,e.g broadcast or one to many :

Code: Select all

typedef struct {
  chanend tx;
  chanend rx[4];
  union {
    Message M;
    Signal S;
  } Types;
} Messenger;

Messenger mc;
  {mc.tx,mc.rx} = new_channel(BROADCAST,3);

Obviously this will not compile as Xcc complains about chanend being of resource type..?
(although strangely ports can be used this way - in structures etc..)

Thoughts?
Locked