- Main Page
- Modules
- Data Structures
- Files

# pico]OS Porting Information
[Introduction]

## Functions
POSFROMEXT UVAR_t | p_pos_findbit (const UVAR_t bitfield)
POSFROMEXT UVAR_t | p_pos_findbit (const UVAR_t bitfield, UVAR_t rrOffset)
POSFROMEXT void | p_pos_initArch (void)
POSFROMEXT void | p_pos_initTask (POSTASK_t task, void *stackstart, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT VAR_t | p_pos_initTask (POSTASK_t task, UINT_t stacksize, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT void | p_pos_freeStack (POSTASK_t task)
POSFROMEXT VAR_t | p_pos_initTask (POSTASK_t task, POSTASKFUNC_t funcptr, void *funcarg)
POSFROMEXT void | p_pos_startFirstContext (void)
POSFROMEXT void | p_pos_softContextSwitch (void)
POSFROMEXT void | p_pos_intContextSwitch (void)
POSEXTERN void | c_pos_intEnter (void)
POSEXTERN void | c_pos_intExit (void)
POSEXTERN void | c_pos_timerInterrupt (void)

## Detailed Description

### General Information

#### Choose the best type of stack management

The operating system can be easily ported to other architectures, it can be ported to very small 8 bit architectures with low memory and to 32 bit architectures with lots of memory. To keep the porting as simple as possible, there are only a couple of functions that must be adapted to the architecute. Before you start porting the operating system to your architecture, you must choose a stack management type. You have the choice between:

POSCFG_TASKSTACKTYPE = 0
The stack memory is provided by the user. This is the best choice for very small architectures with low memory.

POSCFG_TASKSTACKTYPE = 1
The stack memory is dynamically allocated by the architecture dependent code of the operating system. The size of the stack frame is variable and can be choosen by the user who creates the task. This is the best choice for big architectures with lots of memory.

POSCFG_TASKSTACKTYPE = 2
The stack memory is dynamically allocated by the architecture dependent code of the operating system. The size of the stack frame is fixed and can not be changed by the user. This may be an alternative to type 0, it is a little bit more user friendly.

Here is a list of the functions that are architecture specific and must be ported:
p_pos_initTask, p_pos_startFirstContext, p_pos_softContextSwitch, p_pos_intContextSwitch.

If you choose POSCFG_TASKSTACKTYPE = 2 or 3, you must also provide the function p_pos_freeStack.

#### Get more speed with optimized "findbit" function

If your application is critical in performance, you may also provide an assembler version of the function "findbit". There are two different function prototypes possible. The simple prototype for the standard scheduling scheme (POSCFG_ROUNDROBIN = 0) is

UVAR_t p_pos_findbit(const UVAR_t bitfield);

The prototype for a findbit function that supports round robin scheduling (POSCFG_ROUNDROBIN = 1) is

UVAR_t p_pos_findbit(const UVAR_t bitfield, UVAR_t rrOffset);

The function gets a bitfield as input, and returns the number of the right most set bit (that is the number of the first lsb that is set). If round robin is enabled, the function takes an offset as second parameter. The offset is the position where the function starts to search the first set bit. The function scans the bitfield always from right to left, starting with the bit denoted by the offset. The bitfield is seen as circle, when the rightmost bit is not set the function must continue scanning the leftmost bit (wrap around), so all bits of the field are scanned.
It is possible to implement the findbit mechanism as look up table. For this purpose you can define the macro FINDBIT. Please see the header file picoos.h (search for the word POSCFG_FBIT_USE_LUTABLE) and the source file fbit_gen.c for details.

### Assembler Functions

Unfortunately, not the whole operating system can be written in C. The platform port must be written in assembly language. I tried to keep the assembly part of the RTOS as small as possible. But there are three assembly functions left, that are needed for doing the context switching:

- p_pos_startFirstContext
- p_pos_softContextSwitch
- p_pos_intContextSwitch

The operating system requires also a timer interrupt that is used to cut the task execution time into slices. Hardware interrupts must comply with some conventions to be compatible to pico]OS. So the fourth thing you need to write in assember is a framework for hardware interrupts.

The diagram shows the assembler functions in logical structure. At the left side I have drawn a normal interrupt service routine for reference.

The context switching (multitasking) is done by simply swaping the stack frame when an interrupt service routine (eg. the timer interrupt) is left. But it must also be possible for a task to give of processing time without the need of an interrupt. This is done by the function p_pos_softContextSwitch at the right side in the diagram. Since this function is not called by a processor interrupt, it must build up an ISR compatible stack frame by itself. Note that the second part of this function is equal to the function p_pos_intContextSwitch, so the function must be terminated by an return-from-interrupt instruction, even if the function was called from a C-routine.

For completeness, the next diagram shows at its left side how the function p_pos_startFirstContext works. Again, this function looks like the lower part of the funtion p_pos_intContextSwitch in the diagram above. In the middle you can see how the timer interrupt routine must look like.

There is a special interrupt handling needed when interrupts are interruptable on your system. To prevent a deadlock situation (that is, an ISR would be called again and again until the stack flows over), a counting flag variable is exported by pico]OS: posInInterrupt_g. This variable contains the value zero if no interrupt is running yet. And only if no other interrupt is running, the ISR must save the stack pointer to the task environment structure where posCurrentTask_g points to. This behaviour is shown at the right side in the diagram above.

