Donkey Kong Jr Math Promoted
Duck Hunt Promoted Ice Climber WIP
This commit is contained in:
1 parent
71ada15de0
commit
13bd782a90
60 files changed
+12567
-10994
No files matched your search
File renamed without changes.
@@ -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.
|
||||
@@ -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
|
||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
.segment "CHR"
|
||||
.incbin "chr.bin"
|
||||
File renamed without changes.
|
500 Internal Server Error
An error occurred: An error occurred Gitea Version: 28.2.0 |