!pr1
Using the 65816 Stack Relative Mode........Bob Sander-Cederlof

The 65802 and 65816 have two new address modes that allow you to reach into the stack.  The "offset,S" mode lets you access position relative to the stack pointer, and the "(offset,S),Y" mode lets you access data indirectly through an address that is on the stack.  The new address modes are available even when the 65802/16 is in the "emulation" mode.

The hardware adds the value of the offset to the current stack pointer to form an effective address.  The stack pointer is always pointing at one address below the end of the stack.  Thus, an address of "1,S" points to the first item on the stack.

Having these new modes leads to interesting programming possibilities.  When you design a subroutine, you have to decide how you are going to pass parameters into and out of the subroutine.  Usually we try to use the A, X, and Y registers first.  Another method puts the data of the address of the data after the JSR that calls the subroutine.  ProDOS MLI calls use this method:

       JSR $BF00
       .DA #$C1,PARMS

In another method you push data or data addresses on the stack, and then call the subroutine.  This is the preferred method in some computers, but not the 6502.  The new modes make this mode work nicely in the 65802/16, though.

I coded up two examples to show you might use the new modes.  They both are message printing subroutines.  The calling method requires telling the subroutine where to find a variable length message.  In the first example (lines 1070-1330), I chose to push the address of the message text on the stack before calling the message printing subroutine.  In the second example (lines 1340-1640), I used the method of storing the message text immediately after the JSR instruction.

Lines 1070-1110 print out two messages, using the first technique.  I use the PEA (Push Effective Address) instruction to put the address of the first byte of the message text on the stack.  This instruction pushes first the high byte, then the low byte, of the value of the operand.  (I think I would prefer to have called it "PSH #value", because that is the effect.  Then the PEI opcode, which pushes two bytes from the direct page, could be "PSH zp".  But, nobody asked me.)  

Anyway, let's look at the PRINT.IT subroutine.  When the subroutine starts looking at the stack, it looks like this:

       |  msg addr lo  | 4,S
       | ------------- |
       |  msg addr hi  | 3,S
       | ------------- |
       |  ret addr lo  | 2,S
       | ------------- |
       |  ret addr hi  | 1,S
       | ------------- |
       |               |<---Stack Pointer

The LDA (3,S),Y instruction at line 1240 takes the address at 3,S and 4,S (which is the address of the first byte of the message) and adds the Y-register to it; then the LDA opcode picks up the message byte.  After printing all the message and finding the terminating 00 byte, lines 1290-1320 move the return address up two slots higher in the stack (over the top of the message address).  At the same time, the original copy of the return address is removed from the stack.  Then a simple RTS takes us back to the caller, with a clean stack.

The second example uses the "message buried in the code" method.  when PRINT.MSG looks at the stack, only the return address is there.  The return address points to the third byte of the JSR instruction, one byte before the message text.  Therefore the message printing loop in lines 1500-1550 starts with Y=1.  Lines 1560-1620 add the message length to the return address, so that an RTS opcode will return to the caller just past the message.

<<<code here>>>

It might be instructive to look at how these two examples could be code in a plain 6502 environment.  First, we must replace the PEA opcodes in lines 1070 and 1090 with the following:

       LDA #MESSAGE
       PHA
       LDA /MESSAGE
       PHA

Then PRINT.IT would require using temporary memory somewhere or writing self-modifying code.  With a pointer in page zero, it could work like this:

<<<6502 version of print.it>>>

PRINT.MSG also can be written in pure 6502 code with either self-modifying code or a pointer in page zero.  Here is the self-modifying version:

<<<6502 version of print.msg>>>
