Some code oddities I encountered
Posted: Thu Mar 13, 2025 10:13 am
I'm working on some A8 (atari 8 bit) related hardware, and in the process of this I'm using an Atarimax multicart, this device if you've never met it is a cartridge that goes in your A8 and gives a menu of games. Unfortunately it's not open source (or at least, if it is, I've not found any source code) so I've had to reverse engineer it.
The loader has a couple of weird things in it that I really don't know why they would be done like that - forgive me because I'm primarily a Z80 person, so I may just be missing some tricks that experienced 6502 developers know about, but even so I can't see much of a reason why some things have been done in a certain way.
For instance, this code snippet:
Why the bne then beq? Surely a jmp would save a byte and do the same thing? I can't see how this branch would never be taken. Note that no code branches or jumps to 0142, the only branch to goto_main: is the one at 013b.
Then there's this code snippet:
Why would you use the 3-byte instruction sta $000c instead of the 2 byte zero page instruction sta $0c (not just at $014b, but all the loads/stores in that snippet are using 3 byte instructions to store in the zero page rather than the 2 byte instruction).
The only reason I can think of is to either to provide padding (unlikely, the whole routine lives in stack space, so you'd think compactness would be important to allow more stack space) and I don't think any of this is timing sensitive. The only plausible reason I can come up with is that when this routine is written out from the first 8k page of the cartridge, the addresses could be modified to be anywhere in address space, but in this instance this still doesn't make sense because DOSINI and BOOT can't be anywhere in memory (because the OS ROM will use these).
The loader has a couple of weird things in it that I really don't know why they would be done like that - forgive me because I'm primarily a Z80 person, so I may just be missing some tricks that experienced 6502 developers know about, but even so I can't see much of a reason why some things have been done in a certain way.
For instance, this code snippet:
Code: Select all
start_program_1:
0135 lda $02e2 ; INITAD
0138 ora $02e3 ; INITAD + 1
013b beq goto_main ; if INITAD is zero don't jump there (MissileCmd set to 0)
013d jsr jump_initad
goto_main:
0140 bne main ; surely these two can only result in the same as
0142 beq main ; a JMP main?
Then there's this code snippet:
Code: Select all
start_program_2:
0144 bit $30 ; status
0146 bvc jump_runad ; if overflow clear, use RUNAD address
0148 lda $02e0 ; RUNAD
014b sta $000c ; DOSINI (why not a ZP instruction?)
014e lda $0231 ; RUNAD+1
0151 sta $000d ; DOSINI+1 (why not ZP?)
0154 lda #$01
0156 sta $0009 ; BOOT? (why not ZP?)
0159 jmp WARMSV ; $e474, OS ROM WARMSV - warm start. Probably for cart images?
jump_runad:
; For Missile Command, this is ultimately set to $8000
015c jmp (RUNAD) ; $02e0 Run address from executable (xex file?)
jump_initad:
015f jmp (INITAD) ; $02e2 Init address from disk
The only reason I can think of is to either to provide padding (unlikely, the whole routine lives in stack space, so you'd think compactness would be important to allow more stack space) and I don't think any of this is timing sensitive. The only plausible reason I can come up with is that when this routine is written out from the first 8k page of the cartridge, the addresses could be modified to be anywhere in address space, but in this instance this still doesn't make sense because DOSINI and BOOT can't be anywhere in memory (because the OS ROM will use these).