Stack Frames

General discussions about working with the Astrobe IDE and programming ARM Cortex-M0, M3, M4 and M7 microcontrollers.
Post Reply
gray
Posts: 109
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Stack Frames

Post by gray » Wed Mar 13, 2019 10:51 am

I try to figure out the structure of the stack frame for exception handlers (STM32F207 target, or M3 in general, I guess). The programming manual explains the "stacking", but is not specific regarding the order the listed items are put on the stack: R0-R3, return address, PSR, LR. Based on the code in Traps.mod, the return address is accessed at SP +36, with the local variable, hence it would be +32 without a local integer (hope it's OK to quote that much):

Code: Select all

PROCEDURE NMITrap;
VAR 
  trapAddr: INTEGER;
BEGIN
  SYSTEM.GET(SYSTEM.SP + 36, trapAddr);
  ...
However, "stacking" puts only 7 x 4 bytes on the stack by my count. What do I miss? Is it an alignment issue? The manual mentions that the SP is aligned to a double-word address after the stacking if so configured.

Is it correct that the return address is at the top of the stack frame (which would be consistent with "normal" procedure calls, where the LR is saved there, if I am not mistaken).

cfbsoftware
Site Admin
Posts: 493
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Stack Frames

Post by cfbsoftware » Wed Mar 13, 2019 11:16 am

There are three additional instructions inserted on entry to a procedure to save the frame pointer and the link register and adjust the stack pointer for the local variable:

push {FP, LR}
add FP, SP
sub SP, SP, 4

This is because (as you mentioned previously) although the procedure is being used as an exception handler it can be coded as a standard procedure as it never has to return. Otherwise it would be trickier as it might need to push a variable number of registers onto the stack as well as R0-R3 depending on what other actions it performs.

gray
Posts: 109
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Re: Stack Frames

Post by gray » Wed Mar 13, 2019 11:49 am

But I could write this, right?

Code: Select all

PROCEDURE NMITrap[0];
VAR 
  trapAddr: INTEGER;
BEGIN
  SYSTEM.GET(SYSTEM.SP + 68, trapAddr);
  ...
Note the [0] and changed SP-offset, as on entry to a normal interrupt handler you also save the other eight registers R4 to R11, I think. I want to use this with SVCTrap to allow execution after the handling of certain ASSERT codes to return to the code after the ASSERT. It seems to work in my tests, but then again, I might just be lucky.

cfbsoftware
Site Admin
Posts: 493
Joined: Fri Dec 31, 2010 12:30 pm
Contact:

Re: Stack Frames

Post by cfbsoftware » Thu Mar 14, 2019 2:58 am

I haven't tested it myself but it looks OK. The only thing you have to watch out for (what I was alluding to when I said it might be trickier) is if you have marked (*) your interrupt handler as a 'leaf' procedure i.e.

Code: Select all

PROCEDURE* NMITrap[0];
This would normally be a good idea if the handler is not calling other procedures because it makes the handler as efficient as possible. As part of this the compiler only saves the registers that are actually used in an interrupt handler when it is a leaf procedure. Consequently, whenever you changed that handler, you would need to look at the disassembler output and possibly modify the SYSTEM.GET statement as the number of registers used might also have changed.

Note that the RETURN from the interrupt handler automatically uses the correct address to return to. In normal circumstances you don't need to retrieve the trap address. The only reason we bother to identify the trap address in our implementation of the SVCTrap handler is to enable us to display its value when there is a runtime error.

Post Reply