Note that interrupt service routines need some stack space to be able to do their work - in the discussed configuration every ISR would take some stack memory from the stack frame of the currently active task. But this may be a problem at platforms that are low on memory - it would be to expensive to increase every tasks stack frame by the count of bytes an ISR would need. In this case, you can set up a special stackframe that is only used by interrupt service routines. The diagram below shows the small changes to the ISRs discussed above. But attention - this method is only applicable on platforms where interrupts can not interrupt each other.

## Function Documentation

POSEXTERN void c_pos_intEnter | ( | void |  | ) |

| Interrupt control function. This function must be called from an interrupt service routine to show the operating system that an ISR is currently running. This function must be called first before other operating system functions can be called from within the ISR. See also: c_pos_intExit, c_pos_timerInterrupt

POSEXTERN void c_pos_intExit | ( | void |  | ) |

| Interrupt control function. This function must be called from an interrupt service routine to show the operating system that the ISR is going to complete its work and no operating system functions will be called any more from within the ISR. See also: c_pos_intEnter, c_pos_timerInterrupt

POSEXTERN void c_pos_timerInterrupt | ( | void |  | ) |

| Timer interrupt control function. This function must be called periodically from within a timer interrupt service routine. The whole system timing is derived from this timer interrupt. A timer ISR could look like this:
     PUSH ALL; // push all registers to stack@n

     if (posInInterrupt_g == 0)
       saveStackptrToCurrentTaskEnv();

     c_pos_intEnter();
     c_pos_timerInterrupt();
     c_pos_intExit();

     PULL ALL; // pull all registers from stack@n
     RETI;     // return from interrupt@n
Note: Any other ISR looks like this, only the function c_pos_timerInterrupt is replaced by an user function. Dependent on the platform port, it can be necessary to evaluate the variable posRunning_g to ensure that the timer interrupt is not triggered when the OS is not yet running. To avoid this race condintions, it is better to initialize the timer interrupt in the function p_pos_startFirstContext. See also: c_pos_intEnter, c_pos_intExit

POSFROMEXT UVAR_t p_pos_findbit | ( | const UVAR_t | bitfield,
|  | UVAR_t | rrOffset
| ) |

  | Bit finding function. This function is called by the operating system to find the first set bit in a bitfield. See the file fbit_gen.c for an example. Parameters:
  | bitfield | This is the bitfield that shall be scanned.
  | rrOffset | Offset into the bitfield. Scanning begins here.
Returns: the number of the first set bit (scanning begins with the lsb). Note: POSCFG_ROUNDROBIN must be defined to 1 to have this format of the function compiled in.

POSFROMEXT UVAR_t p_pos_findbit | ( | const UVAR_t | bitfield | ) |

  | Bit finding function. This function is called by the operating system to find the first set bit in a bitfield. See the file fbit_gen.c for an example. Parameters:
  | bitfield | This is the bitfield that shall be scanned.
