Files
disasm/_wip/Golf (JU)/copilot/NMI_CALLBACK_AUDIT.md
T
2026-10-18 16:47:03 -04:00

3.3 KiB

Pass 1 NMI callback audit

Dispatcher

The hardware NMI vector enters $C0A6. The fixed prologue saves A/X/Y, performs OAM DMA from page $02, then executes JMP ($0002). Every installed callback must therefore finish through the common epilogue at $C0B8 or deliberately reset/restart the program.

$C888 is the generic installer:

  • Y -> $0002 (callback low byte)
  • X -> $0003 (callback high byte)
  • PPU NMI remains enabled through the shadow value at $00

Confirmed callback installations

$C6C8 installed at $C0EC

Caller loads Y=$C8, X=$C6, then calls $C888.

Role: early/main gameplay display callback. It updates OAM entries at $0214-$0217 and $0284-$0287, advances animation counters $8E/$8F, and terminates with JMP $C0B8.

$CFAA installed at $CF5C

Caller loads Y=$AA, X=$CF, then calls $C888.

Role: gameplay sequencing callback. It decrements/increments $32, updates OAM coordinates, and changes the callback vector to one of the following mid-routine continuations as state thresholds are crossed:

  • $CFC3
  • $D03E
  • $D08A

The routine ultimately reaches the gameplay display tail at $C6C8, which exits through $C0B8.

$DAA2 installed at $DA27

Caller loads Y=$A2, X=$DA, then calls $C888.

Role: title/menu/attract controller callback. It polls controller port $4016, updates $09/$0A/$0D, writes one OAM cursor entry at $0200-$0203, and either:

  • jumps to $C0B8 for the normal NMI epilogue,
  • restarts title/game initialization through $DA2F/$DA4C, or
  • restarts the initial state through $C0C7.

Important correction: $DB0D (78 88 98) is used as OAM Y-position data for $0200, not as an NMI callback-low-byte table. Consequently $BA78/$BA88/$BA98 are not callbacks.

$C5A0 installed at $FC8E

Caller loads Y=$A0, X=$C5, then calls $C888.

Role: active gameplay controller/animation callback. It serially reads $4016, updates input-derived state $2E/$30, angle/selection fields $17/$44/$45, OAM entries, and then enters $C6C8 before returning through $C0B8.

Direct callback-vector transitions

The following direct writes to $02/$03 are confirmed executable and are part of the $CFAA-$D121 callback state machine:

  • $CFB6/$CFBA: install $CFC3
  • $CFDA/$CFDE: install $D03E
  • $D006/$D00A: install $D03E
  • $D02B/$D02F: install $D08A
  • $D05E/$D062: install $D08A
  • $D07A/$D07E: install $D08A

These are mid-routine continuation entries, not independent top-level systems. They share state in $17/$1D/$1E/$1F/$32/$34/$35 and converge on $C6C8.

Confirmed callback set

Top-level callback installations:

  • $C5A0
  • $C6C8
  • $CFAA
  • $DAA2

Dynamic continuation callbacks:

  • $CFC3
  • $D03E
  • $D08A

Common normal exit:

  • $C0B8

No other verified executable write to $0002/$0003 has been found. Apparent writes inside compressed hole packages are data and are excluded.

Source conversion

The previously retained callback spans are now emitted as annotated instructions:

  • $C5A0-$C71D: gameplay input/display callback chain
  • $CFAA-$D123: gameplay sequence callback and dynamic continuation entries

The three bytes at $C71E-$C720 remain data because execution at $C71B jumps directly to the NMI epilogue and cannot fall through into them.