The Stack

 

The 6502 microprocessor features support for a stack, located at &1xx in memory, and extending for 256 bytes. It also featured instructions which performed instructions more quickly relative to page zero (&0xx).

Both of these are inflexible, and not in keeping with the RISC concept.
The ARM processor provides instructions for manipulating the stack (LDM and STM). The actual location where your stack lays it's hat is entirely up to you and the rules of good programming.

For example:

  MOV     R13, #&8000
  STMFD   R13!, {R0-R12, R14}
would work, but is likely to scribble your registers over something important. So typically you would set R13 to the end of your workspace, and stack backwards from there.

These are conventions used in RISC OS. You can replace R13 with any register except R14 (if you need it) and R15. As R14 and R15 have a defined purpose, the next register down is R13, so that is used as the stack pointer.
Likewise, in RISC OS, the stacks are fully descending (FD, or IA) which means the stack grows downwards in memory, and the updated stack pointer points to the next free location.

You can, quite easily, shirk convention and stack using whatever register you like (R0-R13 and R14 if you don't need it) and also you can set up any kind of stack you like, growing up, growing down, pointer to next free or last used... But be aware that when RISC OS provides you with stack information (if you are writing a module, APCS assembler, BASIC assembler, or being a transient utility, for example) it will pass the address in R13 and expect you to be using a fully descending stack. So while you can use whatever type of stack/location that suits you, it is suggested you follow the OS style. It makes life easier.

If you are not sure what a stack is, exactly, then consider it a temporary dumping area. When you start your program, you will want to put R14 somewhere so you know where to branch to in order to exit. Likewise, every time you BL, you will want to put R14 someplace if you plan to call another BL.
To make this clearer:

  ; ...entry, R14 points to exit location

  BL  one
  BL  two
  MOV PC, R14    ; exit

.one
  ; R14 points to instruction after 'BL one'
  ...do stuff...
  MOV PC, R14    ; return

.two
  ; R14 points to instruction after 'BL two'
  ...do stuff...
  BL  three
  MOV PC, R14    ; return

.three
  ; R14 points to instruction after 'BL three'
  B   four
  ; no return

.four
  ; Not a BL, so R14 unchanged
  MOV PC, R14    ; returns from .three because R14 not changed.
Take a moment to work through that code. It is fairly simple. And fairly obvious is that something needs to be done with R14, otherwise you won't be able to exit. Now, a viable answer is to shift R14 into some other register. So now consider that the "...do stuff..." parts use ALL of the remaining registers.
Now what? Well, what we need is a controlled way to dump R14 into memory until we come to need it.
That's what a stack is.

That code again:

  ; ...entry, R14 points to exit location, we assume R13 is set up

  STMFD R13!, {R14}
  BL    one
  BL    two
  LDMFD R13!, {PC} ; exit

.one
  ; R14 points to instruction after 'BL one'
  STMFD R13!, {R14}
  ...do stuff...
  LDMFD R13!, {PC} ; return

.two
  ; R14 points to instruction after 'BL two'
  STMFD R13!, {R14}
  ...do stuff...
  BL    three
  LDMFD R13!, {PC} ; return

.three
  ; R14 points to instruction after 'BL three'
  B     four
  ; no return

.four
  ; Not a BL, so R14 unchanged
  LDMFD R13!, {PC} ; returns from .three because R14 not changed.
A quick note, you can write:
  STMFD R13!, {R14}
  ...do stuff...
  LDMFD R13!, {R14}
  MOV   PC, R14
but the STM/LDM does NOT keep track of which stored values belong in which registers, so you can store R14, and reload it directly into PC thus disposing of the need to do a MOV afterwards.

The caveat is that the registers are saved in ascending order...

  STMFD R13!, {R7, R0, R2, R1, R9, R3, R14}
will save R0, R1, R2, R3, R7, R9, and R14 (in that order). So code like:
  STMFD R13!, {R0, R1}
  LDMFD R13!, {R1, R0}
to swap two registers will not work.

 

Please refer to this document for details on STM/LDM and how to use a stack.


Return to assembler index
Copyright © 2004 Richard Murray