Shi
Loading...
Searching...
No Matches
Stacks

Forth has the notation of three different stacks:

  1. Data-stack for passing values
  2. Control-flow-stack for storing jump origins and destinations for conditional branches
  3. Return-stack for do...loop constructs and temporary storage

Shi only uses two physical stacks, the data- and the return-stack. This is possible because all control-flow words (e.g. if, else, then, begin, until, while, ...) are so called "compile only" words which means that they can only be used when creating a new definition. The way the standard phrases this is that interpretation semantics are undefined.

So this works

: lunch? if eat then ;

whereas this doesn't.

lunch? if eat then

The principal difference is that during compilation mode inside the colon-definition the user can't alter the data-stack which makes it perfectly safe to store branching information on it.

Data-stack
The data-stack in Shi is explicit. Two physical registers are reserved for it. There is tos which is short for top-of-stack and dsp which is the data-stack-pointer. Upon pushing to or popping from the stack values are stored or loaded at the address in dsp.

tos .req r6 @ Top of stack
dsp .req r7 @ Data-stack pointer

The stack size itself can be adjusted with the macro SHI_STACK_SIZE.

Control-flow-stack
Usually control-flow words have a 1:1 relation between the word that creates a branch and the word that has to resolve it. forth-standard.org offers a very nice visual representation of control-flow words here. The problem is that there are two exceptions from this 1:1 relation which are endof and leave. Those words can nest an arbitrary number of times and even mix with other control-flow words. To avoid any clashes endof and leave push their control-flow values by using the control-stack-pointer. csp touches the same physical memory as dsp but pushes from stack begin towards the end. Since csp is less commonly used it's only stored as variable.

Return-stack
The return-stack is implicit and shared with the main application. This means that the return-stack is basically whatever the stack-pointer of the ARMv7-M architecture points to. Use of return-stack is generally discouraged as incautious use can not only crash Shi but the entire system.

Note
All stacks are 32bit wide which is the native word size on ARMv7-M.