Stack frame allocation and interrupts

A stack frame is a memory block that is reserved on the stack by any function that uses local variables. This allocation is typically done at the very beginning of the user code of the function by simply pushing any value on to the stack. For example, a simple «clrf PREINC0,0» instruction can be used to reserve space for one char variable.

When more data has to be pushed, the code for the stack frame allocation can become very long and slow because one byte is reserved at a time. This is why cpik generates in this case a code that just alter the stack pointer (FSR0) by adding to it the number of bytes needed. Unfortunately, the stack pointer is composed of 2 separate 8 bit registers, so doing the operation needs 4 instructions. Here, the annoying things begin. Lets suppose that an interruption occurs just during this calculation: an ISR is triggered, but is executed with a «half-cooked» stack pointer that do not point to a valid memory place.

In order to avoid such a situation, interruptions must be masked prior the calculation, then restored to their previous state after it. By this way, the change of the stack pointer is made atomic (ie: non interruptible) and no problem can occur.

However, this technique cannot be used in an Interrupt Service Routine for very technical reasons, so ISRs are automatically compiled with a specific stack frame allocation technique.

This restriction also applies to routines called by ISR. Because the compiler cannot anticipate whether such a routine will be called by an ISR or not, this routine cannot be automatically compiled with the proper stack management technique. This situation is very rare, but you can avoid it by disabling the standard stack allocation for a specific routine. See section 10.4.6 for details about the fast_stack pragma.

Alain Gibaud 2015-07-09