Over on
http://forum.6502.org/viewtopic.php?f=2&t=7304 I asked whether syntax would have more assembly coders think of zero page as registers instead of byte-saving global. That %Rnnn syntax led me to another syntax-based solution to another common 6502 coding question, how best to pass parameters to subroutines.
The 1980s and 1990s CPUs mostly solved this with a addressing mode relative to the stack pointer. FORTH implementation in the 8-bit CPUs often manage a second “data stack”. A zero page pointer is the obvious place to do this on the 6502.
I came up with something inspired by that, but simper. My solution is a new syntax in the assembler. The general form is %%n.mm, and the mapping from that to addresses is inspired by the $Cn00 memory layout on the Apple II.
%%n where n =0-7, with the lowest level subroutines using 7, the next lowest 6, then 5, and the top-level application using 0. (I’ve yet to use 2, 3, or 4 so 8 layers is probably too many).
%%n.mm where mm is a decimal values, 1-15. I use the shortcut %%n to refer to %%n.0
For example, my PrintString low-level subroutine expects the pointer to the string in %%7, as a two-byte address. CompareString has two parameters, %%7 and %%7.2, both two byte addresses.
In my Apple II4 project, I map this syntax to start at $D000 (after the I/O space and after the screen buffers), but the assembler can map in anywhere in memory.
The result is basically a manual data stack. Yes, it seems to waste space, but on a typical stack you waste the yet-used space where I’m wasting the in-between space. The benefit is that I know exactly what address the parameters for every subroutine should be, making debugging a lot simpler.
Plus there is no push or pull and thus no way to get into a state where the return address or current parameters are not where they are expected to be. The stack pointer just deals with JSR/RTS and the parameters only get set, never unset.
Plus, every so often my code makes a sequence of low-level subroutine calls and as the first parameter to all of those is always %%7, in those cases I can just set %%7 once.
The result of all this feels a lot like a manual version of what a C compiler does, minus the pushing and pulling. I’m manually looking up the list of parameters and %%addresses of the subroutine I’m calling, mustering the parameters in place, then JSR. Then inside any subroutine it’s just LDA %%n.mm to grab the value.
And with the manually set “levels” there is never a conflict.
Anyone have a similar solution? Or something better?