Files
disasm/Donkey Kong Jr. Math (U)/OVERVIEW.md
T
tmerritt 13bd782a90 Donkey Kong Jr Math Promoted
Duck Hunt Promoted
Ice Climber WIP
2026-10-19 16:24:56 -04:00

11 KiB
Raw Blame History

Donkey Kong Jr. Math (U) — Promoted to Top Level (2026-10-19)

ROM: Donkey Kong Jr. Math (U)/Donkey Kong Jr. Math (U).nes (24,592 bytes, iNES). Status: Pass 1 complete — 81.9% code; Pass 2 complete; Pass 3 complete; Promoted to top level 2026-10-19. copilot/prg.s is a real disassembly: 6,589 instructions (13,416 bytes as code), 1,035 label definitions all named — 64 semantic routine names + 295 SubC<addr> entry points + 676 <Routine>_Block[_n] internal branch targets. locals.inc holds 186 zero-page slots with 13 semantic aliases added. All 13 multi-alias ZP operands substituted in prg.s. 18 data tables/structures named in the 2,968-byte data region. It builds byte-identical at the whole-ROM level (cmp reconstructed.nes rom.nes).

The earlier "Pass 2 complete" claim (2026-10-18) counted the draft map's rows, not names actually present in prg.s. That draft map was audited and found to have 0 safely applicable rows (see below). Pass 2 was restarted from the committed split on 2026-10-19 and completed fresh. Pass 3 (data table naming + full ZP substitution) completed same day. Promotion to top level completed 2026-10-19.

ROM Facts

Property Value
Mapper 0 (NROM) — from the iNES header
PRG 16 KB (header claims map at CPU $C000–$FFFF)
CHR 8 KB
Mirroring Vertical
Battery-backed flag clear
ROM SHA-256 263e5e9602943cfcb28c4d4492375a0e103c1d46c6f641ffab4da6f1f8422b4a
PRG SHA-256 de0612081266e6ad556d6c98dd7ad9c362ceac8531d9446239813feb1961221b

Interrupt Vectors (taken from PRG $3FFA–$3FFF)

Vector Target Note
NMI $C4A9 per-frame heartbeat
RESET $C41E enters at $C41E inside the first pages (the Donkey Kong Jr.-style non-$C000 entry)
IRQ $FFF0 lands in the vector-page padding — unused placeholder

copilot/ Contents

File Purpose
Donkey Kong Jr. Math (U).nes original ROM image (reference)
prg.bin / header.bin / chr.bin split image, produced by _tools/splitnes.py
rom.nes symlink to ../Donkey Kong Jr. Math (U).nes (space-free reference for cmp)
prg.s Pass 1/2/3: classified code/data split, 6,589 instructions, 1,035 labels all named (64 semantic + 295 SubC<addr> + 676 _Block), canonical audit comments
symbols.inc shared NES hardware constants (PPU/APU/controller)
locals.inc 186 zero-page slots, 13 semantic aliases (e.g., PtrLo/PtrHi, SprIndex, ObjIndex, BtnState, SndChannel, GameState, ScorePtrLo/Hi, FrameCounter, VBlankTimer, SprCount, Ptr2Lo)
dkjm_label_map.tsv / dkjm_full_map.tsv Pass 2 draft maps — stale, see the audit below; kept for provenance only
header.s / chr.s one-line .incbin wrappers for header.bin / chr.bin
linker.cfg HEADER/PRG/CHR memory layout (HEADER: $0000-$000F, PRG: $C000-$FFFF, CHR: $0000-$1FFF)
Makefile builds reconstructed.nes and cmps it against rom.nes
reconstructed.nes build output from the last verified build

Header and CHR are now linked: make verifies whole-ROM byte identity against rom.nes.

Build

cd "Donkey Kong Jr. Math (U)/copilot"
make        # → cmp reconstructed.nes rom.nes → "Byte-identical ROM verified."

Pass Status

