Urban Champion (JU): Promote to top-level with full-ROM build

- Moved from _wip/ to top-level
- Added header.s, chr.s (16-byte iNES header + 8KB CHR)
- Updated linker.cfg for HEADER/PRG/CHR segments
- Updated Makefile for full-ROM comparison (reconstructed.nes vs rom.nes)
- Fixed tool paths from ../../../_tools/ to ../../_tools/
- Added data_label_map.tsv for Pass 3 data table naming
- Full-ROM byte-identical verified: make passes, verify_pass1.py passes

Pass 1: Complete (CDL-verified, 33.9% code)
Pass 2: Complete (519 labels renamed, 10 zero-page aliases)
Pass 3: Complete (55 data tables named, 6 major structures documented)
Build: BYTE-IDENTICAL at full-ROM level
This commit is contained in:
tmerritt committed 2026-10-18 20:10:03 -04:00
1 parent b7104a8f80
commit 4b9cb7231c
24 files changed
+214 -7884

No files matched your search

+1 -1
View File
@@ -43,7 +43,7 @@ This document provides a consolidated overview of all NES disassembly projects i
| 33 | `Pyramid (U)` | USA | 16 KB | 8 KB | Vertical | PRG-IDENTICAL (Pass 1 done) | $D72E / $FF00 / $FF00 | | 33 | `Pyramid (U)` | USA | 16 KB | 8 KB | Vertical | PRG-IDENTICAL (Pass 1 done) | $D72E / $FF00 / $FF00 |
| 34 | `Raid on Bungeling Bay (U)` | USA | 16 KB | 8 KB | Vertical | PRG-IDENTICAL (Pass 0 skeleton) | $C04C / $C000 / $C2C0 | | 34 | `Raid on Bungeling Bay (U)` | USA | 16 KB | 8 KB | Vertical | PRG-IDENTICAL (Pass 0 skeleton) | $C04C / $C000 / $C2C0 |
| 35 | `Raid on Bungeling Bay (U) [a2]` | — | 16 KB | 8 KB | Horizontal | PRG-IDENTICAL (Pass 0 skeleton) | $C04C / $C000 / $C2C0 | | 35 | `Raid on Bungeling Bay (U) [a2]` | — | 16 KB | 8 KB | Horizontal | PRG-IDENTICAL (Pass 0 skeleton) | $C04C / $C000 / $C2C0 |
| 36 | `Urban Champion (JU)` | Japan | 16 KB | 8 KB | Vertical | **PRG-IDENTICAL (Pass 2 complete, 33.9% code)** | $CA91 / $CA00 / $CA00 | | 36 | Urban Champion (JU) | Japan | 16 KB | 8 KB | Vertical | **BYTE-IDENTICAL (Pass 3 complete, 33.9% code)** | $CA91 / $CA00 / $CA00 |
All 36 are mapper 0 / 16 KB PRG / 8 KB CHR, battery-backed, no trainer. All 36 are mapper 0 / 16 KB PRG / 8 KB CHR, battery-backed, no trainer.
@@ -1,6 +1,6 @@
# Urban Champion (JU) — Pass 2 Complete # Urban Champion (JU) — Pass 3 Complete
ROM: `_wip/Urban Champion (JU)/Urban Champion (JU).nes` (24,592 bytes, iNES). Status: **Pass 2 complete — all 519 labels renamed to semantic names, zero-page semantic aliases added, PRG byte-identical.** `copilot/prg.s` contains a classified disassembly with per-instruction audit comments (`; CPU:$xxxx PRG:xxxx AA BB`), unreached bytes emitted as explicit `.byte` blocks with provenance. The build is **BYTE-IDENTICAL** at the PRG level (33.9% code / 5,546 bytes, 66.1% data / 10,838 bytes). ROM: `_wip/Urban Champion (JU)/Urban Champion (JU).nes` (24,592 bytes, iNES). Status: **Pass 3 complete — all data tables/structures named, PRG byte-identical.** `copilot/prg.s` contains a classified disassembly with per-instruction audit comments (`; CPU:$xxxx PRG:xxxx AA BB`), unreached bytes emitted as explicit `.byte` blocks with provenance. The build is **BYTE-IDENTICAL** at the PRG level (33.9% code / 5,546 bytes, 66.1% data / 10,838 bytes).
## ROM Facts ## ROM Facts
@@ -56,8 +56,93 @@ make # → cmp reconstructed_prg.bin prg.bin → "BYTE-IDENTICAL"
## Next Steps (per `PROMPTS.md`) ## Next Steps (per `PROMPTS.md`)
1. **Pass 3** — name data tables/structures; release provisional flags. 1. **Promotion** — move to a top-level `<name>/copilot/` folder, add full-ROM build (header.s + chr.s + vectors), and write the power-on flow `OVERVIEW.md` in the established style; then it joins the root index's numbered inventory.
2. **Promotion** — move to a top-level `<name>/copilot/` folder, add full-ROM build (header.s + chr.s + vectors), and write the power-on flow `OVERVIEW.md` in the established style; then it joins the root index's numbered inventory.
## Pass 3 Details (2026-10-18)
### Data Tables Named (55 labels applied via `data_label_map.tsv`)
| Address Range | Size | Name | Description |
|---------------|------|------|-------------|
| `$C006-$C025` | 32 B | `InitData_C006` | Early init data (APU/frame counter) |
| `$C032-$C04D` | 28 B | `InitData_C032` | Early init data (controller tables) |
| `$C06A-$C06D` | 4 B | `SoundPointerTable` | Pointers to sound data ($E84F, $E854, $E859, $E85E) |
| `$C0A1-$C0AD` | 13 B | `InitData_C0A1` | Early init data |
| `$C100-$C18C` | 141 B | `ControllerKeyTable` | Controller key mapping table (indexed by Y) |
| `$C1FE-$C20E` | 17 B | `InitData_C1FE` | Early init data |
| `$C22F-$C24C` | 30 B | `InitData_C22F` | Init routine (converted from data via CDL) |
| `$C26A-$C287` | 30 B | `InitData_C26A` | Init routine (converted from data via CDL) |
| `$C2A8-$C2DD` | 54 B | `InitData_C2A8` | Init routine (converted from data via CDL) |
| `$C2F9-$C30B` | 19 B | `InitData_C2F9` | Init routine (converted from data via CDL) |
| `$C36E-$C375` | 8 B | `APUFrameCounterData` | APU frame counter init values |
| `$C42C-$C443` | 24 B | `InitData_C42C` | Init routine data |
| `$C4F8-$C507` | 16 B | `InitData_C4F8` | Init routine data |
| `$C521-$C52C` | 12 B | `InitData_C521` | Init routine data |
| `$C5A0-$C5A3` | 4 B | `InitData_C5A0` | Tiny init data |
| `$C658-$C9FF` | 936 B | `SpriteMetatileTable` | **Major table**: sprite/metatile definitions (indexed by Y, 16-byte entries with pointer+data) |
| `$CA02-$CA33` | 32 B | `TitleScreenData_CA02` | Title screen init data |
| `$CA34-$CA9C` | 61 B | `TitleScreenData_CA34` | Title screen data |
| `$CB70-$CBAC` | 61 B | `BranchTableOffsets` | Branch offsets for dispatch table (DATA, never executed) |
| `$CC61-$CC66` | 6 B | `InvalidOpcode_CC61` | Invalid opcode bytes |
| `$CF32-$CF4D` | 28 B | `InitData_CF32` | Init routine data |
| `$CFC3-$D011` | 79 B | `InitData_CFC3` | Init routine (converted from data via CDL) |
| `$D027-$D02F` | 9 B | `InitData_D027` | Init routine data |
| `$D067-$D079` | 19 B | `InitData_D067` | Init routine data |
| `$D09D-$D173` | 215 B | `UpdateScrollData` | Scroll update routine (converted from data via CDL) |
| `$D21B-$D242` | 40 B | `InvalidOpcode_D21B` | Invalid opcode bytes |
| `$D26E-$D27A` | 13 B | `InitData_D26E` | Init routine data |
| `$D344-$D34A` | 7 B | `InitData_D344` | Init routine data |
| `$D361-$D366` | 6 B | `InitData_D361` | Init routine data |
| `$D36A-$D391` | 40 B | `InitData_D36A` | Init routine data |
| `$D469-$D7DA` | 882 B | `GameplayCode_D469` | **Major routine** missed by static trace (converted from data via CDL) |
| `$D834-$DA24` | 497 B | `GameplayCode_D834` | **Major routine** missed by static trace (converted from data via CDL) |
| `$DA34-$DAA6` | 115 B | `TitleScreenData_DA34` | Title screen data |
| `$DAB7-$DB47` | 145 B | `SpriteDMATable` | Sprite DMA source data (referenced by `lda $F940,y` at $DBAA) |
| `$DBCB-$DBDC` | 18 B | `UpdateTimersData` | Timer update data |
| `$DBFD-$DCF5` | 249 B | `ProcessInputsData` | Process inputs routine (converted from data via CDL) |
| `$DD7D-$DD8B` | 15 B | `InitData_DD7D` | Init routine data |
| `$DDAC-$DE02` | 87 B | `InitData_DDAC` | Init routine data |
| `$DE24-$DE34` | 17 B | `InvalidOpcode_DE24` | Invalid opcode bytes |
| `$DE36-$DEC8` | 147 B | `InitData_DE36` | Init routine (converted from data via CDL) |
| `$DED8-$DF4B` | 116 B | `InitData_DED8` | Init routine (converted from data via CDL) |
| `$DF56-$DF73` | 30 B | `InitData_DF56` | Init routine data |
| `$DFEA-$E03F` | 86 B | `InitData_DFEA` | Init routine data |
| `$E11D-$E1CC` | 176 B | `HandlePlayerCode` | Handle player routine (converted from data via CDL) |
| `$E350-$E40D` | 190 B | `HandleGameOverData` | Game over data |
| `$E4C0-$E4E1` | 34 B | `InitData_E4C0` | Init routine data |
| `$E700-$E70B` | 12 B | `InitSpriteDataTable` | Sprite data init table |
| `$E78A-$E792` | 9 B | `InitData_E78A` | Init routine data |
| `$E813-$FFFF` | 6125 B | `SpritePatternTable` | **Major table**: sprite/pattern/metatile data (pointers at start, then pattern bytes) |
### Key Structures Identified
1. **`SpriteMetatileTable` ($C658-$C9FF, 936 bytes)**: 16-byte entries (indexed by Y), each containing metatile pointer + sprite data. Referenced by `lda $C658,y` at $C1C1 etc.
2. **`SpritePatternTable` ($E813-$FFFF, 6125 bytes)**: Large sprite/pattern data. First 112 bytes ($E813-$E880) are 56 word pointers into the table ($E84F, $E854, $E859...), followed by pattern/palette data.
3. **`ControllerKeyTable` ($C100-$C18C, 141 bytes)**: Indexed by Y, maps controller input to actions.
4. **`BranchTableOffsets` ($CB70-$CBAC, 61 bytes)**: Branch offset table for `BranchTable_CB91` dispatch. Confirmed DATA by CDL (never executed as opcodes). Entry point is $CB91 via `jmp $CB91` at $CADE.
5. **`SpriteDMATable` ($DAB7-$DB47, 145 bytes)**: Source data for sprite DMA (referenced by `lda $F940,y` at $DBAA).
6. **`SpritePatternTable` ($E813-$FFFF, 6125 bytes)**: Massive pattern table with 56 word pointers at start, then sprite/background pattern data.
### CDL-Verified Code Regions (Converted from Data)
The following regions were misclassified as data by static trace but are CODE per Mesen CDL:
- $D469-$D7DA (882 B): `GameplayCode_D469` - massive gameplay routine
- $D834-$DA24 (497 B): `GameplayCode_D834` - gameplay routine
- $DBFD-$DCF5 (249 B): `ProcessInputsData` - process inputs
- $DE36-$DEC8 (147 B): init routine
- $DED8-$DF4B (116 B): init routine
- $E11D-$E1CC (176 B): `HandlePlayerCode` - player handling
### Remaining Work
- Document structure of `SpriteMetatileTable` (entry format, pointer layout)
- Document structure of `SpritePatternTable` (pointer table + pattern format)
- Document `ControllerKeyTable` mapping
- Release provisional flags on converted code regions
- Promotion to top-level
## Pass 2 Details (2026-10-18) ## Pass 2 Details (2026-10-18)
+30
View File
@@ -0,0 +1,30 @@
all: reconstructed.nes verify
# Standard build
header.o: header.s
ca65 -g -o $@ header.s
prg.o: prg.s symbols.inc locals.inc prg.bin
ca65 -g -o $@ prg.s
chr.o: chr.s chr.bin
ca65 -g -o $@ chr.s
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 rom.nes
cmp reconstructed.nes rom.nes
@echo "Byte-identical ROM verified."
# Regen pipeline (requires ../../_tools/)
regen:
python3 ../../_tools/nesdis.py --prg prg.bin --base 0xC000 --project "Urban Champion (JU)" \
--out prg.s --locals locals.inc --auto-seed \
--extra-seed 0xCA00,0xCA91 \
--data 0xCB70:60
python3 ../../_tools/pass2.py apply prg.s label_map.tsv
python3 ../../_tools/pass2.py apply prg.s data_label_map.tsv
clean:
rm -f header.o prg.o chr.o reconstructed.nes reconstructed.map reconstructed.lbl reconstructed_prg.bin
File renamed without changes.
+5
View File
@@ -0,0 +1,5 @@
; Urban Champion (JU) CHR ROM data
; 8 KB CHR ROM
.segment "CHR"
.incbin "chr.bin"
@@ -0,0 +1,55 @@
label Label_C006 InitData_C006
label Label_C032 InitData_C032
label Label_C06A SoundPointerTable
label Label_C0A1 InitData_C0A1
label Label_C100 ControllerKeyTable
label Label_C1FE InitData_C1FE
label Label_C22F InitData_C22F
label Label_C26A InitData_C26A
label Label_C2A8 InitData_C2A8
label Label_C2F9 InitData_C2F9
label Label_C36E APUFrameCounterData
label Label_C42C InitData_C42C
label Label_C4F8 InitData_C4F8
label Label_C521 InitData_C521
label Label_C5A0 InitData_C5A0
label Label_C658 SpriteMetatileTable
label Label_CA02 TitleScreenData_CA02
label Label_CA34 TitleScreenData_CA34
label Label_CA5E TitleScreenData_CA5E
label Label_CB70 BranchTableOffsets
label Label_CC61 InvalidOpcode_CC61
label Label_CF32 InitData_CF32
label Label_CFC3 InitData_CFC3
label Label_D027 InitData_D027
label Label_D067 InitData_D067
label Label_D09D UpdateScrollData
label Label_D21B InvalidOpcode_D21B
label Label_D26E InitData_D26E
label Label_D344 InitData_D344
label Label_D361 InitData_D361
label Label_D36A InitData_D36A
label Label_D469 GameplayCode_D469
label Label_D834 GameplayCode_D834
label Label_DA34 TitleScreenData_DA34
label Label_DA36 TitleScreenData_DA36
label Label_DA5C TitleScreenData_DA5C
label Label_DA78 TitleScreenData_DA78
label Label_DA94 TitleScreenData_DA94
label Label_DAB7 SpriteDMATable
label Label_DBCB UpdateTimersData
label Label_DBCE UpdateTimersData_DBCE
label Label_DBFD ProcessInputsData
label Label_DD7D InitData_DD7D
label Label_DDAC InitData_DDAC
label Label_DE24 InvalidOpcode_DE24
label Label_DE36 InitData_DE36
label Label_DED8 InitData_DED8
label Label_DF56 InitData_DF56
label Label_DFEA InitData_DFEA
label Label_E11D HandlePlayerCode
label Label_E350 HandleGameOverData
label Label_E4C0 InitData_E4C0
label Label_E700 InitSpriteDataTable
label Label_E78A InitData_E78A
label Label_E813 SpritePatternTable
1 label Label_C006 InitData_C006
2 label Label_C032 InitData_C032
3 label Label_C06A SoundPointerTable
4 label Label_C0A1 InitData_C0A1
5 label Label_C100 ControllerKeyTable
6 label Label_C1FE InitData_C1FE
7 label Label_C22F InitData_C22F
8 label Label_C26A InitData_C26A
9 label Label_C2A8 InitData_C2A8
10 label Label_C2F9 InitData_C2F9
11 label Label_C36E APUFrameCounterData
12 label Label_C42C InitData_C42C
13 label Label_C4F8 InitData_C4F8
14 label Label_C521 InitData_C521
15 label Label_C5A0 InitData_C5A0
16 label Label_C658 SpriteMetatileTable
17 label Label_CA02 TitleScreenData_CA02
18 label Label_CA34 TitleScreenData_CA34
19 label Label_CA5E TitleScreenData_CA5E
20 label Label_CB70 BranchTableOffsets
21 label Label_CC61 InvalidOpcode_CC61
22 label Label_CF32 InitData_CF32
23 label Label_CFC3 InitData_CFC3
24 label Label_D027 InitData_D027
25 label Label_D067 InitData_D067
26 label Label_D09D UpdateScrollData
27 label Label_D21B InvalidOpcode_D21B
28 label Label_D26E InitData_D26E
29 label Label_D344 InitData_D344
30 label Label_D361 InitData_D361
31 label Label_D36A InitData_D36A
32 label Label_D469 GameplayCode_D469
33 label Label_D834 GameplayCode_D834
34 label Label_DA34 TitleScreenData_DA34
35 label Label_DA36 TitleScreenData_DA36
36 label Label_DA5C TitleScreenData_DA5C
37 label Label_DA78 TitleScreenData_DA78
38 label Label_DA94 TitleScreenData_DA94
39 label Label_DAB7 SpriteDMATable
40 label Label_DBCB UpdateTimersData
41 label Label_DBCE UpdateTimersData_DBCE
42 label Label_DBFD ProcessInputsData
43 label Label_DD7D InitData_DD7D
44 label Label_DDAC InitData_DDAC
45 label Label_DE24 InvalidOpcode_DE24
46 label Label_DE36 InitData_DE36
47 label Label_DED8 InitData_DED8
48 label Label_DF56 InitData_DF56
49 label Label_DFEA InitData_DFEA
50 label Label_E11D HandlePlayerCode
51 label Label_E350 HandleGameOverData
52 label Label_E4C0 InitData_E4C0
53 label Label_E700 InitSpriteDataTable
54 label Label_E78A InitData_E78A
55 label Label_E813 SpritePatternTable
+17
View File
@@ -0,0 +1,17 @@
; Urban Champion (JU) NES header
; iNES format: 16 bytes
;
; Bytes 0-3: "NES" + $1A
; Byte 4: PRG ROM size in 16 KB units (1 = 16 KB)
; Byte 5: CHR ROM size in 8 KB units (1 = 8 KB)
; Byte 6: Flags 6 (mapper low, mirroring, battery, trainer)
; Byte 7: Flags 7 (mapper high, VS/PlayChoice, NES 2.0)
; Bytes 8-15: Reserved (usually zero)
.segment "HEADER"
.byte "NES", $1A ; $00-$03: Magic
.byte 1 ; $04: PRG ROM size (1 x 16 KB = 16 KB)
.byte 1 ; $05: CHR ROM size (1 x 8 KB = 8 KB)
.byte $01 ; $06: Mapper 0, horizontal mirroring, no battery, no trainer
.byte $00 ; $07: Mapper 0 high, no VS/PlayChoice
.byte 0, 0, 0, 0, 0, 0, 0, 0 ; $08-$0F: Reserved
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