haker
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Local Variables

Local storage refers to variables local to the function currently executing. This is in contrast to global variables.

Using stack frames and allocating variables on the stack is a common practice. WOPR is little different in that stack frames are supported directly by the CPU, while commonly stack frames are implemented in higher level languages.

This choice was made to make WOPR programming a little easier and to make WOPR code more compact, especially since it has only 64K of memory.

Stack Frame Layout

Until now, return stack contained only return address, address of the instruction where to continue execution when the call returns.

Now, we introduce proper stack frame. Each call creates a stack frame, and each return removes it.

Return Stack Size
return address word
stack frame size word
variable

In the simplest case, if the function does not have any local variables, the stack frame will contain only return address and stack frame size.

Return Stack Size Offset Value
return address word -2 ?
stack frame size word 0 0

If the function has a single variable which is a single byte, stack frame would look like this:

Return Stack Size Offset Value
return address word -2 ?
stack frame size word 0 2
variable 1 byte 2 ?

In a more complex example with multiple variables, two word variables a and one byte sized one.

Return Stack Size Offset Value
return address word -2 ?
stack frame size word 0 5
variable 1 word 2 ?
variable 2 word 4 ?
variable 3 byte 5 ?

Offset

Stack frame is laid out so that the stack frame size is pointed to by the RS register. So we say that stack frame size is at offset 0.

First variable is at offset 2, and location of each subsequent one is calculated by adding the size of each variable.

alloc

Function must allocate the space for any local variables it will use. This is done using alloc instruction.

The most common case is to allocate space for all variables using a single instruction. So a function in our previous example, which allocates five bytes for two word variables and one byte variable, would look like this:

my_func:
        push 5
        alloc
        ; ... do your thing here
        ret ; this will return and remove stack frame including all variables

alloc can be executed multiple times, and each one would increase the size of the stack frame and thus allocating additional memory for your variables.

my_func:
        push 5
        alloc
        push 10
        alloc
        ret ; this will return and remove stack frame including all variables

Above example would create a stack frame with 15 bytes allocated to local variables, like so:

Return Stack Size Offset Value
return address word -2 ?
stack frame size word 0 15
variables 15 bytes 2-15 ?

This pattern is useful when the size of some variable, usually a buffer, is not known ahead of time and has to be calculated.

free

free does the opposite of alloc and would reduce the size of the stack frame.

my_func:
        push 8
        alloc
        push 4
        free
        ; at this point, we have only 4 bytes allocated
        ret ; this will return and remove stack frame including all variables

Like mentioned earlier, the stack frame is automatically released when a function executes ret or iret. This will automatically free the space for local variables. So in most cases free is not required. It is available nevertheless to allow implementing complex functions.

Accessing local variables with lpush

The easiest way to access local variables is using the lpush instruction. It is very similar to push except the value pushed is first added to RS, so the value pushed is RS+P0. This effectively pushes the absolute address of a variable so that it can be accessed using load or sto instructions.

my_func:
        push 4
        alloc     ; allocate 2 word variables

        ; initialize first variable (offset 2) to zero
        lpush 2
        push 0
        sto

        ; initialize second variable (offset 4) to zero
        lpush 4
        push 0
        sto

        ret ; this will return and remove stack frame including all variables