Previous Next


The problem:

Since the OS memory has 8 process control blocks (PCB), the easiest way to implement these process blocks in C is to create a structure for each one of the eight blocks. For example:

/* Structure defining process control blocks */
   struct PCB_t {
   int (*entry_pt)(void); /* Pointer to the code for the task */
   unsigned char PCBTimeoutVal; /* Maximum number of ticks before task is ready    */
   unsigned char PCBCurrentTime; /* Number of ticks until task is ready to run    */
   unsigned char PCBMessMask; /* Indicates which tasks we are waiting on */
   unsigned char PCBMessSrc; /* Incidates which tasks have sent messages */
   unsigned char PCBAck; /* Acknowledge bits */
   unsigned char PCBState; /* State register for passing data between successive    runs of the task */
   unsigned char PCBMessages[8]; /* Message mailboxes */
   } PCBs[8];

The simplest way to access the members of each PCB block is to use the dot operator provided in C. For instance, in order to identify the value stored in variable PCBMessSrc, one can just use x = PCB[OSCurrentTask].PCBMessSrc. In fact, each function call in the OS looks like:

void OSSendAck(unsigned    char task) {
   char i;
   char ackMask; 
   char *PCBptr;
   int taskOffset; 
   PCBptr = &PCBs; 
   /* Create the mask with the current task's bit set */
   //for (i=0;i<OSCurrentTask-1;i++)

However, this is precisely where the problem lies. The dot operator actually requires the microcontroller to perform multiplication calculation to figure out the exact location of the structure content. In addition, accessing members of a structures with a dot operator faces a 200 machine cycles penalty. This means that a function that requires repetitive OS calls to PCB structure members is going to range at least couple houndred machine cycles. Such limitation in performance creates a problem for programs that require fast task switching procedure.


Proposed Solution:

One way of getting around such limitation in COMATOS is simply re-write the code so that it does not need multiplication operations to locate the structure content. We know that the PCB blocks are stored in order by process number (e.g. process 1’s block is located in memory after process 0’s and before process 2’s) and each block is 16 bytes long:

Offset C type Field
0x00 Function pointer PCBEntryPtr (High byte)
0x01 PCBEntryPtr (Low byte)
0x02 unsigned char PCBTimeoutVal
0x03 unsigned char PCBCurrentTime
0x04 unsigned char PCBMessMask
0x05 unsigned char PCBMessSrc
0x06 unsigned char PCBAck
0x07 unsigned char
unsigned char[8] Mailboxes


From the above figure, each byte represents a different field (e.g. 0x02 represents PCBTimeoutVal), and there are a total of 16 fields (thus, 16 bytes long). With this mapping scheme in mind, we can rewrite the dot operator line by adding task offset to distinguish different PCBs. Furthermore, we can add an additional field offset within each task to distinguish different byte storage. So first, we need to create a PCB pointer which points to the PCB struc defined in comatos8515.h file. Then we have to define the task offset. Because each PCB has 16 fields (0x00-0xff), we must make sure that our task offset is exactly 16 or 2^4 apart. Also, we know that there are 8 PCBs with number 0 thru 7 (OSCurrentTask can be anywhere from 0 to 7); thus, the Function pointer of each PCB (0x00) is simply 16 * OSCurrentTask. In order to access each field of a given PCB, we have to define each individual offset as follow:

// make byte count offsets for indexing in sched loop
     #define entry_ptOffset 0 
     #define PCBTimeoutValOffset 2
     #define PCBCurrentTimeOffset 3 
     #define PCBMessMaskOffset 4
     #define PCBMessSrcOffset 5 
     #define PCBAckOffset 6 
     #define PCBStateOffset 7
     #define PCBMessagesOffset 8

Now, let’s just add the individual offset to the OSCurrentTask*16 will provide the final result:

*(PCBptr + 16*OSCurrentTask + IndividualOffset);

With this in mind, we can change the original code into the following:

unsigned char OSGetAck(void) {
     unsigned char temp; 
     char *PCBptr;
     int OSCurrentTaskOffset; 
     PCBptr = &PCBs; 
     OSCurrentTaskOffset = ((int)OSCurrentTask) << 4;
     temp = *(PCBptr + OSCurrentTaskOffset + PCBAckOffset);
     *(PCBptr + OSCurrentTaskOffset + PCBAckOffset) = 0;
     return temp; 


Previous Next



Questions? Contact Nick Liu