Pinball 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. there are 2 files for symbols. symbols.inc which has NES specific values for APU, PPU, and controller. locals.inc has application specific values for zero page variables and forward references while decoding. --- ## Promotion requirements (must all be satisfied before a project is promoted out of `_wip//` into its mapper folder, e.g. `NROM//`) ### Pass 3: Symbols and locals applied Before any promotion, `_tools/apply_symbols.py` must have been run on `prg.s`, substituting `symbols.inc`/`locals.inc` names into operands: - All NES hardware registers (PPU, APU, controller) must be referenced by their symbolic names from `symbols.inc`, never as raw `$2000-$4017` literals. - Zero-page variables must use their `locals.inc` names where those aliases exist; multi-alias addresses require a `--sites` file for per-routine resolution. - Any remaining numeric operands that could have been named but were left as residue must be documented in `locals.inc` with a recorded reason. - `make` must print **Byte-identical ROM verified.** (whole-ROM compare against `rom.nes` in the project folder) after symbol application. ### Pass 3: ROM-specific semantic naming Before promotion, every routine, table, data block, and zero-page alias must carry a name derived from **observed ROM behavior**, not generic placeholders: - Method/table names must describe *what they do in this game*. Names like `Actor`, `Object`, `Entity`, `Sprite` are placeholders and are **not acceptable** unless the ROM genuinely has no more specific semantic basis. - Example: In a game about soldiers, a routine that updates soldier position must be named something like `UpdateSoldierPosition` or `MoveSoldier` — **never** `UpdateActor` or `MoveEntity`. A table holding soldier health must be `SoldierHealthTable`, not `ActorDataTable`. - Data tables must be named for their content (e.g., `LevelLayoutTable`, `EnemyPatternTable`, `TitleScreenText`), not generically (`DataTable1`, `Buffer`). - Zero-page aliases in `locals.inc` must use behavioral names (e.g., `SoldierX`, `BulletY`, `FrameCounter`), not neutral `ZpXX` names, unless the role is genuinely undetermined after tracing. ### Pass 3: Branch and jump targets use named labels Before promotion, every branch (`beq`, `bne`, `bcc`, `bcs`, `bpl`, `bmi`, `bvc`, `bvs`) and every jump/call (`jmp`, `jsr`) must target a **symbolic label**, never a raw address literal: - Branch targets must be labeled with descriptive names derived from their role (e.g., `UpdateSoldierPosition_Loop`, `CheckHit_NotHit`, `GameMode_Return`). - `jsr`/`jmp` targets must use semantic entry-point names (e.g., `SubC0400` is acceptable as an address-derived entry point only if no better semantic name exists; a routine that plays music must be `PlayMusic` or similar). - No branch or jump operand may be a raw `$XXXX` address in `prg.s`. - Labels used as branch/jump targets must be defined exactly once in `prg.s`. - Every label that is the target of a branch or jump must have a name that reflects its role in program flow (e.g., `_Loop`, `_Next`, `_Done`, `_Store`, `_Return`, `_Skip`, `_Exit`), not just `Label_C000`. ### Verification checklist before promotion 1. `make` in the project folder prints **Byte-identical ROM verified.** 2. `prg.s` contains no raw `$2000-$4017` hardware literals — all use `symbols.inc` names. 3. `prg.s` contains no raw `$XXXX` jump/branch targets — every `jsr`, `jmp`, `beq`, `bne`, `bcc`, `bcs`, `bpl`, `bmi`, `bvc`, `bvs` targets a symbolic label. 4. `prg.s` contains no neutral `ZpXX` zero-page references unless truly undetermined; all others use `locals.inc` aliases. 5. `prg.s` has no generic placeholder names (`Actor`, `Object`, `Entity`, `DataTable1`, `Buffer`, `SubC` for anything with an identifiable role). 6. `locals.inc` documents every remaining `ZpXX` neutral slot with a recorded reason. 7. Project `README.md` contains a power-on flow analysis (RESET/NMI/main-loop walk) and a Pass 3 data-table inventory. 8. `apply_symbols.py` residue report shows no resolvable operand left numeric without justification. 9. `CHANGELOG.md` carries the project's Pass 1, Pass 2, Pass 3 and Promotion rows, with dates. ### Pass 3: Changelog entry `CHANGELOG.md` is the repository's running log, and it has two parts. **For every change, of any kind, to any project** - a disassembly, a rename, a comment repair, a tool fix, a documentation fix - a line goes into the **Pending** list at the top of the file, naming the project and saying what changed. The list is what the **next git commit's message is written from**, so the message and the log cannot drift apart. When the commit is made, the entries move to **History** under the commit they went in with, and **Pending** starts empty again. **For every milestone a project reaches**, the milestone also gets a row in the milestone index at the end of the file, which carries one section per project with a row for each of the four milestones - **Pass 1** (the code/data split), **Pass 2** (the labels replaced by names), **Pass 3** (the semantic naming) and **Promotion** (the move into the top-level mapper folder): - The row carries the **date** of the milestone and a sentence saying what it produced. Use the numbers the project README and the root `README.md` already carry: the instruction count, the code coverage, the number of named labels, the number of semantic zero-page aliases and the number of named data tables. - A milestone that has not happened gets a `-` in the date column and a note saying what is still open, so a reader can see at a glance which projects are done and which are not. - The entry is added **in the same commit** as the milestone it records, so the changelog and the source never disagree.