I'm starting out with 6502 Assembly right now and have a problem wrapping my head around loops that need to deal with numbers bigger than 8 bit.
Specifically, I want to loop through some memory locations. In pseudo-c-code, I want to do this:
// Address is a pointer to memory
int* address = 0x44AD;
for(x = 0; x < 21; x++){
// Move pointer forward 40 bytes
address += 0x28;
// Set memory location to 0x01
&address = 0x01;
}
So starting at address $44AD
I want to write $01
into ram, then jump forward $28
, write $01
into that, then jump forward $28
again until I've done that 20 times (last address to write is $47A5
).
My current approach is loop unrolling which is tedious to write (even though I guess an Assembler can make that simpler):
ldy #$01
// Start from $44AD for the first row,
// then increase by $28 (40 dec) for the next 20
sty $44AD
sty $44D5
sty $44FD
[...snipped..]
sty $477D
sty $47A5
I know about absolute addressing (using the Accumulator instead of the Y register - sta $44AD, x
), but that only gives me a number between 0 and 255. What I really think I want is something like this:
lda #$01
ldx #$14 // 20 Dec
loop: sta $44AD, x * $28
dex
bne loop
Basically, start at the highest address, then loop down. Problem is that $14 * $28 = $320 or 800 dec, which is more than I can actually store in the 8-Bit X register.
Is there an elegant way to do this?
The 6502 is an 8-bit processor, so you aren't going to be able to calculate 16-bit addresses entirely in registers. You will need to indirect through page zero.
// set $00,$01 to $44AD + 20 * $28 = $47CD
LDA #$CD
STA $00
LDA #$47
STA $01
LDX #20 // Loop 20 times
LDY #0
loop: LDA #$01 // the value to store
STA ($00),Y // store A to the address held in $00,$01
// subtract $28 from $00,$01 (16-bit subtraction)
SEC
LDA $00
SBC #$28
STA $00
LDA $01
SBC #0
STA $01
// do it 19 more times
DEX
BNE loop
Alternatively, you could use self-modifying code. This is a dubious technique in general, but common on embedded processors like the 6502 because they are so limited.
// set the instruction at "patch" to "STA $47CD"
LDA #$CD
STA patch+1
LDA #$47
STA patch+2
LDX #20 // Loop 20 times
loop: LDA #$01 // the value to store
patch:STA $FFFF
// subtract $28 from the address in "patch"
SEC
LDA patch+1
SBC #$28
STA patch+1
LDA patch+2
SBC #0
STA patch+2
// do it 19 more times
DEX
BNE loop