I have just completed a port of the Atomthreads RTOS to the STM8 microcontroller. Anyone interested in running an RTOS on the STM8 can download the source code from http://atomthreads.com.
This has to be one of the easiest architectures I’ve ever ported an RTOS to. There are only six CPU registers and only three of these are general purpose registers for compiler use. The other three are used for the program counter, stack pointer and code condition flags. This fact alone would significantly reduce the lines of code required within the assembler context-switch routine, but it turns out that on this architecture it is not actually necessary to explicitly save and restore any registers on the stack within the context-switch routine, resulting in the shortest context-switch routine I have ever written.
In the Atomthreads RTOS, threads are switched by one of two events:
- Preemptive: An interrupt handler action results in a reschedule decision
- Cooperative: A thread voluntarily schedules itself out
Whenever interrupt handlers are called on the STM8, the CPU automatically saves five of the six CPU registers on the current thread’s stack (omitting the stack pointer, SP). This means that for preemptive context-switches almost all of the CPU registers are already saved by the time the context-switch routine is called. All that the context-switch routine needs to do is store the current thread’s stack pointer somewhere before scheduling in the new thread.
In the case of a cooperative context switch, the thread has deliberately called out to the scheduler. The compiler will therefore have stacked any registers which might be clobbered by the called routine. In the case of the STM8, all of the general purpose registers may be clobbered by the called function, so it turns out that for cooperative switches, it is not necessary to save any further registers either. The same scheme applies as to preemptive switches: only the stack pointer for the current thread needs to be stored somewhere before scheduling in the new thread.
A context-switch on STM8, therefore, has to do this:
- Store current thread’s stack pointer somewhere
- Set the stack pointer to that of the new thread which is being scheduled in
This can be achieved in 5 instructions on the STM8. Note that we are not actually avoiding the overhead of saving the registers; this is still being done by the ISR entry (for preemptive switches) or the compiler (for cooperative switches), but it does mean that we do not need to write any register save/restore code in the architecture’s port. The point is that the structure of the Atomthreads RTOS allows for a very simple context-switch routine, and hence a shorter development effort when porting to new CPU architectures. The RTOS takes advantage of the fact that several registers are typically already saved before the context-switch routine is called, either by the compiler for cooperative switch function calls, or during the interrupt entry for preemptive switches. On the AVR architecture, for example, this approximately halves the lines of code in the context-switch routine, but on the STM8 it reduces the context-switch routine to almost nothing.
This is the second architecture that Atomthreads has been ported to, and it has proven the portability of the codebase and given an indication of how easy it is port to a new CPU architecture and toolchain. The STM8 port code took less than a day to write and was easy to prove because of Atomthreads’ built-in automated test suite, all of which passed first time. No kernel changes were required to run Atomthreads on this new CPU. Other architectures will generally have more complicated register save/restore requirements on a context-switch, but once you understand the architecture and the compiler’s calling conventions it should be clear which registers need to be context-switched.
Atomthreads now runs on both the ATmega/AVR and the STM8 architectures, using both GCC and the Cosmic compiler respectively. These are both 8-bit CPUs, however, so the next port I intend to do will likely be a 32-bit architecture to prove portability across these realms.
Note that anyone intending to port a different RTOS to the STM8 should be aware that the programming manual contains some misleading information, claiming: “Fast interrupt handling through alternate register files (up to 4 contexts) with standard stack compatible mode (for real time OS kernels)”. It turns out that, while this was implemented in the core, it has never been included in any released products. The current STM8 range use the standard stack compatible mode, whereby registers are saved on the current thread’s stack whenever an interrupt occurs.