I'm trying to study mnemonics logic, and tried this simple test with C64 asm, made with VSCode and Kick Asm. Basically i'm trying to print from upper left corner sequence chars from 0 to 9 and then backwards. This is working attempt:
.label SCREEN_RAM = $0400 // Start of C64 screen memory
// --- Variable ---
counter: .byte 0
//backCounter: .byte 39
animationDirection: .byte 1 // Start animation going forward (0=backward, 1=forward)
.var backCounter = $39
BasicUpstart2(main)
main:
lda #0 // Initialize a counter to 0
sta counter
jmp checkloop
checkloop:
ldy animationDirection // Load the current direction flag
cpy #1
beq print_loop_forward
//.break
//lda #10 // Load the desired value into the accumulator
//sta counter // Store the value from the accumulator into 'counter'
ldy #backCounter //#$39
jsr print_loop_backwards
jmp exit2
print_loop_backwards:
//.break
//ldy #backCounter //#$39 no!
ldx counter // Load the counter into Y register (for offsetting)
tya
sta SCREEN_RAM, x // Store the character on the screen with offset
dey
inc counter
ldx counter
cpx #20
bne print_loop_backwards // Compare with 10 (decimal)
rts
print_loop_backwards_not_working:
.break
lda #backCounter //#$39
ldx counter // Load the counter into Y register (for offsetting)
sta SCREEN_RAM, x // Store the character on the screen with offset
dec backCounter
//.break
inc counter
ldx counter
cpx #20
bne print_loop_backwards // Compare with 10 (decimal)
rts
print_loop_forward:
//.break
lda counter // Load the counter value into the accumulator
//cmp #0
//beq exit
clc
adc #$30 // Add $30 to convert to ASCII
ldx counter // Load the counter into Y register (for offsetting)
sta SCREEN_RAM, x // Store the character on the screen with offset
inc counter
ldx counter
cpx #10
bne print_loop_forward // Compare with 10 (decimal)
//.break
lda #0
sta animationDirection
jmp checkloop
exit: // Label for the exit point
rts
exit2: // Label for the exit point
lda #$21 // Load the counter into Y register (for offsetting)
ldx #$99
sta $0500, x
rts
As you can see i've tried another way to do that in this loop:
print_loop_backwards_not_working
Firstly I've tried that attempt, modifying the variable "backCounter" during loop without success, but didn't understand why the variable doesn't reflect changements like the "counter", which i'm able to modify with INC. Tried with DEC as you see, but also with SEC\SBC #$1.
Obviously while tried this method without success, line:
ldy #backCounter //#$39
was commented out.
Hope someone help me clarify this!
6502/6510 opcodes have Immediate, Absolute and Indirect modes. If you want to use a memory address as a counter, you should use Absolute mode which can be represented as below.
LDA $FFFF
or it's Zeropage version;
LDA $FF
You are trying to use the Immediate mode which looks like;
LDA #$FF
So, you have three sensible options here.
1 - Use Absolute mode like below;
LDY backCounter
...
DEC backCounter
Absolute mode reads backCounter from memory address to Y register and when we need to decrease the counter, we directly decrease in memory. When we read the memory address next time, it's already decremented.
2 - Use modifying code. I don't recommend it, i'm sharing this as an alternative option.
label1:
LDY #backCounter
...
DEC label1+1
Here we use Immediate mode and decrease the opcode parameter in memory. Don't forget if you don't reset the parameter, your code doesn't work with backCounter's initial value next time.
3 - Use registers directly. This is the fastest method which you already use in your working example.
LDY #backCounter
...
DEY
As long as you have free registers, you should go with registers. When you are out of registers, using Absolute mode like "LDY backCounter" is your second best option. Self modifying code can be very useful time to time. But it's not the safest option and can cause some side effects. In modern CPUs, self modifying code can be restricted or at least cause caching issues and make your code run much slower. But in good old 8-bit CPUs era, self modifying code was safe to use as long as you know what you are doing.