# Donkey Kong (JU) — Pass 2/3 Complete, Promoted ROM: `Donkey Kong (JU)/Donkey Kong (JU).nes` (24,592 bytes, iNES). Status: **Pass 2/3 complete, promoted to top level 2026-10-19 — whole ROM rebuilds byte-identically.** `copilot/prg.s` contains a classified disassembly with 6,014 instructions (76.3% code / 12,505 bytes), **1,015 label definitions and zero `Label_` residue**, and 10 named data tables. `make` verifies header + PRG + CHR against `copilot/rom.nes` (a relative symlink that survives the `git mv`). **Relationship note:** separate title from the already-disassembled `Donkey Kong Jr. (JU)` and `Donkey Kong 3 (JUE)` — do not reuse their symbols. ## 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 | Horizontal | | Battery-backed flag | clear | | ROM SHA-256 | `f9f026fd3560eeb03be9f6d1efa329b4c71d562caf06d4a5a691e5342f8da8e6` | | PRG SHA-256 | `2952648e8a6eea65b7f388af8fce9ef33a9cb07178835fea6674db75d2623c49` | ## Interrupt Vectors (taken from PRG $3FFA–$3FFF) | Vector | Target | Note | |--------|--------|------| | NMI | `$C85F` | per-frame heartbeat | | RESET | `$C79E` | non-$C000 entry, like `Donkey Kong Jr. (JU)` | | IRQ | `$FFF0` | lands in the vector-page padding — unused placeholder | ## `copilot/` Contents | File | Purpose | |------|---------| | `rom.nes` | relative symlink → `../Donkey Kong (JU).nes` (space-free link name, per convention) | | `prg.bin` / `header.bin` / `chr.bin` | split image, produced by `_tools/splitnes.py` | | `header.s` / `chr.s` | one-line `.incbin` of `header.bin` / `chr.bin` (added at promotion) | | `prg.s` | Pass 1/2/3: classified code/data split, 6,014 instructions, 1,015 labels (zero `Label_` residue), 10 named data tables, audit comments on every emission | | `symbols.inc` | shared NES hardware constants (PPU/APU/controller) | | `locals.inc` | 145 zero-page slot definitions with neutral `ZpXX` names (behavioral naming not yet assigned) | | `linker.cfg` | HEADER (16 bytes) + PRG at $C000 (16 KB) + CHR (8 KB) | | `Makefile` | links `reconstructed.nes` (header + PRG + CHR) and `cmp`s it against `rom.nes` | | `reconstructed.nes` | build output from the last verified build | | `dk_full_map.tsv` | complete Pass 2 label map (919 applied rows) plus 407 `zp` proposals that were never applied | | `dk_label_map.tsv` | superseded first-draft map (219 label rows), kept for provenance | ## Build ```bash cd "Donkey Kong (JU)/copilot" make # → cmp reconstructed.nes rom.nes → "Byte-identical ROM verified." ``` ## Pass 2 Details (2026-10-19) All **919** remaining address-derived `Label_XXXX` definitions were replaced; `prg.s` now carries **1,015** labels and **zero `Label_` residue**. - **319 of the 919** were routine entry points (`jsr`/`jmp` targets): - **102** were named from observed behaviour — e.g. `LoadSpriteInitPointerToZp00` ($C807), `CopyVramDataToBuffer` ($CBDF), `UpdateObjectListZp5D` ($DA16), `CheckSpriteListCollision` ($D8AD), `UpdateRandomSeed` ($F4ED), `ReadControllers` ($F50E), `UpdateSoundEngine` ($FA48). - **217** stayed address-based as `SubC` (`SubCC24`, `SubCE130`, …) — honest residue where the body is too context-dependent to name without guessing. This matches sibling practice (`Golf (JU)`: 108, `Mario Bros (JU)`: 223). - The **77** entry points already named in earlier passes were left untouched. - **600** internal branch targets were named `_Block` / `_Block_n` in address order within their owning routine (the `Donkey Kong Jr. (JU)` / `Balloon Fight (JU)` convention). Ownership is control-flow containment: an internal label is attributed to the routine whose body actually reaches it, not merely the nearest preceding entry (this matters for loops that physically precede their own entry, e.g. `FlushPpuBuffer_Block` at $F1EC under the entry at $F228). - Two name collisions in the raw proposals were disambiguated by the indexing zero-page slot — `UpdateObjectListZp5D`/`DispatchObjectStateZp5E` ($DA16/$DA4C, index Zp5D/Zp5E) versus `UpdateObjectListZpAE`/`DispatchObjectStateZpAF` ($E1E9/$E250, index ZpAE/ZpAF). - `jsr`/`jmp` operands stay **numeric** (`jsr $F228`), matching `Wild Gunman (U)`; only branch operands are symbolic, so the call graph is read from the labels. - Applied with `_tools/pass2.py apply` (919 definitions + 2,622 references rewritten, comments re-aligned to the file's column convention); `make` still prints **byte-identical** — labels only, no byte or audit-comment content change. - **Residue:** the 217 `SubC` names, the 145 zero-page slots in `locals.inc` (neutral `ZpXX`), and the 407 unapplied `zp` proposals in `dk_full_map.tsv`. ## Pass 3 Details (2026-10-19) - **Data table naming**: 10 data regions identified and named in `prg.s`: - `LevelPtrTable` ($C000–$C03B, 60 bytes) — level header data - `ObjectPtrTable` ($C03C–$C043, 8 bytes) — 4 pointer pairs ($C63E/$C657/$C6E1/$C760) read by the dispatchers at $C815/$C823/$C831/$C847/$C853 - `LevelDataPtrTable` ($C044–$C79D, 1882 bytes) — level data pointer tables - `SpriteInitPtrTable` ($C4B0–$C4BF, labelled at the byte-row boundary) — **residue:** the routine at $C807 reads `$C4A7,x`/`$C4A8,x`, i.e. the referenced table starts mid-row at $C4A7, which cannot hold a label without splitting the canonical 16-byte audit-comment line; the label marks the row containing the tail instead - `UnreachedCode_D650` ($D650–$D696, 71 bytes) — unreached code block (clears $0472/$0473, copies $0200 → $0460) - `UnreachedCode_E144` ($E144–$E165, 34 bytes) — unreached code block (clears $0068–$0071, processes sprite data) - `MusicDataTable` ($F55B–$FA47, 1261 bytes) — music/sound data: note frequencies, envelopes, sequences - `APUDataTable` ($FAE6–$FB74, 143 bytes) — APU register tables: pulse/noise channel data, frequency LUTs - `SfxDataTable` ($FE59–$FFEF, 407 bytes) — sound effect data: frequency sweeps, envelope shapes, channel configs - `VectorTable` ($FFF6–$FFFF, 10 bytes) — 4 bytes of vector-page padding then the NMI/RESET/IRQ words at $FFFA–$FFFF - All regions remain byte-identical; `make` now proves the **whole ROM** (header + PRG + CHR). - No provisional flags remain; all data regions classified. Names like `LevelPtrTable` are descriptive (usage-derived where references exist — see the provenance comment block above the $C000 region in `prg.s`). ## Promotion (2026-10-19) Executed per `PROMPTS.md` / AGENTS.md: `git mv` to top level, `rom.nes` symlink added, `header.s` + `chr.s` + HEADER/PRG/CHR `linker.cfg` added (a Pass-0 skeleton ships none of the three), Makefile switched from `cmp reconstructed_prg.bin prg.bin` to `cmp reconstructed.nes rom.nes`. No `_tools` path change was needed — this Makefile does not reference `_tools/`, and there is no `make regen` target. Mirroring discrepancy resolved to Horizontal from header byte 6. ## Next Steps None outstanding for the pass contract. Optional deeper work: refine the descriptive table names above against runtime traces, decode the `$D650`/`$E144` unreached blocks into real code entries, and give behavioural names to the 217 `SubC` routines and the 145 zero-page slots where usage justifies it.