Page 95 - Introduction to Microcontrollers Architecture, Programming, and Interfacing of The Motorola 68HC12
P. 95
72 Chapter 3 Addressing Modes
Figure 3.11. A Stack Buffer for Two Stacks
The hardware stack, pointed to by SP, is useful for holding a subroutine's
arguments and local variables. This will be discussed at the end of this section. However,
because return addresses are saved on and restored from the hardware stack, we sometimes
need a stack that is not the same as that hardware stack. For instance, we may push data
in a subroutine, then return to the calling routine to pull the data. If we use the hardware
stack, data pushed in the subroutine need to be pulled before the subroutine is exited, or
that data will be pulled by the RTS instruction, rather than the subroutine's return
address. A second stack can be implemented using an index register such as Y. If index
register Y is also needed for other purposes in the program, this second stack pointer can
be saved and restored to make it available only when the second stack is being accessed.
Figure 3.11 illustrates that a second auxiliary stack may use the same buffer as the
hardware stack. The hardware stack pointer is initially loaded with the address of (one
past) the high address of the buffer, while the second auxiliary stack pointer (Y) is loaded
with (one below) the low end of the same stack buffer. The second stack pointer is
initialized as: LDY #$B7F. Accumulator A can be pushed using STAA 1, +Y. A
byte can be pulled into accumulator A using LDAA 1, Y- . A 16-bit word can be
pushed and pulled in an obvious way. Observe that autoincrementing and
autodecrementing are reversed compared to pushing and pulling on the hardware stack,
because, as seen in Figure 3.11, their directions are reversed.
The advantage of having the second stack in the same buffer area as the hardware
stack is that when one stack utilizes little of the buffer area, the other stack can use more
of the buffer, and vice versa. You only have to allocate enough buffer storage for the
worst-case sum of the stack sizes, whereas if each stack had a separate buffer, each buffer
would have to be larger than the worst case size of its own stack.
A recursive subroutine is one that calls itself. The procedure to calculate n factorial,
denoted n!, is recursive; for any positive nonzero integer n, if n is one, n! is 1, otherwise
n! is (n-1)! * n. The subroutine in Figure 3.12 calculates n!; upon entry, n is in
accumulator D, and upon exit, n! is in accumulator D.