Preserving a Hi-Score on NES

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 : )

4 Responses to Preserving a Hi-Score on NES

  1. Thomas Hjelm says:

    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.

  2. Thomas Hjelm says:

    oops, looks like wordpress stripped my leading whitespace. hope it’s still readable!


Bulk Email Sender