• Commodore Free Magazine, Issue 80 - Part 15

    From Stephen Walsh@39:901/280 to All on Sat May 17 18:24:12 2014
    next higher address. But as many things
    computer, it's exactly the opposite, so I prefer to view it this way: the
    top of the Stack is the next position at which the data we "push" will go,
    and each successive push is made to the next lower address within the range $0100-$01FF. The value of the S Register (the Stack Pointer) keeps track
    of this position. Conversely, each pull, which targets data already placed
    on the Stack, will read from the next position in an upward direction (in memory). We will discuss pulls in a moment because they are handled
    slightly differently, but for right now let's picture the push.

    If you have the chance, take a look at a disassembly of the Commodore 64
    ROM, specifically the RESET routine at $FCE2. The very first thing the ROM does (after disabling interrupts) is to set the Stack Pointer to the value
    $FF, which means the position in memory the next pushed byte will be placed
    at is $0100+$FF, or $01FF. Recall that the Stack Pointer is actually an
    offset from $0100. Once we push a byte onto the Stack, the Stack Pointer automatically decrements to $FE, so our next push will be to $0100+$FE, or $01FE. With another push the Stack Pointer decrements once more to $FD,
    which means the next byte pushed will be placed at $0100+$FD, or $01FD.
    This process continues indefinitely, right? Well, not exactly.

    What happens when we start with a Stack Pointer value of $FF and push 256
    bytes on the stack? The Stack Pointer is an 8-bit register with an implied high byte of $01, so it decrements until it reaches $00 and, if once again decremented, it actually wraps back to $FF (keeping in mind an implied high byte of $01). But what about the first push we made to $01FF? The truth
    is that the data we placed with that first push is still in memory at
    $01FF, and we can assume the data is important to us, or we wouldn't have
    put it there in the first place. So what happens if we inadvertently
    "wrap" the Stack, causing the Stack Pointer to once again have a value of
    $FF, meaning we placed data to all 256 locations in the range $0100-$01FF? Generally speaking, when this happens we can sum it up with just one word - crash! You can imagine the scenario. But I'll explain it now because it
    gives us the opportunity to discuss what a Stack pull is.

    THE STACK PULL

    By now we have an idea what happens when we place data on the Stack, and we know the function of the Stack Pointer. Armed with this knowledge it is logical to assume we should match every push with a pull in order to
    maintain Stack equilibrium. This assumption is correct and the tell-tale
    sign you have not achieved equilibrium is the crash. Before getting into retrieving Stack data, it should be mentioned again that any data you do
    place on the Stack is never actually removed. Data in any given location
    may be over-written, but the Stack is, after all, just regular memory with
    a very special hardware pointer keeping track of the relative position of
    our next push. It is the Stack Pointer register value which changes
    through all of this activity, so as a programmer utilizing the Stack you address data in relative terms as opposed to absolute or indirect
    addressing as with normal instructions.

    To recap, after pushing data on the Stack the Stack Pointer is
    automatically decremented. Pulling data from the Stack is handled in the reverse order. The Stack Pointer is first incremented, then the data is retrieved. The data is not physically removed; it is merely "read" from
    the memory at the address pointed to by the Stack Pointer relative to
    $0100. It is this concept which can be difficult for the novice to
    understand. In fact, if you push data to the Stack and do not over-write
    that data with something else it remains right where it is, unaltered, and could, in theory, be retrieved anytime during the life of a program - and
    even after a program has finished its execution.

    THE SUBROUTINE

    We have established that the Stack Pointer is incremented by the CPU before
    a pull occurs, and that for subroutine calls the CPU places the return
    address onto the Stack (so that the CPU can later find its way back). The
    CPU places the address of the last byte of the JSR instruction onto the
    Stack, not the actual return address itself, which would be one byte later
    in the code stream. So, for the instruction JSR $1234 (stored in memory as $20, $34, $12) the address placed onto the Stack is that which contains the
    $12 byte. 65x family processors always store multi-byte data with the low
    byte in the lower address, the high byte in the next higher address, so the address $C002 would be placed onto the Stack in reverse order as $02, $C0.
    In plain language this means the CPU pushes the high byte of the return
    address first, then the low byte. So now the question becomes, "If we come back (return via RTS) to the $12 byte, how do we get to the next
    instruction that follows?"

    The answer lies with the RTS instruction, which first increments the
    multi-byte value it retrieves from the Stack (hopefully it is the return address!). When the return address is pulled (lower addressed byte first)
    one is added to the value before it is sent to the Program Counter (it is pre-incremented). An internal carry flag (not the one we use) is cleared
    or set based on the result of this first addition. Then the value of the internal carry flag (which is either 0 or 1) is added to the next retrieved byte, or high byte of the return address. So that's it. One is added to
    the two-byte return address before it is sent to the Program Counter in the exact same way we add multi-byte numbers with the ADC instruction. Now the Program Counter contains the correct address to continue execution - the address directly after the jump to subroutine instruction.

    STACK INSTRUCTIONS

    As mentioned, special instructions are used to access the Stack, and the
    6502 has a very simple, limited lineup. Pushing data on the Stack is accomplished with the PHA instruction, which reads PusHA Register. This instruction pushes the contents of the A Register, or Accumulator, onto the Stack, and decrements the Stack Pointer. Pulling (retrieving) data
    requires the PLA instruction, or PulLA Register. In this case the Stack Pointer is first incremented; then the retrieved data is placed into the Accumulator. As with all data transfers, certain Status Register flags (in this case Z and N) are cleared or set based on the effect the transfer has
    on the destination register. The same is not true of push instructions as
    no destination register is involved.

    Another type of Stack instruction involves getting or setting the value of
    the Stack Pointer itself. We will see in Part Two just how valuable these
    next two instructions can be when setting up what is known as a Stack
    Frame, which is just a fancy name for a place we can store temporary local data. The first instruction is TSX, or Transfer Stack Pointer to X
    Register, and it does exactly what it sounds like it does. Its
    complementary sibling, TXS, does exactly the opposite. If you managed
    earlier to pull out your copy of the Kernal RESET routine you saw this one
    in action. It Transfers the contents of the X Register to the Stack
    Pointer.

    A final Stack instruction pair is PHP/PLP. These instruction push or pull
    the Status, or S Register, respectively. PHP pushes the values of all
    status flags, while PLP fills the Status Register with the value it pulls
    from the Stack. Both instructions, while not used frequently, are
    invaluable because they allow you to preserve the Status Register flags,
    which is extremely important during interrupt handling.

    IN CONCLUSION

    Today was all about the 6502 Hardware Stack, but there is so much more to
    tell, so we'll pick this up again next time when I will show you how to get tricky with some nifty techniques. Did you know advanced programmers
    sometimes place certain data on the stack to make programs auto-run? Or
    that the Stack is actually a

    --- MBSE BBS v1.0.01 (GNU/Linux-i386)
    * Origin: Dragon's Lair ---:- bbs.vk3heg.net -:--- (39:901/280)