Returns: the number of the first set bit (scanning begins with the lsb). Note: POSCFG_ROUNDROBIN must be defined to 0 to have this format of the function compiled in.

POSFROMEXT void p_pos_freeStack | ( | POSTASK_t | task | ) |

  | Stack free function. This function is called by the operating system to free a stack frame that was set up by the function p_pos_initTask. See the available port source files for an example on how to write this function. Parameters:
  | task | pointer to the task environment structure.
Note: POSCFG_TASKSTACKTYPE must be defined to 1 or 2 to have this format of the function compiled in. This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_initTask

POSFROMEXT void p_pos_initArch | ( | void |  | ) |

| Architecture port initialization. This function is called from the posInit function to initialize the architecture specific part of the operating system. Note: POSCFG_CALLINITARCH must be defined to 1 when posInit shall call this function. This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. A timer interrupt should be initialized in the funcion p_pos_startFirstContext.

POSFROMEXT VAR_t p_pos_initTask | ( | POSTASK_t | task,
|  | POSTASKFUNC_t | funcptr,
|  | void * | funcarg
| ) |

  | Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. This function is responsible to allocate the stack memory and to store the pointer of the stack frame into the task environment. See the available port source files for an example on how to write this function. Parameters:
  | task | pointer to the task environment structure.
  | funcptr | pointer to the first function that shall be executed by the new task.
  | funcarg | argument that should be passed to the first function.
Returns: zero on success. A negative value should be returned to denote an error (e.g. out of stack memory). Note: POSCFG_TASKSTACKTYPE must be defined to 2 to have this format of the function compiled in. This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_freeStack

POSFROMEXT VAR_t p_pos_initTask | ( | POSTASK_t | task,
|  | UINT_t | stacksize,
|  | POSTASKFUNC_t | funcptr,
|  | void * | funcarg
| ) |

  | Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. See the available port source files for an example on how to write this function. Parameters:
  | task | pointer to the task environment structure.
  | stacksize | size of the stack memory for the new task. The stack memory may be allocated dynamically from within this function.
  | funcptr | pointer to the first function that shall be executed by the new task.
  | funcarg | argument that should be passed to the first function.
Returns: zero on success. A negative value should be returned to denote an error (e.g. out of stack memory). Note: POSCFG_TASKSTACKTYPE must be defined to 1 to have this format of the function compiled in. This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_freeStack

POSFROMEXT void p_pos_initTask | ( | POSTASK_t | task,
|  | void * | stackstart,
|  | POSTASKFUNC_t | funcptr,
|  | void * | funcarg
| ) |

  | Task initialization function. This function is called by the operating system to initialize the stack frame of a new task. See the available port source files for an example on how to write this function. Parameters:
  | task | pointer to the task environment structure.
  | stackstart | pointer to the start of the stack memory.
  | funcptr | pointer to the first function that shall be executed by the new task.
  | funcarg | argument that should be passed to the first function.
Note: POSCFG_TASKSTACKTYPE must be defined to 0 to have this format of the function compiled in. This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called.

POSFROMEXT void p_pos_intContextSwitch | ( | void |  | ) |

| Context switch function. This function is called by the operating system to initiate a context switch from interrupt level. This function has then to switch the context variable and restore the new context from stack memory. See the available port source files for an example on how to write this function. Note: This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_softContextSwitch, p_pos_startFirstContext

POSFROMEXT void p_pos_softContextSwitch | ( | void |  | ) |

| Context switch function. This function is called by the operating system to initiate a software context switch. This function has then to save all volatile processor registers to stack memory, switch the context variable and restore the new context from stack memory. See the available port source files for an example on how to write this function. Note: This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_intContextSwitch, p_pos_startFirstContext

POSFROMEXT void p_pos_startFirstContext | ( | void |  | ) |

| Context switch function. This function is called by the operating system to start the multitasking. The function has to restore the first context from stack memory. See the available port source files for an example on how to write this function. Note: This function is not part of the pico]OS. It must be provided by the user, since it is architecture specific. The processor interrupts are disabled when this function is called. See also: p_pos_softContextSwitch, p_pos_intContextSwitch