Init code

From NESdev Wiki
Revision as of 04:22, 13 June 2009 by Ndwiki (talk | contribs) (1 revision: Rest of pages not related to reference)
Jump to navigationJump to search

When the NES is powered on or reset, the program should do the following within a fixed bank:

  • Set IRQ ignore bit (not strictly necessary as the 6502 sets this flag on all interrupts, including RESET, but it allows program code to simulate a reset by JMP ($FFFC))
  • Disable decimal mode (not strictly necessary as the 2A03 has no decimal mode, but it maintains compatibility with generic 6502 debuggers)
  • Initialize stack pointer
  • If using a mapper that generates IRQs, disable APU timer IRQs
  • Disable DMC IRQs [1]
  • Disable PPU NMIs and rendering
  • Initialize the mapper (if any)

The init code after this point may be placed in a separate bank using a bankswitch followed by a JMP:

  • Set all RAM that your program uses to a known state. This often involves clearing internal RAM (@ $0000-$07FF) (and PRG RAM if needed (@ $6000-$7FFF)), except that which is intended to survive a reset (such as high scores).
  • Wait at least 30,000 cycles (see Power-up state of PPU) before reading or writing registers $2003 through $2007. This is commonly done by waiting for the PPU to signal the start of vertical blank twice through $2002.

Some mappers have no fixed bank because they switch all 32 KB of PRG at a time. These include AxROM, BxROM, GxROM, and some configurations of Nintendo MMC1. You'll have to put the interrupt vectors and the code up to the end of the JMP in a separate section that is duplicated in each bank.

Sample implementation:

reset:
    sei        ; ignore IRQs
    cld        ; disable decimal mode
    ldx #$40
    stx $4017  ; disable APU frame IRQ
    ldx #$ff
    txs        ; Set up stack
    inx        ; now X = 0
    stx $2000  ; disable NMI
    stx $2001  ; disable rendering
    stx $4010  ; disable DMC IRQs

    ; Optional (omitted):
    ; Set up mapper and jmp to further init code here.

    ; Clear the vblank flag, so we know that we are waiting for the
    ; start of a vertical blank and not powering on with the
    ; vblank flag spuriously set
    bit $2002

    ; First of two waits for vertical blank to make sure that the
    ; PPU has stabilized
@vblankwait1:  
    bit $2002
    bpl @vblankwait1

    ; We now have about 30,000 cycles to burn before the PPU stabilizes.
    ; Use it to clear RAM.  X is still 0...
    txa
@clrmem:
    sta $000,x
    sta $100,x
    sta $200,x
    sta $300,x
    sta $400,x
    sta $500,x
    sta $600,x
    sta $700,x  ; Remove this if you're storing reset-persistent data
    inx
    bne @clrmem
   
@vblankwait2:
    bit $2002
    bpl @vblankwait2