Donkey Kong Jr Math Promoted

Duck Hunt Promoted
Ice Climber WIP
This commit is contained in:
tmerritt committed 2026-10-19 16:24:56 -04:00
1 parent 71ada15de0
commit 13bd782a90
60 files changed
+12567 -10994

No files matched your search

+144
View File
@@ -0,0 +1,144 @@
# 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 `cmp`s 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
```bash
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.md`s.
+25
View File
@@ -0,0 +1,25 @@
CA65 ?= ca65
LD65 ?= ld65
all: reconstructed.nes verify
prg.o: prg.s symbols.inc locals.inc
$(CA65) -g -o $@ $<
header.o: header.s
$(CA65) -g -o $@ $<
chr.o: chr.s
$(CA65) -g -o $@ $<
reconstructed.nes: header.o prg.o chr.o linker.cfg
$(LD65) -C linker.cfg -m reconstructed.map -Ln reconstructed.lbl -o $@ header.o prg.o chr.o
verify: reconstructed.nes
cmp reconstructed.nes rom.nes
@echo "Byte-identical ROM verified."
clean:
rm -f *.o reconstructed.nes reconstructed.map reconstructed.lbl
.PHONY: all verify clean
+2
View File
@@ -0,0 +1,2 @@
.segment "CHR"
.incbin "chr.bin"
File renamed without changes.
Internal Server Error - Gitea: Git with a cup of tea
500 Internal Server Error

An error occurred:

An error occurred

Gitea Version: 28.2.0