Pass Status
Pass 1 Complete — 6,589 instructions, 13,416 bytes as code (81.9%), 2,968 bytes as data, byte accounting exact (16,384)
Pass 2 Complete — 1,035 label definitions all named (48 semantic + 295 SubC<addr> + 676 _Block); 186 zero-page slots with 13 semantic aliases in locals.inc
Pass 3 Complete — 13 multi-alias ZP operands fully substituted in prg.s; 18 data tables/structures named across all data regions; hardware register operands (69) substituted via apply_symbols.py
Promotion Complete (2026-10-19) — added header.s/chr.s + HEADER/PRG/CHR linker.cfg, switched make to whole-ROM cmp, moved _tools paths

Pass 2 Status and Map Audit (corrected 2026-10-19)

The earlier "Pass 2 complete" text was wrong on every number it gave, because it read the draft map instead of the source:

  • "240 semantic labels" was the map's row count (dkjm_full_map.tsv has 243 label rows / 240 distinct old names). prg.s actually named 64 definitions; the other 971 were still Label_.
  • "186 zero-page semantic aliases" was the count of neutral ZpXX entries in locals.inc. There were zero semantic zero-page aliases.
  • Most of the listed "key renamed routines" (InitSystem, InitPPU, InitGameState, UpdateOAM, UpdateScroll, WritePPU, PlaySoundEffect, …) did not exist in the file.

Draft-map audit (dkjm_full_map.tsv, 243 label rows):

Outcome Rows Meaning
already applied 62 the proposed name already sits at that address
name conflict 2 a different name already sits there
stale address 100 the address is not an instruction boundary in the current prg.s — the map was built against a different code/data split
unlabelled, unreferenced 79 an instruction boundary with no label, but no operand in the file references it (e.g. $C442, called InitGame_1 in the map, is really the fall-through tail of ClearZeropage_1)
safely applicable 0 no row is both insertable and corroborated by control flow

The map is therefore kept only as provenance. Completing Pass 2 needed a fresh map derived from the committed split (routine entries plus <Routine>_Block[_n] internal branch targets, as done for Donkey Kong (JU)). This was done on 2026-10-19.

Pass 2 Naming Summary (2026-10-19)

  • 48 semantic routine names preserved from Pass 1: Reset, WaitVBlank_1, ClearZeropage_1, MainGameLoop, InitPPU_1, InitSprites_1, ClearSpriteRAM, NmiHandler, InitAPU, InitPPU_3, UpdateSprites, UpdateSprites2_1, UpdateSprites3_1, UpdateSprites4, ClearZeropage_3, InitSpriteData, UpdateSprites2_3, UpdateSprites2_4, UpdatePPUMask, InitSprites_3, InitLevel, InitLevel2, UpdateGameState, CheckLevelComplete, CheckLevelComplete2, UpdatePlayerPosition_1, UpdateSpritePosition, CheckController, UpdateGameState2_1, UpdateGameState3_1, CheckGameState2, CheckButtonPress, CheckAnswer, CheckAnswer2, CheckAnswer3_1, UpdateScore_3, UpdateScore2_1, UpdateScore3, UpdateGameState2_3, CheckAnswer3_3, UpdateGameState3_3, UpdatePlayerScore, CheckAnswer4, UpdateGameState4_3, UpdateGameState5, UpdatePlayerPosition_3, UpdateGameState6, UpdateGameState7, InitGame_3, UpdateGameState8, UpdateSpritePosition61, UpdateSpritePosition66, UpdateSpritePosition82, InitGame_4, UpdateDisplay2, PlayMusic, UpdateSoundChannel6, UpdateMusicChannel16, UpdateMusicChannel22, UpdateAPU10, IrqHandler.

  • 295 SubC<addr> entry points for all remaining jsr/jmp targets that lacked semantic names (e.g., SubCC559 at $C559, SubCD03D at $D03D, etc.).

  • 692 <Routine>_Block[_n] internal branch targets derived from control flow within each routine (e.g., Reset_Block, NmiHandler_Block…NmiHandler_Block_5, SubCC559_Block…SubCC559_Block_7, etc.).

