Stack Processing

Basic Stacks

Suppose we want to evaluate


(1 + 5) - (2 + 3)

Saying how to do this out loud (and being very wordy about it!), we'd probably say something like:
  1. ``Add 1 to 5 and stash the result someplace''
  2. ``Add 2 to 3 and stash the result someplace''
  3. ``Take the last two results and subtract them''
One of the basic rules of programming is to avoid special cases - the way we just described evaluating that expression uses a different description of how to add 1 to 5, and 2 to 3 than how to add the last two results. So here's another description of how to do it:
  1. ``Write a 1 on a piece of paper and put it on the table''
  2. ``Write a 5 on a piece of paper and put it on top of the last piece of paper''
  3. ``Add the contents of the top two pieces of paper together, throw them away, write the result of the addition on a piece of paper, and put it where the old pile of papers was.''
  4. ``Write a 2 on a piece of paper and put it on top of the last piece of paper''
  5. ``Write a 3 on a piece of paper and put it on top of the last piece of paper''
  6. ``Add the contents of the top two pieces of paper together, throw them away, write the result of the addition on a piece of paper, and put it where the old pile of papers was.''
  7. ``Subtract the top piece of paper from the second piece from the top, throw the pieces of paper away, write the result on yet another piece, and put the new piece on the table.''

This is an example of using a stack. A stack is a natural data structure to use in applications where you need to retrieve data from the structure in the reverse of the order in which it is inserted (like we just did). The classic example is in expression evaluation like we did above (in fact there have been many, many pocket calculators on the market that use stack-based operations. HP is best known, but far from alone). The stack has two fundamental operations: push and pop. push puts data on the stack, and pop gets it back off (there are a variety of definitions of stack, with extra operations defined as needed. We only need these two). We can do it like this:


push(1)
push(5)
push(pop() + pop())
push(2)
push(3)
push(pop() + pop())
push(-pop()+ pop())

There is actually an alternative notation for arithmetic, developed by Lukasiewicz, called Polish notation. There are two varieties of Polish notation; Polish (also called Polish Prefix) and Reverse Polish (also called Polish Postfix). We'd write the expression up above as

1 5 + 2 3 + -

in reverse Polish.

Stack Support on the HC11

Stack Pointer

The first piece of support the HC11 has for a stack is the stack pointer, SP. This is another 16 bit register, which is defined to always point to the top of the stack (as we'll see in a minute, this is a slight lie - it doesn't quite point to the top of the stack). There are a small number of instructions that directly manipulate SP:

lds Load stack pointer
sts Store stack pointer
des Decrement stack pointer (allocates space on stack)
ins Increment stack pointer (deallocates space on stack)
tsx Transfer sp+1 to x
txs Transfer x-1 to sp
tsy Transfer sp+1 to y
tys Transfer y-1 to sp

Stack operations

Motorola refers to pop as pul (that's actually an old term). So the set of stack operations is:

psha Push A
pshb Push B
pshx Push X
pshy Push Y
pula Pop A
pulb Pop B
pulx Pop X
puly Pop Y

When the HC11 pushes something, it executes the following sequence of steps:

  1. Place the object to be pushed at the memory location currently pointed to by SP.
  2. Move SP past the object you just pushed. This subtrace either one or two from it, depending on the size of the object you pushed.

When it pops something, it does the exact opposite.

We always point the stack pointer at address $ff before doing anything with it; that's because the stack ``grows down.''

The Arithmetic Example Again

So here's what that arithmetic example from the start of the day would look like on an HC11:


* Code to perform the following algebric  equation:
*      (1 + 5) - (2 + 3)

RAM     equ   $0010
STACK   equ   $00ff
EEPROM  equ   $f800
RESET   equ   $fffe


        org   EEPROM
start   lds  #STACK       * set the stack pointer

        ldaa #1         * push(1)
        psha

        ldaa #5         * push(5)
        psha

        pulb            * push(pop() + pop())
        pula
        aba
        psha

        ldaa #2         * push(2)
        psha

        ldaa #3         * push(3)
        psha

        pulb            * push(pop() + pop())
        pula
        aba
        psha

        pulb           * push (-pop() + pop())
        pula
        sba
        psha

eloop   bra  eloop

        org   RESET
	fdb   start
	

(as you simulate this code, you'll be able to watch the data getting put on the stack, but when a pop() happens you won't see the data disappear. Actually taking the time to erase the data from the stack would take extra time, and there's no need to actually do it, but you must never try to access data once it's been popped. It turns out interrupts make use of the stack also, and so the data above the stack pointer can get corrupted at any moment).