update of Circus WIP

start of Pyramid wip
This commit is contained in:
tmerritt committed 2026-10-16 16:17:08 -04:00
1 parent 9aef410424
commit 3877214637
8 files changed
+17570 -28

No files matched your search

+1
View File
@@ -32,5 +32,6 @@ cd "<Project>/copilot" && make # builds reconstructed.nes, then cmp vs rom.nes
- Zero pages are reused across modes; aliases may be required in `locals.inc` (e.g. `RandomStateAlt = $E4` beside `RandomState0 = $54`).
- Donkey Kong Jr. is architecturally different: reset entry is $C66E, the reset path idles forever in an LFSR loop, and the entire frame state machine runs inside NMI. Its `DeferredTaskHandlerTable` entry 0 deliberately mirrors the IRQ vector word at $BFFE.
- IRQ vectors often point at unused/data targets in these games — verify before assuming a handler is broken.
- Unlicensed titles break static-trace assumptions: Pyramid (U) pokes a mapper unlock at `$4100` (beyond the register space) despite a mapper-0 header, and dispatches through `jmp ($0002)` built from RAM — trace via its two queue tables (`$C3A6`, `$CCD5`), and do NOT fall-through-seed gaps that follow `rts`/`jmp`/`brk` (that misclassifies data as code).
- ROM filenames contain spaces; builds `incbin` a space-free `rom.nes` inside `copilot/`. Keep that copy/symlink working and don't rename it.
- `.gitignore` contains `ROMS/*` but the actual directory is `_ROMS` — the pattern matches nothing, so ROM binaries stay tracked. Check before committing large blobs.
+43 -1
View File
@@ -136,7 +136,47 @@ This document provides a consolidated overview of all NES disassembly projects i
---
## Skeleton Projects (under `_wip/`)
25 additional ROMs awaiting full disassembly. Each is set up as a Pass-0 skeleton (`default_project.tar.gz`): `copilot/` contains the split `prg.bin`/`header.bin`/`chr.bin`, a symbolic skeleton `prg.s`, and builds **BYTE-IDENTICAL** at the PRG level. Mapper 0 / 16 KB PRG / 8 KB CHR for all.
| Project | Vectors (NMI/RESET/IRQ) | Mir. | Status |
|---------|--------------------------|------|--------|
| `CIRCUS` | $C05A / $C000 / $C4B7 | H | BYTE-IDENTICAL |
| `Donkey Kong (JU)` | $C85F / $C79E / $FFF0 | V | BYTE-IDENTICAL |
| `Donkey Kong Jr. Math (U)` | $C4A9 / $C41E / $FFF0 | H | BYTE-IDENTICAL |
| `Duck Hunt (JUE)` | $C086 / $C000 / $C000 | H | BYTE-IDENTICAL |
| `Golf (JU)` | $C0A6 / $C000 / $C0C4 | H | BYTE-IDENTICAL |
| `Hogan's Alley (JU)` | $C088 / $C000 / $C000 | H | BYTE-IDENTICAL |
| `Ice Climber (JE)` | $C076 / $C014 / $FFF0 | V | BYTE-IDENTICAL |
| `Ice Climber (U)` | $C076 / $C014 / $FFF0 | V | BYTE-IDENTICAL |
| `Joypad Test Cartridge (U)` | $CCF7 / $C000 / $C000 | H | BYTE-IDENTICAL |
| `Lode Runner (U)` | $C02C / $C000 / $FFF9 | H | BYTE-IDENTICAL |
| `Lunar Pool (U)` | $FF65 / $E80C / $FF64 | H | BYTE-IDENTICAL |
| `MUSCLE (U)` | $86CB / $8000 / $8764 | H | BYTE-IDENTICAL |
| `Mario Bros (JU)` | $C07D / $C000 / $C000 | H | BYTE-IDENTICAL |
| `Millipede (U)` | $C7F1 / $C735 / $FFF0 | H | BYTE-IDENTICAL |
| `NES PowerPad Test Card (U)` | $E06E / $E000 / $E000 | H | BYTE-IDENTICAL |
| `Pac-Man (Tengen) (U)` | $C0FA / $C033 / $C16A | V | BYTE-IDENTICAL |
| `Pac-Man (U)` | $C0FA / $FF00 / $C16A | V | BYTE-IDENTICAL |
| `Pinball (JU)` | $C1ED / $C000 / $C1ED | H | BYTE-IDENTICAL |
| `Popeye (JU) (PRG 0)` | $C701 / $C649 / $FFF0 | H | BYTE-IDENTICAL |
| `Popeye (JU) (PRG 1)` | $C701 / $C649 / $FFF0 | V | BYTE-IDENTICAL |
| `Pyramid (U)` | $D72E / $FF00 / $FF00 | H | **Pass 1 done** — classified code/data, byte-identical; see `_wip/Pyramid (U)/OVERVIEW.md` |
| `Raid on Bungeling Bay (U)` | $C04C / $C000 / $C2C0 | H | BYTE-IDENTICAL |
| `Raid on Bungeling Bay (U) [a2]` | $C04C / $C000 / $C2C0 | V | BYTE-IDENTICAL |
| `Urban Champion (JU)` | $CA91 / $CA00 / $CA00 | H | BYTE-IDENTICAL |
| `Wild Gunman (U)` | $C086 / $C000 / $C000 | H | BYTE-IDENTICAL |
Notable vector/header observations for Pass 1 work:
- **Pac-Man (U)** RESET at `$FF00` (vector-page tail), while the Tengen variant RESETs at `$C033` — different builds confirmed (PRG bytes differ).
- **MUSCLE (U)** vectors sit in the `$8000-EFFF` window — inconsistent with the `prg.s` skeleton's expected `$C000-$FFFF` mapping; verify the header/image match before Pass 1.
- **Lunar Pool (U)** NMI `$FF65` / IRQ `$FF64` are adjacent in the vector page; RESET `$E80C`.
- **NES PowerPad Test Card (U)** RESET/IRQ both at `$E000`, far from the usual `$C000`-page entries.
- **Ice Climber (JE) vs (U)**: byte-identical PRG *and* header — only the CHR differs (~regional title graphic).
- **Popeye (JU) PRG 0 vs PRG 1**: different PRG binaries (and mirroring); same vectors.
- **Raid on Bungeling Bay (U) vs [a2]**: `[a2]` differs in mirroring only per header, but PRGs differ — separate builds.
- **Pyramid (U)** — *already at Pass 1*: interesting unlicensed Sachen boot ($4100 mapper pokes, "AV" stack-byte check, two queued-event dispatchers). See its `OVERVIEW.md`.
## Common Patterns Across All Projects
@@ -206,4 +246,6 @@ All 11 projects in this repository rebuild **byte-identical** to their original
| 10 | Donkey Kong 3 (JUE) | BYTE-IDENTICAL |
| 11 | Donkey Kong Jr. (JU) | BYTE-IDENTICAL (Pass 1) |
Every project builds successfully with `make` in the `copilot/` folder, and every reconstructed ROM matches the original byte-for-byte. Donkey Kong Jr. shares the same byte-identical build guarantee; its remaining Pass 2/3 work is semantic renaming and table decoding, not build-correctness.
Every project builds successfully with `make` in the `copilot/` folder, and every reconstructed ROM matches the original byte-for-byte. Donkey Kong Jr. shares the same byte-identical build guarantee; its remaining Pass 2/3 work is semantic renaming and table decoding, not build-correctness.
The 25 `_wip/` skeleton projects above also all rebuild byte-identical (PRG level); all Pass 1 work and promotion to this index's numbered inventory is future work.
+1 -1
View File
@@ -1,4 +1,4 @@
Donkey Kong Jr disassembly project.
CIRCUS disassembly project.
you will disassemble a NES rom. I will provide you with the skeleton project as a tar.gz file renamed to txt. build the byte identical rom. once you have completed a first pass to identify the code vs the data blocks, stop and provide me with the code. The goal is a byte-identical disassembly. Identify code and data sections. After the first pass, take a second pass and replace the known labels. Pass a third time to better identify use of code and data tables naming more appropriately.
with code blocks that are generated, each method will have a local and global description, the parameters and the return value(s). for each instruction, include a comment at the end of the line with the offset followed by the actual bytes that are expected to be encoded. during building the byte exact source, include the remaining incbin line so we can cycle through builds quickly and efficently.
+161 -2
View File
@@ -1,2 +1,161 @@
; CIRCUS zero-page aliases (declared during Pass 2).
; These intentionally conservative names will be refined in Passes 2 and 3.
; CIRCUS application-specific RAM aliases - Pass 2
; Generated from a complete static trace of direct zero-page accesses.
; ZpXX names indicate confirmed storage with a role not yet unique enough for a behavioral name.
Zp00 = $00 ; 24 refs; reads=13; writes=14; ClearInternalRamLoop, InitializeVramQueue, RunMainStateDispatcher
StateSubstage = $01 ; 14 refs; reads=12; writes=6; SecondaryStateHandlerPointerTable, ContinueStateInitialization, UpdateMenuState_OnNonzero_C237
Zp01 = $01 ; indexed structure-field alias
StateTimer = $02 ; 21 refs; reads=13; writes=15; InitializeCurrentScreen, UpdateMenuState, FinishStateHandler
Zp02 = $02 ; indexed structure-field alias
Zp03 = $03 ; 25 refs; reads=18; writes=7; FinishStateHandler_OnZero_C2D2, FinishStateHandler_OnNonnegative_C2EB, FinishStateHandler_OnNonzero_C32D
Zp04 = $04 ; 11 refs; reads=7; writes=8; NmiHandler, FinishNmiPpuUpdates, ResetPpuScroll
Zp05 = $05 ; 6 refs; reads=4; writes=2; AdvanceRoundTransition_OnZero_C34B, ReadControllers_OnNonzero_C40D, ReadControllers_StoreAndContinue_C444
Zp06 = $06 ; 2 refs; reads=1; writes=1; ProcessAudioFrame_JoinBranchPaths_F8AD, DecodeAudioStream_OnNotEqualFD_F902
Zp07 = $07 ; 4 refs; reads=2; writes=2; ReadControllers_StoreAndContinue_C444, ProcessAudioFrame_JoinBranchPaths_F8AD, DecodeAudioStream_OnNotEqualFD_F902
Zp08 = $08 ; 4 refs; reads=1; writes=3; RequestAudioSequence_OnNonzero_F835, DecodeAudioStream_IncrementAndContinue_F8E1, ExecuteAudioCommand_OnEqual04_FA80
ControllerEdgeFlags = $09 ; 22 refs; reads=17; writes=6; RunMainStateDispatcher, UpdateMenuState, ReadControllers_CallNext_C64B
Zp09 = $09 ; indexed structure-field alias
Zp0A = $0A ; 11 refs; reads=5; writes=6; FinishStateHandler_OnZero_C28F, FinishStateHandler_LoadAndContinue_C2AB, FinishStateHandler_OnNonnegative_C2EB
Zp0B = $0B ; 4 refs; reads=2; writes=2; FinishStateHandler_OnNonnegative_C2EB, AdvanceRoundTransition_OnZero_C39A, ExecuteAudioCommand_JoinBranchPaths_FA12
Zp0C = $0C ; 16 refs; reads=12; writes=4; DispatchVariantObjectUpdate_OnZero_D82E, DispatchVariantObjectUpdate_JoinBranchPaths_D88A, DispatchVariantObjectUpdate_OnBelow40_D8B7
Zp0D = $0D ; 6 refs; reads=5; writes=1; DispatchVariantObjectUpdate_OnZero_DA20, ObjectStateLookupTables_OnNonnegative_F34D, ExecuteAudioCommand_OnZero_F9D1
Zp0E = $0E ; 7 refs; reads=2; writes=5; UpdateMenuState_OnZero_C22B, FinishStateHandler_OnNonzero_C31B, ReadControllers_OnNonzero_C40D
Zp0F = $0F ; 18 refs; reads=11; writes=9; ReadControllers_JoinBranchPaths_C8E2, DispatchVariantObjectUpdate_JoinBranchPaths_D971, DispatchVariantObjectUpdate_OnEqualF0_D9E6
Zp10 = $10 ; 2 refs; reads=1; writes=1; ExecuteAudioCommand_OnNonzero_F99B, ExecuteAudioCommand_OnZero_F9D1
Zp12 = $12 ; 1 refs; reads=1; writes=0; SetPaletteRamAddress_OnZero_CA29
Zp1E = $1E ; 2 refs; reads=1; writes=1; RequestAudioSequence, RequestAudioSequence_OnZero_F85D
Zp23 = $23 ; 1 refs; reads=1; writes=0; SetPaletteRamAddress_LoadAndContinue_CA31
Zp2F = $2F ; 4 refs; reads=2; writes=2; RequestAudioSequence, RequestAudioSequence_OnNonzero_F835, RequestAudioSequence_OnEqual08_F867
Zp34 = $34 ; 1 refs; reads=1; writes=0; SetPaletteRamAddress_LoadAndContinue_CA31
Zp40 = $40 ; 2 refs; reads=1; writes=1; RequestAudioSequence, RequestAudioSequence_JoinBranchPaths_F873
Zp45 = $45 ; 1 refs; reads=1; writes=0; SetPaletteRamAddress_LoadAndContinue_CA25
Zp4F = $4F ; 2 refs; reads=1; writes=1; RequestAudioSequence, RequestAudioSequence_JoinBranchPaths_F873
Zp50 = $50 ; 6 refs; reads=5; writes=2; ReadControllers_LoadAndContinue_C470, ReadControllers_OnNonzero_C480, ReadControllers_OnNonnegative_C591
Zp51 = $51 ; 5 refs; reads=2; writes=3; SetupScreenPaletteTransfer_LoadIndexAndContinue_CF58, SetupScreenPaletteTransfer_OnZero_D1DC, SetupScreenPaletteTransfer_LoadIndexAndContinue_D1E4
Zp52 = $52 ; 5 refs; reads=5; writes=0; ObjectStateLookupTables_OnCarrySet_E548, ObjectStateLookupTables_JoinBranchPaths_E581, ObjectStateLookupTables_OnNonnegative_EC68
PpuCtrlShadow = $53 ; 11 refs; reads=8; writes=3; WriteMaskedPpuControl, InitializeApuAndPpu_LoadAndContinue_C3C1, SetPaletteRamAddress_LoadAndContinue_CA4B
PpuMaskShadow = $54 ; 3 refs; reads=1; writes=2; ApplyPpuMaskShadow, SetVisiblePpuMask, ConfigurePpuForScreenTransfer
Zp56 = $56 ; 11 refs; reads=6; writes=5; DispatchVariantObjectUpdate_OnNotEqual02_D84A, DispatchVariantObjectUpdate_OnNotEqual03_D86F, DispatchVariantObjectUpdate_OnNonzero_D987
Zp59 = $59 ; 1 refs; reads=0; writes=1; ClearInternalRamLoop
Zp5F = $5F ; 2 refs; reads=1; writes=1; FinishStateHandler_OnNonzero_C32D
Zp60 = $60 ; 3 refs; reads=3; writes=1; FinishStateHandler_OnZero_C28F, AdvanceRoundTransition_OnZero_C34B, ReadControllers_LoadAndContinue_C67B
Zp61 = $61 ; 6 refs; reads=4; writes=2; FinishStateHandler_OnZero_C2B2, AdvanceRoundTransition_OnZero_C39A, ReadControllers_LoadAndContinue_C62D
CurrentGameVariant = $63 ; 11 refs; reads=10; writes=1; ReadControllers_LoadIndexAndContinue_C835, ReadControllers_OnEqual06_C8C1, SetupScreenPaletteTransfer_LoadAndContinue_CD28
Zp64 = $64 ; 13 refs; reads=12; writes=1; ReadControllers_LoadIndexAndContinue_C835, ReadControllers_OnZero_C897, SetupScreenPaletteTransfer_LoadAndContinue_CF0D
Zp65 = $65 ; 1 refs; reads=0; writes=1; ReadControllers_JoinBranchPaths_C845
Zp66 = $66 ; 8 refs; reads=6; writes=4; AdvanceRoundTransition_OnZero_C34B, ReadControllers_OnZero_C897, ReadControllers_OnOverflowClear_C8B3
Zp67 = $67 ; 2 refs; reads=1; writes=2; AdvanceRoundTransition_OnZero_C34B
Zp68 = $68 ; 5 refs; reads=4; writes=1; SetupScreenPaletteTransfer_LoadAndContinue_CF0D, DispatchVariantObjectUpdate_LoadAndContinue_DA05, ObjectStateLookupTables_OnZero_E685
Zp69 = $69 ; 7 refs; reads=6; writes=1; ReadControllers_OnEqual06_C8C1, SetupScreenPaletteTransfer_LoadAndContinue_CF0D, DispatchVariantObjectUpdate_LoadAndContinue_DA05
Zp6A = $6A ; 20 refs; reads=16; writes=4; ReadControllers_JoinBranchPaths_C8E2, SetPaletteRamAddress_LoadAndContinue_CC20, SetPaletteRamAddress_OnNonzero_CC40
Zp6B = $6B ; 17 refs; reads=12; writes=7; ReadControllers_JoinBranchPaths_C8B5, ReadControllers_OnEqual06_C8C1, ReadControllers_OnAtLeast02_C8D7
Zp6C = $6C ; 4 refs; reads=1; writes=4; ObjectStateLookupTables_LoadAndContinue_E5B0, ObjectStateLookupTables_OnNonnegative_EC68, ObjectStateLookupTables_OnNonnegative_EC89
Zp6D = $6D ; 9 refs; reads=7; writes=8; ReadControllers_JoinBranchPaths_C8B5, InitializeRoundParameters, ObjectStateLookupTables_OnZero_E659
Zp6E = $6E ; 4 refs; reads=1; writes=3; FinishStateHandler_OnNonnegative_C2EB, AdvanceRoundTransition_OnZero_C34B, AdvanceRoundTransition_OnZero_C382
Zp6F = $6F ; 2 refs; reads=1; writes=1; ReadControllers_LoadAndContinue_C889
Zp70 = $70 ; 28 refs; reads=18; writes=10; ObjectStateLookupTables_JoinBranchPaths_E64C, ObjectStateLookupTables_OnBelow08_E667, ObjectStateLookupTables_OnNonzero_E7A9
Zp71 = $71 ; 7 refs; reads=5; writes=2; ObjectStateLookupTables_OnZero_E685, ObjectStateLookupTables_OnZero_E814, ObjectStateLookupTables_LoadAndContinue_E82C
Zp72 = $72 ; 4 refs; reads=1; writes=3; ObjectStateLookupTables_OnZero_E693, ObjectStateLookupTables_OnZero_EA68, ObjectStateLookupTables_LoadIndexAndContinue_F2DB
Zp73 = $73 ; 34 refs; reads=21; writes=13; SetPaletteRamAddress_LoadAndContinue_CC6C, DispatchVariantObjectUpdate_OnZero_DA3E, DispatchVariantObjectUpdate_OnNonzero_DA76
Zp74 = $74 ; 56 refs; reads=41; writes=23; SetPaletteRamAddress_LoadAndContinue_CC6C, DispatchVariantObjectUpdate_OnNotEqual02_D84A, DispatchVariantObjectUpdate_OnNotEqual03_D86F
Zp75 = $75 ; 6 refs; reads=3; writes=3; ObjectStateLookupTables_JoinBranchPaths_E823, ObjectStateLookupTables_OnNonzero_E8A8, ObjectStateLookupTables_OnAtLeast04_EB7B
Zp76 = $76 ; 30 refs; reads=9; writes=21; DispatchVariantObjectUpdate_JoinBranchPaths_DAB3, DispatchVariantObjectUpdate_StoreAndContinue_DADA, DispatchVariantObjectUpdate_OnCarrySet_DAE4
Zp77 = $77 ; 69 refs; reads=33; writes=37; SetPaletteRamAddress_LoadAndContinue_CC16, SetPaletteRamAddress_LoadAndContinue_CC20, SetPaletteRamAddress_OnNonzero_CC40
Zp78 = $78 ; 22 refs; reads=9; writes=13; SetPaletteRamAddress_LoadAndContinue_CC16, SetPaletteRamAddress_LoadAndContinue_CC20, SetupScreenPaletteTransfer_LoadAndContinue_CEE5
Zp79 = $79 ; 28 refs; reads=17; writes=18; ReadControllers_JoinBranchPaths_C845, ReadControllers_OnNonzero_C861, SetupScreenPaletteTransfer_LoadAndContinue_D1E8
Zp7A = $7A ; 17 refs; reads=8; writes=9; SetPaletteRamAddress_LoadAndContinue_CC20, SetupScreenPaletteTransfer_LoadAndContinue_D1E8, SetupScreenPaletteTransfer_OnNonzero_D206
Zp7B = $7B ; 27 refs; reads=14; writes=15; SetupScreenPaletteTransfer_OnZero_D21D, SetupScreenPaletteTransfer_OnZero_D255, SetupScreenPaletteTransfer_OnNonzero_D270
WorkPointer0Lo = $7C ; 24 refs; reads=14; writes=10; ReadControllers_OnNonzero_C861, SetupScreenPaletteTransfer_CallNext_CEB7, SetupScreenPaletteTransfer_CallNext_D1C4
Zp7C = $7C ; indexed structure-field alias
WorkPointer0Hi = $7D ; 10 refs; reads=2; writes=9; ReadControllers_OnNonzero_C861, ReadControllers_OnNonzero_C87C, SetupScreenPaletteTransfer_CallNext_CEB7
Zp7D = $7D ; indexed structure-field alias
WorkPointer1Lo = $7E ; 12 refs; reads=4; writes=8; SetPaletteRamAddress_LoadAndContinue_CBE4, SetupScreenPaletteTransfer_LoadAndContinue_D1E8, SetupScreenPaletteTransfer_OnNonzero_D206
Zp7E = $7E ; indexed structure-field alias
WorkPointer1Hi = $7F ; 17 refs; reads=10; writes=11; SetPaletteRamAddress_LoadAndContinue_CBE4, SetupScreenPaletteTransfer_LoadAndContinue_D1E8, SetupScreenPaletteTransfer_OnNonzero_D206
Zp7F = $7F ; indexed structure-field alias
Zp80 = $80 ; 9 refs; reads=2; writes=7; ReadControllers_OnNonzero_C861, DispatchVariantObjectUpdate_OnCarrySet_D9AB, DispatchVariantObjectUpdate_OnNonzero_D9C4
Zp81 = $81 ; 2 refs; reads=0; writes=2; ObjectStateLookupTables_OnZero_E685, ObjectStateLookupTables_LoadIndexAndContinue_F2DB
Zp82 = $82 ; 2 refs; reads=0; writes=2; ObjectStateLookupTables_OnZero_E693, ObjectStateLookupTables_LoadIndexAndContinue_F2DB
Zp83 = $83 ; 7 refs; reads=3; writes=4; DispatchVariantObjectUpdate_OnZero_DA3E, DispatchVariantObjectUpdate_JoinBranchPaths_DAB3, DispatchVariantObjectUpdate_OnCarrySet_DAE4
Zp84 = $84 ; 17 refs; reads=13; writes=10; DispatchVariantObjectUpdate_OnNotEqual03_D91A, DispatchVariantObjectUpdate_OnNotEqual03_D93D, DispatchVariantObjectUpdate_OnCarrySet_D9AB
Zp86 = $86 ; 5 refs; reads=0; writes=5; DispatchVariantObjectUpdate_JoinBranchPaths_DAB3, DispatchVariantObjectUpdate_OnEqual00_DC1B, DispatchVariantObjectUpdate_OnEqual03_DC21
Zp87 = $87 ; 9 refs; reads=5; writes=4; ObjectStateLookupTables_LoadAndContinue_EE5F, ObjectStateLookupTables_OnNonzero_EEBB, ObjectStateLookupTables_LoadAndContinue_F342
Zp88 = $88 ; 1 refs; reads=1; writes=0; ObjectStateLookupTables_OnZero_F356
Zp89 = $89 ; 2 refs; reads=1; writes=1; ProcessQueuedVramUpdates_LoadAndContinue_D2FD, ExecuteVramDescriptorStream
Zp8A = $8A ; 2 refs; reads=1; writes=1; ExecuteVramDescriptorStream, ExecuteVramDescriptorStream_OnNonzero_D35F
Zp8B = $8B ; 2 refs; reads=1; writes=1; SetupScreenPaletteTransfer_OnZero_D255, ObjectStateLookupTables_StoreIndexAndContinue_ED26
Zp8C = $8C ; 22 refs; reads=9; writes=13; SetPaletteRamAddress_LoadAndContinue_CBE4, SetPaletteRamAddress_LoadAndContinue_CC6C, SetupScreenPaletteTransfer_LoadAndContinue_D1E8
Zp8D = $8D ; 3 refs; reads=2; writes=1; SetPaletteRamAddress_LoadAndContinue_CBE4, SetPaletteRamAddress_LoadAndContinue_CC62, ObjectStateLookupTables_OnNonzero_F5D8
Zp8E = $8E ; 11 refs; reads=5; writes=6; SetPaletteRamAddress_LoadAndContinue_CBE4, SetPaletteRamAddress_LoadAndContinue_CC6C, SetupScreenPaletteTransfer_LoadAndContinue_D1E8
Zp8F = $8F ; 4 refs; reads=2; writes=2; SetPaletteRamAddress_LoadAndContinue_CC62, SetupScreenPaletteTransfer_CallNext_D1C4, ObjectStateLookupTables_OnNonnegative_E905
Zp90 = $90 ; 4 refs; reads=3; writes=2; ObjectStateLookupTables_LoadAndContinue_E61D, ObjectStateLookupTables_LoadAndContinue_F08C, ObjectStateLookupTables_OnZero_F09E
Zp91 = $91 ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_LoadIndexAndContinue_F0A8, ObjectStateLookupTables_OnNonzero_F155
Zp92 = $92 ; 3 refs; reads=3; writes=2; ObjectStateLookupTables_LoadAndContinue_EFC7, ObjectStateLookupTables_OnEqual02_EFDC
Zp94 = $94 ; 3 refs; reads=2; writes=1; ObjectStateLookupTables_LoadAndContinue_EFC7, ObjectStateLookupTables_OnEqual02_EFDC
Zp98 = $98 ; 3 refs; reads=2; writes=2; ObjectStateLookupTables_OnZero_E5D1, ObjectStateLookupTables_JoinBranchPaths_E618
Zp9A = $9A ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_LoadAndContinue_E7BA
Zp9B = $9B ; 6 refs; reads=3; writes=4; ReadControllers_JoinBranchPaths_C8E2, ObjectStateLookupTables_LoadIndexAndContinue_E484, ObjectStateLookupTables_JoinBranchPaths_E4AA
Zp9C = $9C ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_LoadIndexAndContinue_E521, ObjectStateLookupTables_OnNonzero_E86C
Zp9D = $9D ; 2 refs; reads=2; writes=1; ObjectStateLookupTables_LoadAndContinue_E509
ZpA7 = $A7 ; 3 refs; reads=1; writes=3; ObjectStateLookupTables_OnNonzero_EEBB, ObjectStateLookupTables_LoadAndContinue_F08C, ObjectStateLookupTables_OnZero_F09E
ZpA8 = $A8 ; 4 refs; reads=2; writes=2; ObjectStateLookupTables_LoadAndContinue_F08C, ObjectStateLookupTables_OnZero_F09E, ObjectStateLookupTables_OnCarryClear_F141
ZpAA = $AA ; 3 refs; reads=3; writes=1; ObjectStateLookupTables_OnBelow08_F672, ObjectStateLookupTables_OnCarryClear_F693, ObjectStateLookupTables_OnEqualFF_F6B6
ZpAB = $AB ; 3 refs; reads=2; writes=2; ReadControllers_JoinBranchPaths_C8B5, ReadControllers_JoinBranchPaths_C8D9, ObjectStateLookupTables_OnCarrySet_F44E
ZpAD = $AD ; 5 refs; reads=4; writes=3; ReadControllers_JoinBranchPaths_C8B5, ObjectStateLookupTables_OnBelow08_F672, ObjectStateLookupTables_JoinBranchPaths_F6E3
ZpAE = $AE ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_JoinBranchPaths_F4F5, ObjectStateLookupTables_LoadAndContinue_F540
ZpAF = $AF ; 5 refs; reads=2; writes=3; DispatchVariantObjectUpdate_JoinBranchPaths_D971, ObjectStateLookupTables_OnCarrySet_F131, ObjectStateLookupTables_JoinBranchPaths_F495
ZpB0 = $B0 ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_OnNotEqual40_E62D, ObjectStateLookupTables_OnBelow01_F6DD
ZpB3 = $B3 ; 3 refs; reads=1; writes=2; ObjectStateLookupTables_LoadIndexAndContinue_EED9, ObjectStateLookupTables_OnZero_EEFF, ObjectStateLookupTables_OnAtLeastA4_EF3D
ZpB8 = $B8 ; 6 refs; reads=2; writes=4; ReadControllers_JoinBranchPaths_C8E2, DispatchVariantObjectUpdate_JoinBranchPaths_D971, DispatchVariantObjectUpdate_OnEqualF0_D9E6
ZpBE = $BE ; 5 refs; reads=3; writes=3; DispatchVariantObjectUpdate_OnNonzero_DA76, ObjectStateLookupTables_LoadAndContinue_EE5F, ObjectStateLookupTables_JoinBranchPaths_EE86
ZpBF = $BF ; 5 refs; reads=5; writes=2; DispatchVariantObjectUpdate_OnZero_D912, DispatchVariantObjectUpdate_OnNotEqual02_D935, ObjectStateLookupTables_LoadAndContinue_EE0A
ZpC0 = $C0 ; 1 refs; reads=0; writes=1; ObjectStateLookupTables_OnBelow01_F6DD
ZpC5 = $C5 ; 1 refs; reads=1; writes=0; ReadControllers_CallNext_C64B
ZpC6 = $C6 ; 1 refs; reads=1; writes=1; ReadControllers_CallNext_C64B
ZpC7 = $C7 ; 3 refs; reads=2; writes=1; ObjectStateLookupTables_OnCarrySet_F44E, ObjectStateLookupTables_OnZero_F4BE, ObjectStateLookupTables_OnNonnegative_F5CD
ZpC9 = $C9 ; 6 refs; reads=3; writes=3; DispatchVariantObjectUpdate_OnZero_D887, DispatchVariantObjectUpdate_OnNonzero_D945, DispatchVariantObjectUpdate_OnCarryClear_D959
ZpCA = $CA ; 13 refs; reads=7; writes=6; DispatchVariantObjectUpdate_JoinBranchPaths_D885, DispatchVariantObjectUpdate_OnCarryClear_D8AF, DispatchVariantObjectUpdate_OnCarryClear_D8D7
ZpCB = $CB ; 4 refs; reads=2; writes=3; DispatchVariantObjectUpdate_OnNonzero_DA60, DispatchVariantObjectUpdate_OnNonzero_DA76, ObjectStateLookupTables_OnNonnegative_F0BD
ZpCC = $CC ; 2 refs; reads=1; writes=1; UpdateMenuSelection_LoadAndContinue_D5DF, ObjectStateLookupTables_JoinBranchPaths_DCE6
ZpCD = $CD ; 6 refs; reads=3; writes=4; ReadControllers_JoinBranchPaths_C8E2, DispatchVariantObjectUpdate_OnCarryClear_D959, DispatchVariantObjectUpdate_OnZero_DA19
ZpCE = $CE ; 6 refs; reads=2; writes=4; DispatchVariantObjectUpdate_JoinBranchPaths_D839, DispatchVariantObjectUpdate_OnZero_D858, DispatchVariantObjectUpdate_OnZero_D87F
ZpCF = $CF ; 2 refs; reads=1; writes=2; ReadControllers_JoinBranchPaths_C8E2, ObjectStateLookupTables_LoadAndContinue_F601
ZpD0 = $D0 ; 5 refs; reads=3; writes=2; ObjectStateLookupTables_OnNonzero_E86C, ObjectStateLookupTables_OnZero_E8E9, ObjectStateLookupTables_OnZero_E9B3
ZpD1 = $D1 ; 1 refs; reads=0; writes=1; ObjectStateLookupTables_OnNonnegative_E980
ZpD2 = $D2 ; 3 refs; reads=3; writes=2; ObjectStateLookupTables_JoinBranchPaths_F267, ObjectStateLookupTables_JoinBranchPaths_F2A0, ObjectStateLookupTables_OnZero_F356
ZpD3 = $D3 ; 5 refs; reads=4; writes=3; ObjectStateLookupTables_JoinBranchPaths_F474, ObjectStateLookupTables_LoadIndexAndContinue_F479, ObjectStateLookupTables_OnCarrySet_F4BB
ZpD4 = $D4 ; 1 refs; reads=0; writes=1; ObjectStateLookupTables_OnEqualFE_E9A9
ZpD5 = $D5 ; 4 refs; reads=3; writes=2; ObjectStateLookupTables_OnCarrySet_F44E, ObjectStateLookupTables_CallNext_F5C6, ObjectStateLookupTables_OnNonnegative_F5CD
ZpD6 = $D6 ; 3 refs; reads=1; writes=2; ObjectStateLookupTables_OnCarrySet_F44E, ObjectStateLookupTables_LoadIndexAndContinue_F479, ObjectStateLookupTables_JoinBranchPaths_F495
ZpD7 = $D7 ; 2 refs; reads=1; writes=1; ObjectStateLookupTables_LoadAndContinue_F540
ZpD9 = $D9 ; 4 refs; reads=0; writes=4; ReadControllers_OnNonnegative_C900, ObjectStateLookupTables_OnEqual20_E8CD, ObjectStateLookupTables_OnNonzero_EBE7
ZpDB = $DB ; 1 refs; reads=0; writes=1; ObjectStateLookupTables_OnNonzero_E849
ZpDE = $DE ; 10 refs; reads=5; writes=5; ReadControllers_JoinBranchPaths_C8E2, DispatchVariantObjectUpdate_LoadIndexAndContinue_D824, DispatchVariantObjectUpdate_OnNonzero_D8E4
ZpDF = $DF ; 18 refs; reads=15; writes=4; ReadControllers_JoinBranchPaths_C8E2, DispatchVariantObjectUpdate_OnCarrySet_D820, DispatchVariantObjectUpdate_JoinBranchPaths_D88A
IndirectPointerLo = $E0 ; 13 refs; reads=1; writes=12; ClearUpperRamPages, SelectNametableClearPage_OnNonzero_C3E2, ReadControllers_LoadIndexAndContinue_C4BA
IndirectPointerHi = $E1 ; 14 refs; reads=3; writes=13; ClearUpperRamPages, ClearUpperRamPageLoop, SelectNametableClearPage_OnNonzero_C3E2
TransferByteCount = $E2 ; 7 refs; reads=3; writes=7; SelectNametableClearPage_OnNonzero_C3E2, ClearPpuPage_OnNonzero_C3FA, ReadControllers_OnNonzero_C4AF
ZpE3 = $E3 ; 3 refs; reads=1; writes=3; ReadControllers_OnCarryClear_C4EA, ReadControllers_LoadAndContinue_C67B, ReadControllers_OnNonnegative_C68D
Controller1Shift = $E4 ; 10 refs; reads=6; writes=5; ReadControllers_OnNonzero_C40D, ReadControllers_StoreAndContinue_C444, ReadControllers_OnNonzero_C454
ZpE4 = $E4 ; indexed structure-field alias
Controller2Shift = $E5 ; 4 refs; reads=2; writes=3; ReadControllers_OnNonzero_C40D, ReadControllers_OnNonzero_C454, ReadControllers_OnCarryClear_C4EA
ControllerReadScratch = $E7 ; 4 refs; reads=2; writes=2; ReadControllers_OnNonzero_C40D
ZpE8 = $E8 ; 3 refs; reads=2; writes=1; ReadControllers_StoreIndexAndContinue_C6F3, ReadControllers_OnBelow0A_C70D
ZpEE = $EE ; 4 refs; reads=2; writes=2; ReadControllers_StoreIndexAndContinue_C6F3, ReadControllers_OnBelow0A_C70D
ZpEF = $EF ; 7 refs; reads=4; writes=4; ReadControllers_LoadAndContinue_C5B2, ReadControllers_OnNonnegative_C5B6, ReadControllers_StoreIndexAndContinue_C6F3
ZpF0 = $F0 ; 8 refs; reads=4; writes=6; DecodeAudioStream_OnZero_F962, ExecuteAudioCommand_OnNotEqualE0_FA23, ExecuteAudioCommand_OnNonzero_FA32
ZpF1 = $F1 ; 4 refs; reads=2; writes=3; DecodeAudioStream_OnZero_F962, ExecuteAudioCommand_OnNotEqual0C_FA62, ExecuteAudioCommand_JumpNext_FA73
ZpF2 = $F2 ; 1 refs; reads=0; writes=1; RequestAudioSequence_OnNonzero_F835
ZpF3 = $F3 ; 1 refs; reads=0; writes=1; RequestAudioSequence_OnNonzero_F835
AudioChannelStructOffset = $F4 ; 8 refs; reads=7; writes=1; ProcessAudioFrame_OnCarryClear_F880, ProcessAudioFrame_OnZero_F88B, DecodeAudioStream_OnZero_F921
AudioApuRegisterOffset = $F5 ; 14 refs; reads=13; writes=1; ProcessAudioFrame_OnCarryClear_F880, ProcessAudioFrame_OnNotEqual54_F895, ProcessAudioFrame_OnNonnegative_F89E
AudioSequencePointerLo = $F6 ; 5 refs; reads=4; writes=2; ProcessAudioFrame_JoinBranchPaths_F8AD, DecodeAudioStream, ExecuteAudioCommand_OnNotEqual08_F981
AudioSequencePointerHi = $F7 ; 4 refs; reads=3; writes=2; ProcessAudioFrame_JoinBranchPaths_F8AD, DecodeAudioStream, ExecuteAudioCommand_OnNotEqual08_F981
SavedObjectIndex = $F8 ; 7 refs; reads=4; writes=3; SetPaletteRamAddress_StoreIndexAndContinue_CC7E, SetPaletteRamAddress_OnCarryClear_CC8C, SetPaletteRamAddress_StoreIndexAndContinue_CC8F
SavedObjectSlot = $F9 ; 21 refs; reads=14; writes=7; SetPaletteRamAddress_StoreIndexAndContinue_CB2D, SetPaletteRamAddress_JoinBranchPaths_CB4B, ObjectStateLookupTables_OnNonzero_E601
SavedTransferIndex = $FA ; 8 refs; reads=4; writes=4; UpdateMenuSelection_OnZero_D627, UpdateMenuSelection_OnNonzero_D62B, ObjectStateLookupTables_LoadAndContinue_E562
NmiDelayCounter = $FB ; 3 refs; reads=2; writes=2; NmiHandler, ReadControllers_LoadAndContinue_C4C8
ZpFF = $FF ; 2 refs; reads=1; writes=1; FinishStateHandler_OnNonzero_C32D
MenuSelectionIndex = $0302
VariantSequenceCounter = $03B0
+12748 -5
View File
File diff suppressed because it is too large. Load diff
+73 -14
View File
@@ -1,7 +1,6 @@
# Pyramid (U) — Skeleton Project
ROM: `_wip/Pyramid (U)/Pyramid (U) (Sachen).nes` (24,592 bytes, iNES). Status: **SKELETON — not yet disassembled.** The entire 16 KB PRG bank is a single unclassified block; `copilot/prg.s` is the default-project skeleton (`default_project.tar.gz`) that reproduces it as one `.incbin`. The skeleton build is **byte-identical** at the PRG level.
# Pyramid (U) — Pass 1
ROM: `_wip/Pyramid (U)/Pyramid (U) (Sachen).nes` (24,592 bytes, iNES). Status: **PASS 1 — code/data split complete, byte-identical.** 5,834 of 16,384 PRG bytes (35.6%) are classified as traced 6502 code (396 labels, 70 distinct `jsr` targets); everything else is explicit `.byte` data with per-line PRG-offset annotations. `make` → `cmp reconstructed_prg.bin prg.bin` → **BYTE-IDENTICAL**.
## ROM Facts
@@ -19,9 +18,68 @@ ROM: `_wip/Pyramid (U)/Pyramid (U) (Sachen).nes` (24,592 bytes, iNES). Status: *
| Vector | Target | Note |
|--------|--------|------|
| NMI | `$D72E` | per-frame heartbeat |
| RESET | `$FF00` | initial execution at $FF00, inside the last PRG page — unusual; PASS 1 should confirm the true cold-start path |
| IRQ | `$FF00` | redirects to RESET — unused placeholder |
| NMI | `$D72E` | normal per-frame engine entry (waits PPU, runs frame state, drives APU silence/queue) |
| RESET | `$FF00` | real cold-start code — see boot chain below |
| IRQ | `$FF00` | redirects to RESET target; `sei` at boot, no `cli` seen on the traced path — IRQ likely never fires |
## Boot chain (all statically traced from `$FF00`)
1. `ldx #$FF / txs / sei / cld`, clear PPUCTRL/PPUMASK.
2. Repeated `LDA #<val> / JSR $FF49` — `$FF49` does **`STA $4100`** (write beyond the NES register space, $4000–$4017) followed by a long delay loop ($CE×256-ish iterations ×4 outer). The header claims mapper 0, but on the real Sachen cart these `$4100` pokes are an mapper-unlock/protection sequence. Boot pokes `$30`, `$10/$30/$10+$30` (via `$FF4C` delay variant twice) or `$20/$30/$20` depending on a check.
3. `JSR $FF57` — reads stack page bytes `$0120`/`$0121` and compares against `$41`/`$56` ("A","V"). `SEC` ⇒ proceeds to the `$4100` poke sequence above; `CLC` ⇒ alternate poke sequence, then falls into:
4. `JSR $FF69` — seeds `$0120`/`$0121` with `$41`/`$56`.
5. `JMP $C800` — real init: waits two `$2002` vblank phases, clears `$0000-$07FF`, builds ZP pointer `$D7/$D8 = $C8xx`, zeroes `$00`, writes `$98` to PPUCTRL / `$1A` to PPUMASK.
`$FF74-$FF7C` (`LDA #$00 / STA $0120 / STA $0121 / RTS`) clears the checker bytes; never called from static paths — emitted as data in the tail block.
## Dispatcher architecture (two queue + `jmp ($0002)` dispatchers)
The engine is the classic *queued-task* pattern (same family as the repo's Burger Time / DK Jr. analysis):
| Dispatcher | Site | Pointer | Vector table | Entries |
|-----------|------|---------|--------------|---------|
| 1 | `$C3A3` | `$0002/$0003` | `$C3A6` | 9: `$C3B6 $C3C7 $C3FD $C35F $C3E3 $C3E7 $C3EB $C3EF $D820` |
| 2 | `$CCCA` | `$0002/$0003` | `$CCD5` | 8: `$CCEE $CD27 $CC90 $CD75 $CD43 $CDA4 $CE1A $CE5E` |
Both build the pointer with the `TXA / ASL / TAX / LDA $tbl,X / STA $02 / LDA $tbl+1,X / STA $03 / LDX $45 / LDY $46 / jmp ($0002)` idiom; dispatcher 2 additionally copies an 8-byte low-value table from `$CCCD,X` into `$04EA,X` and syncs `$0430/$0431` (X/Y "cursor" state) before the jump. The `jmp ($0002)` sites terminate static traces; the tail at `$CCEB` (`jsr $D2BF / jsr $D476 / jmp $CC90`) re-queues into dispatcher 2.
**Pass-1 candidates not statically resolvable** (emitted as code where entered only via runtime dispatch, documented for Pass 2 review): `$D7EB` (`EA EA A2 FF 9A / jmp $D655` — alternate cold-start stub, caller unknown), `$C201` (PPUCTRL/PPUMASK setup helper + OAM-buffer splitters, fall-through of the `$2002` wait loop at `$C1F6-$C200`), `$C43E` (division/multiply-style arithmetic helper entered after `rts` at `$C43D`).
## Code coverage summary (final Pass-1 state)
| Metric | Value |
|--------|-------|
| Code bytes traced | 5,834 / 16,384 (35.6%) |
| Labels | 396 |
| Distinct `jsr` targets | 70 |
| Data/gap bytes | 10,550 (64.4%) |
| Indirect `jmp ($0002)` sites | 2 (both queue dispatchers) |
Regions entered only via runtime dispatch (queue-table targets) are traced; remaining unreached bytes sit in the data map below.
## Data map (unreached bytes, all provenance-checked)
| Region | Size | Content evidence |
|--------|------|------------------|
| `$C201-$C2FF` tail ($C225-$C2FF) | 219 | zero padding after the PPU-setup helpers |
| `$C34A-$C35E` | 21 | data after the dispatcher-1 `jmp ($0002)` tail |
| `$C3A6-$C3B7` | 18 | dispatcher-1 vector table (9 words) |
| `$C585-$C7FF` | 635 | text/marker tables (tile-index values `$88 $20 $88 $C1`; zero-padded from `$C714`) |
| `$C95A-$C9A6`, `$CAAA-$CAF2`, `$CBC1-$CBDB` | 177 | tile-index/lookup tables read via `lda $tbl,X` |
| `$CCCD-$CCE4` | 24 | dispatcher-2 low-byte table (8) + vector table (8 words) |
| `$D021-$D029` | 9 | brightness ramp `$0F $14 $28 $3C $50 $64` |
| `$D1AA-$D1B1`, `$D2AB-$D2BE` | 28 | small pointer/value tables |
| `$D320-$D3A0` | 129 | per-level byte tables (`$01 $02 $01 $02 ... $00 $08`) |
| `$D467-$D475`, `$D4EE-$D509`, `$D556-$D56A`, `$D5D5-$D631` | 146 | pointer/value pools read via `lda $tbl,X` / `adc` arithmetic |
| `$D69C-$D6AB` | 16 | value ramp `$27 $29 $2B $2D ...` |
| `$D79D-$D7E2` | 37 | small tables flanking the NMI handler |
| `$D7F3-$DE99` | 1,703 | packed level data (`$22 $2F`-patterned runs after the `$D7EB` stub) |
| `$DEBB-$DECA` | 16 | table |
| `$DF3E-$DF7F` | 80 | music frequency table (`$C3 $EC $6A $ED ...`) |
| `$E276-$ED6D` | 2,808 | audio pool: instrument/envelope ramps (`$FA $A8 $80 $3C ...` declining) + APU-register data |
| `$EDBF-$F890` | 2,770 | audio/graphics bulk tables + large `$00` runs (incl. `$F07F-$F890` padding) |
| `$F942-$FEFF` | 1,470 | mostly zeros — padding, save for small tables near `$FA00` |
| `$FF74-$FFF9` | 134 | tail: clear-checker bytes + pure zeros up to the vector page |
## `copilot/` Contents
@@ -29,14 +87,15 @@ ROM: `_wip/Pyramid (U)/Pyramid (U) (Sachen).nes` (24,592 bytes, iNES). Status: *
|------|---------|
| `Pyramid (U) (Sachen).nes` | original ROM image (reference) |
| `prg.bin` / `header.bin` / `chr.bin` | split image, produced by `_tools/splitnes.py` |
| `prg.s` | Pass-1 skeleton: `.incbin "prg.bin", $0000, $4000` (whole PRG) |
| `symbols.inc` | shared NES hardware constants (PPU/APU/controller, from the skeleton) |
| `locals.inc` | project-local zero-page aliases — empty for now (filled in Pass 2) |
| `prg.s` | Pass-1 classified source: traced code + explicit `.byte` data, `; PRG:$xxxx AA BB` per line |
| `symbols.inc` | shared NES hardware constants (PPU/APU/controller) |
| `locals.inc` | project-local zero-page aliases — still empty (filled in Pass 2) |
| `linker.cfg` | PRG at $C000, 16 KB, `fill = yes` |
| `Makefile` | links `reconstructed_prg.bin` and `cmp`s it against `prg.bin` |
| `reconstructed_prg.bin` | build output from the last verified build |
| `prg.s.skeleton` | backup of the pre-classification skeleton (`.incbin`-only) source |
Header/CHR are reproduced verbatim from `header.bin`/`chr.bin` (not linked): `make` verifies **PRG bytes only** at this stage, which is exactly what a skeleton proves. When this project is promoted to a full disassembly, `header.s` / `chr.s` (as e.g. `Burger Time (U)`) and a full-ROM `make` target get added.
Header/CHR are reproduced verbatim from `header.bin`/`chr.bin` (not linked): `make` verifies **PRG bytes only** at this stage, exactly like every other `_wip/` skeleton. When this project is promoted to a top-level full disassembly, `header.s` / `chr.s` and a full-ROM `make` target (cf. `Burger Time (U)`) get added.
## Build
@@ -47,7 +106,7 @@ make # → cmp reconstructed_prg.bin prg.bin → "BYTE-IDENTICAL"
## Next Steps (per `PROMPTS.md`)
1. **Pass 1** — replace the blanket `.incbin` with classified code/data: trace reachability from RESET ($FF00) and NMI ($D72E), emit per-instruction `; PRG:$xxxx AA BB` annotations, keep unreached bytes as explicit `.byte` blocks.
2. **Pass 2** — replace `Label_`/`Sub_` names with semantic routine names; fill `locals.inc`.
3. **Pass 3** — name data tables/structures; release provisional flags.
4. **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.
1. **Pass 1 — DONE.** Code/data split, `; PRG:$xxxx AA BB` audit annotations on every line, byte-identical build.
2. **Pass 2** — semantic names: `BootUnlock`, `StackByteCheck`, `QueueDispatch1/2`, NMI/IRQ frame handlers, audio routines; fill `locals.inc` with zero-page aliases (`$02/$03` pointer, `$45/$46` X/Y state, `$04EA` dispatcher copy, `$0120/$0121` "AV" checker).
3. **Pass 3** — name the data tables (level data at `$D7F3+`, envelope pool at `$E276+`, frequency table at `$DF3E`, ramps).
4. **Promotion** — move to a top-level `<name>/copilot/` folder, add `header.s`/`chr.s` + full-ROM `make`, write the power-on flow `OVERVIEW.md` in the established style; then it joins the root index's numbered inventory.
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
; Pyramid (U) NES disassembly - Pass 1 (skeleton)
; Generated from the supplied 16 KiB PRG image.
; Pass 1 classifies recursively reachable code, inline address tables, vectors,
; and untraced/data regions. All PRG data bytes are emitted explicitly with .byte directives.
.setcpu "6502"
.include "symbols.inc"
.include "locals.inc"
.segment "PRG"
.incbin "prg.bin", $0000, $4000