So I was at work thinking to myself. I said to myself, I says, “Self, what was it that you had heard about that one time… you know, about preserving a hi score on NES in the 700 page of RAM?”
What I’m babbling about, is this. You know how you play some game that has a hi score feature in it, but if you press reset, the hi score is still there? Well, oddly enough I never put much thought into it. But tonight it popped into my head, and I figured out how to do it. I remember someone telling me that the way you can do it is by having a space in RAM set aside that you don’t erase at the reset routine, and fill it with specific bytes. When it gets reset after those bytes are fed into it, you test them against the same bytes in ROM, and if they match, you don’t zero out the hi score. I don’t know if that sounds confusing, but here’s the code I came up with (EDIT: see the comments for a bit smaller code for this by Thomas!):
; in the declarations, of course ram_check = $700 hi_ten = $706 hi_hundreds = $707 hi_thousands = $708 hi_ten_thousands = $709 hi_hun_thousands = $70a ; this is in ROM rom_check: ; The string that gets put in RAM for .byte "SLYDOG" ; the hi score check ; and the actual subroutine that happens at reset slydog_ram_check: ldx #$00 @start_ram_check: lda ram_check, x ; compare the RAM starting at $700 to cmp rom_check, x ; the ROM at rom_check beq @fill_ram_check ; if one of the bytes don't match ldx #$00 ; throw zero back in the X register @write_rom_ram: lda rom_check, x ; load a byte from rom_check sta ram_check, x ; store it in ram_check inx ; increment X and repeat until cpx #$06 ; X is 6 bne @write_rom_ram lda #$00 ; Now throw a zero in all of the sta hi_ten ; hi score bytes. This means it sta hi_hundreds ; was a hard power up, so there is sta hi_thousands ; no hi score saved. If we don't do sta hi_ten_thousands ; this, the NES will print garbage sta hi_hun_thousands ; on-screen as the hi score jmp @done_check ; routine is done @fill_ram_check: inx ; if the original comparison matched cpx #$06 ; then we increment X six times bne @start_ram_check ; to be sure the whole string matches @done_check: rts ; and we're outta here
It seems to work for me fairly well. It can also be used in other pages of RAM. I had heard that the 700 page was for stuff that needed to be saved, but it works in other places I tested. Anyway, I just thought it was cool and that I’d share : )
That’s a cool trick. I’ve never thought about how to do it before, but the code looks good. This only works on a soft reset, right?
Just to tighten the code up a little bit, if you count down from 5 to 0, you can branch with BPL and skip the CPX. You can also eliminate the JMP if you reorder your code blocks:
slydog_ram_check:
ldx #$05
@start_ram_check:
lda ram_check, x ; compare the RAM starting at $700 to
cmp rom_check, x ; the ROM at rom_check
bne @write_rom_ram ; if the bytes don’t match, branch to reset score
dex ; else, they matched
bpl @start_ram_check ; repeat for all 6 bytes
rts ; goodbye
@write_rom_ram:
ldx #$05
@loop:
lda rom_check, x ; load a byte from rom_check
sta ram_check, x ; store it in ram_check
dex ; decrement X and repeat until
bpl @loop ; all bytes copied
lda #$00 ; Now throw a zero in all of the
sta hi_ten ; hi score bytes. This means it
sta hi_hundreds ; was a hard power up, so there is
sta hi_thousands ; no hi score saved. If we don’t do
sta hi_ten_thousands ; this, the NES will print garbage
sta hi_hun_thousands ; on-screen as the hi score
rts ; and we’re outta here
Not a big deal, but it saves a couple of bytes. It’s cool to see another NES post on your blog.
I _always_ forget that I can use more than one RTS haha I don’t know if it feels more confusing to me, or what.
You know, I never thought about the fact that since DEX’ing is decrementing, that it affects the negative flag. That’s pretty cool! Usually if I were to do the backwards way of comparing like that, I would’ve made X = 6, and did a
beqBNE after that to skip the CPX. Very cool. Thanks man! Your comment is noted in the post.Oh, and yes, it only works on a soft reset.
oops, looks like wordpress stripped my leading whitespace. hope it’s still readable!