#define portSAVE_CONTEXT() \
asm volatile ( \
"push r0 \n\t" \ (1)
"in r0, __SREG__ \n\t" \ (2)
"cli \n\t" \ (3)
"push r0 \n\t" \ (4)
"push r1 \n\t" \ (5)
"clr r1 \n\t" \ (6)
"push r2 \n\t" \ (7)
"push r3 \n\t" \
"push r4 \n\t" \
"push r5 \n\t" \
:
:
:
"push r30 \n\t" \
"push r31 \n\t" \
"lds r26, pxCurrentTCB \n\t" \ (8)
"lds r27, pxCurrentTCB + 1 \n\t" \ (9)
"in r0, __SP_L__ \n\t" \ (10)
"st x+, r0 \n\t" \ (11)
"in r0, __SP_H__ \n\t" \ (12)
"st x+, r0 \n\t" \ (13)
);
Referring to the source code above:
- Processor register R0 is saved first as it is used when the status register is saved, and must be saved with its
original value.
- The status register is moved into R0 (2) so it can be saved onto the stack (4).
- Processor interrupts are disabled (3). If portSAVE_CONTEXT() was only called from within an ISR there would be no
need to explicitly disable interrupts as the AVR will have already done so. As the portSAVE_CONTEXT() macro is also
used outside of interrupt service routines (when a task suspends itself) interrupts must be explicitly cleared as early as
possible.
- The code generated by the compiler from the ISR C source code assumes R1 is set to zero. The original value of R1 is
saved (5) before R1 is cleared (6).
- Between (7) and (8) all remaining processor registers are saved in numerical order.
- The stack of the task being suspended now contains a copy of the tasks execution context. The kernel stores
the tasks stack pointer so the context can be retrieved and restored when the task is resumed. The X processor register is
loaded with the address to which the stack pointer is to be saved (8 and 9).
- The stack pointer is saved, first the low byte (10 and 11), then the high nibble (12 and 13).
Next: RTOS Implementation - Restoring The Context