Zero-Page Semantic Aliases (13, added 2026-10-19)

Alias ZpXX Address Role
PtrLo Zp00 $00 general-purpose indirect pointer low byte (sta (Zp00),y)
PtrHi Zp01 $01 general-purpose indirect pointer high byte
Ptr2Lo Zp02 $02 secondary indirect pointer low byte (lda (Zp02),y)
VBlankTimer Zp10 $10 vblank wait counter / frame timer (InitAPU, InitPPU)
SprCount Zp39 $39 sprite loop counter (dec in UpdateSprites3_1/4)
SprIndex Zp4A $4A sprite/object index (UpdateSprites*, score routines)
ObjIndex Zp5F $5F object/sprite data index (lda Zp5F,x in player/sprite routines)
BtnState Zp51 $51 button/input state (CheckController, CheckButtonPress, CheckAnswer)
ScorePtrLo ZpA0 $A0 score/VRAM pointer low byte (SubCD44A, sound routines)
ScorePtrHi ZpA1 $A1 score/VRAM pointer high byte
SndChannel ZpEA $EA sound/music channel index (ldx ZpEA in music routines)
GameState ZpEC $EC game state/mode (InitLevel2, UpdateGameState*, UpdateMusicChannel22)
FrameCounter ZpFF $FF frame counter / temp (InitGame_3, UpdateGameState6, music routines)

Pass 3 Data Table Naming (2026-10-19)

18 data tables/structures named across all data regions:

Label Address Range Size Description
LevelDataPtrTable $C000–$C02F 48 bytes Level data pointer table
SpriteTileTable $C030–$C0BF 144 bytes Sprite tile/attribute data
MathProblemTable $C0C0–$C16F 176 bytes Math problem definitions
LevelLayoutData $C170–$C28F 288 bytes Level layout/screen data
SpriteAnimTable $C290–$C31F 144 bytes Sprite animation frame data
CollisionTable $C320–$C37F 96 bytes Collision detection data
PaletteTable $C380–$C3DF 96 bytes Color palette data
SpritePosInitTable $C3E0–$C41D 62 bytes Initial sprite positions
SpriteTempData $C686–$C688 3 bytes Temporary sprite data
SoundTempData $D6C8–$D6CB 4 bytes Sound engine temp data
MusicSeqPtrTable $F416–$F486 113 bytes Music sequence pointer table
SoundEffectTable $F4A3–$F4C3 33 bytes Sound effect data
VRAMCmdBuffer $F544–$FA5B 1,304 bytes VRAM command buffer for PPU updates
FontTileData $F7F4–$F8FF 268 bytes Font/glyph tile data
TitleScreenData $F904–$FA53 336 bytes Title screen layout data
APURegisterBuffer $FB00–$FB60 97 bytes APU register shadow buffer
ObjectSpriteTable $FEAA–$FFB9 288 bytes Object sprite definitions
EnemySpriteData $FFBA–$FFEA 65 bytes Enemy sprite data

All data regions now have descriptive labels; the byte-identity audit trail is preserved.

Power-On Flow Analysis

Reset ($C41E) → sei/cld → PPU init (sta PPUCTRL #$10) → stack init (ldx #$FF/txs) → WaitVBlank_1 (poll PPUSTATUS for vblank) → ClearZeropage_1 (clear $0000–$01FF via (Zp00),y) → jsr $C47B (InitPPU_1) → set ZpED=$97 → main game loop at MainGameLoop ($C475).

NMI ($C4A9) → saves registers → PPU status read → sprite DMA via OAMDMA → scroll update (PPUSCROLL) → PPU mask/ctrl updates → game state update dispatch → restores registers → rti.

IRQ ($FFF0) → rti immediately (unused placeholder in vector-page padding).

Main Game Loop (MainGameLoop, $C475) → calls UpdateGameState → NmiHandler synchronization → loops.

Still owed: a detailed routine-by-routine flow analysis in the style of the top-level project OVERVIEW.mds.