Druzyek wrote:
Hi! I just started with 6502 assembly and I find myself often trying to translate from C. When I make functions I feel like I should put temporary variables on the stack but this seems a little inconvenient so I tried using some zero-page memory as pseudo-registers. That means, though, that I would have to push copies of all of them on to the stack every time I call one function from another. Is that the standard way to do it? Here is some code I was working on. Is there a better way to do it?
Without taking the time to figure out any of the graphics, I'll comment on some efficiency things.
Forth on the 6502 puts the data stack in ZP (zero page), and indexes them by X, so loading the top stack item is for example LDA 0,X, or from the address pointed to by that address, LDA (0,X) for example. Doing the same thing with the next two-byte cell would be LDA 2,X, from from the address pointed to by that cell, LDA (2,X). Having the separate stack for data solves various problems with trying to mix data and return addresses.
In your listing, if calling a routine will always be preceded by putting numbers on the stack from the same pseudo registers, why not just make the routine itself get them from there, skipping the overhead of moving things to and from the stack.
Next, in your
Code:
;Copy arguments from stack to registers
TSX
INX ;Skip current stack pointer address
INX ;Skip PC copy on stack
INX
INX ;Skip pseudo register copies
INX
INX
INX
INX
LDA STACK,X
just skip all the INX's and do LDA STACK
+8,X. This assumes the stack was initialized at power-up with LDX#$FF, TXS, so you don't accidentally index into page 2.
Code:
LDA R0 ;Get Y argument
BEQ CalcX ;Is it 0 yet?
SEC
SBC #$01 ;Subtract 1 from Y
STA R0
can be replaced with
Code:
LDA R0
BEQ CalcX
DEC R0
and
Code:
LDA R3
INC
STA R3
can be replaced with the single instruction INC R3,
On the 65c02 (ie, CMOS version, which has more instructions and addressing modes),
Code:
LDY #$00
STA (R2),Y ;Write to final address
can be replaced with the single instruction STA (R2). No Y needed.
Quote:
In C I would do something like this:
Code:
#define SCREEN_WIDTH 0x40
SCREEN[Y * SCREEN_WIDTH + X] = color;
After the internal building blocks are working and streamlined, you can use macros to hide the details without losing any control or efficiency. In your example, the macro invocation might look something like
Code:
SCREEN Y_, SCREEN_WIDTH + X_, color
(I put a trailing "_" after X and Y since the assembler probably won't allow a variable with the same name as processor registers.) I have an article on macros, particularly for program structures, at
http://wilsonminesco.com/StructureMacros/index.html. I just finished another work project using them, and they have sure made it easier to keep control of the project and be more productive and get fewer bugs, without losing any of the benefits of assembly, because in almost all cases the macros assemble exactly the same thing I would by hand-- it's just that the source code is much more clear and maintainable. I do need to update the 6502 source-code file though to get the most recent improvements in.