# 10-Yard Fight (U) ## Status **Pass 1.** The project builds and verifies byte-identical to the original ROM. `prg.s` is a traced disassembly classifying bytes as reachable code or data, with every instruction carrying a trailing audit comment. Unreached bytes remain as explicit `.byte` blocks; no ROM byte is deleted or reformatted. `make` assembles `header.s`, `prg.s`, `chr.s`, links them with `ld65` and compares the result against `rom.nes`: ``` Byte-identical ROM verified. ``` ## ROM | Property | Value | |----------|-------| | Format | iNES | | Mapper | 0 | | Board | NROM-256 | | Mirroring | Horizontal | | Four-screen VRAM | no | | Battery | no | | PRG | 32 KB (2 x 16 KB), mapped at CPU $8000-$FFFF | | CHR | 8 KB (1 x 8 KB) | | Trainer | none | | Footer | none | | NMI vector | $8471 | | RESET vector | $8000 | | IRQ vector | $84FF | | ROM file | `10-Yard Fight (U).nes` | | SHA-256 | `7b7d6af8c16b24adf4c71a923481aba1fff2b7dca782f821fd5187bd7c562bd1` | ### Header notes - none ## Power-on flow analysis Derived from the disassembly by `_tools/derive_poweron.py`; the call graph is walked from the reset entry. **RESET** is at `$8000` (`Reset`). The CPU comes here out of reset with the PPU and APU in their power-on state and the zero page and RAM uninitialised. The reset path calls: | Address | Routine | |---------|---------| | `$8007` | `SubC8007` (falls through) | | `$8012` | `SubC8012` (falls through) | | `$BE8D` | `SubCBE8D` | | `$902F` | `SubC902F` | | `$803A` | `SubC803A` (falls through) | | `$90FD` | `SubC90FD` | | `$C337` | `SubCC337` | | `$88FB` | `SubC88FB` | | `$807A` | `SubC807A` | | `$803A` | `SubC803A` | | `$8EC4` | `SubC8EC4` | | `$8EF1` | `SubC8EF1` | | `$89AD` | `SubC89AD` | | `$88C8` | `SubC88C8` | **NMI** is at `$8471` (`NmiHandler`). It is the per-frame handler; what it calls: | Address | Routine | |---------|---------| | `$84FA` | `SubC84FA` | **IRQ** is at `$84FF` (`IrqHandler`) - a different address from RESET. ## Pass 3 data-table inventory Every `; ---- data $XXXX-$YYYY` block in `prg.s` is listed below. A block is **named** when at least one instruction in this dump reads it, and the name carries the game's own concept (a team level, a play result, the scoreboard, the field). A block that no instruction reaches is left unnamed and is recorded here with its ROM provenance. Two facts about the ROM shape the table: - **The PRG is one 32 KB image, not two banks.** It is mapped at `$8000-$FFFF`; the vectors (`$FFFA-$FFFF`) are the last six bytes of the image, and the second 16 KB bank (`$C000-$FFFF`) is **not** a second copy of the first - it holds the OAM DMA routine at `$CC0E`, 13 386 bytes of `$FF` padding at `$CC24`, and the vectors. The running code is the first bank only. - **Two of the tables are code, not data.** `EntityUpdateJumpTable` (`$9E57`) and `EntityHandlerJumpTable` (`$8569`) are dispatch tables of 16-bit PRG addresses that the game reaches through `jmp (Zp10)` at `$9ECC` and `$84D0`. The static tracer cannot follow an indirect jump, so the handler bodies at those addresses (`$A3A8`, `$A0FB`, `$A7F3`, `$A3EC`, `$A46B`, `$AB20`, `$A612`, `$A94F`, `$A99B`, `$AD1A`, `$AE86`, `$AAF8`, `$AC7B`, `$AF77`, `$AEA8`, `$AF46`, `$84D3`, `$86E5`, `$873D`, `$879E`, `$84F6`, `$87CF`, `$87E7`, `$8453`, `$844A`, `$8450`) are still classified as data in `prg.s`. They are code the tracer could not reach, and they are listed below as such. ### Decoding the text tables Pattern table 0 of the CHR is an ASCII font: tile `$00`-`$09` are the digits `0`-`9`, tile `$0A`-`$23` are `A`-`Z`, tile `$24` is a full stop, tile `$2C` is a copyright sign, tile `$30` is the space, tile `$01`/`$25` spell `1St`, tile `$28` is a second small `st` shape, and tiles `$27`, `$2E` and `$2F` are arrow and rule graphics. Every "text" table below is a list of those tile indices terminated by `$FF`, and the reader is the nametable writer at `$9152` (`lda (Zp12),y` / `cmp #$FF` / `sta PPUDATA`). ### Inventory | Address | Size | Name | Structure | Read by | |---------|------|------|-----------|---------| | `$8329-$838F` | 103 | `LevelTeamNameTextPool` | 7 `$FF`-terminated nametable tile strings in 16-byte rows: `$8329` "HIGH SCHOOL", `$8339` " COLLEGE ", `$8349` "PROFESSIONAL", `$8359` " PLAYOFF ", `$8369` "SUPER BOWL ", `$8379` "FIRST HALF", `$8384` "SECOND HALF" | pointer built by `adc #$29` at `$82EF` (`$8329` + 16 x (team level AND `$FE`)) and `adc #$0B` at `$8314` (`$8384`); drawn by `jsr SubC9152` at `$8301` and `$8326` | | `$83EC-$841F` | 52 | `TeamLevelPresetPairTable` ($83EC), `TeamLevelCountdownPresetTable` ($83F6), `TeamLevelStatTable` ($840C), `TeamLevelSpriteOffsetTable` ($8414) | four per-team-level parameter tables: 5 x 2-byte preset pairs indexed by (level AND `$0E`); 11 x 2-byte pairs indexed by 2 x level; 16 bytes; 12 bytes | `lda $83EC,y` at `$83D5`, `lda $83ED,y` at `$83DA`, `lda $83F6,y` at `$83C6`, `lda $83F7,y` at `$83CB`, `lda $840C,y` at `$83E1`, `lda $8414,y` at `$83E6` (all in `SubC83C6`) | | `$844A-$8455` | 12 | - | **code the tracer could not reach** - handler reached through `jmp (Zp10)` at `$84D0` | pointer `$844A`/`$8450`/`$8453` loaded from `$8569` at `$84C6`/`$84CB` | | `$84D3-$84F2` | 32 | - | **code the tracer could not reach** - handler reached through `jmp (Zp10)` at `$84D0` | pointer `$84D3` loaded from `$8569` at `$84C6`/`$84CB` | | `$8555-$857E` | 42 | `SpriteInitRecordTable` ($8555), `EntityHandlerJumpTable` ($8569) | 5 x 4-byte sprite init records (a constant `$28` flag byte, a value byte, a constant `$01` flag byte and a tile column `$58`,`$60`,`$68`,`$70`,`$78`); 11 x 16-bit little-endian PRG code addresses | `lda $8555,x` at `$854B` (20 bytes copied to `$0760`, X = `$13`..`$00` from `ldx #$13` at `$8549`); `lda $8569,x` at `$84C6` and `lda $856A,x` at `$84CB` (X = (state AND `$1F`) x 2), dispatched by `jmp (Zp10)` at `$84D0` | | `$8691-$8838` | 424 | `FieldSpritePlacementTable` | 21 x 4-byte records (tile, sprite Y, X low, X high); the last three records (`$86D9-$86E4`) are copied separately; `$86E5-$8838` is **code** | `lda $8691,y` at `$8612`, `lda $8692,y` at `$861D`, `lda $8693,y` at `$8623`, `lda $8694,y` at `$8629`; `lda $86D9,x` at `$865F` and `$866A`; the code at `$86E5` is reached by `jmp (Zp10)` at `$84D0` | | `$88C1-$88C7` | 7 | `PlayerMoveStepTable` | 7 x 8-bit movement steps (1,1,2,3,4,5,6) | `lda $88C1,y` at `$88AA` and at `$88B5`, added to the low byte of the two 16-bit positions `Zp25`/`Zp27` | | `$88D3-$88F2` | 32 | `SpritePatternTable` | 8 x 4-byte sprite-pattern records, copied to the zero-page buffer `$00A3-$00C2` | `lda $88D3,x` at `$88CA` (32 bytes copied to `ZpA3`) | | `$8A8D-$8A94` | 8 | - | not referenced by any instruction; 4 x 16-bit little-endian values (`$03E8`=1000, `$0258`=600, `$0190`=400, `$00C8`=200) | not referenced by any instruction | | `$8ACC-$8B13` | 72 | `PlayerPositionTable` | 18 x 4-byte records (X low, Y low, X high, Y high); the first 12 records are the on-field player slots (two teams, four groups of three) | `lda $8ACC,x` at `$8AA0`, `lda $8ACD,x` at `$8AAA`, `lda $8ACE,x` at `$8AB0`, `lda $8ACF,x` at `$8AB6` (copied to `$07C4-$07C7`) | | `$8C5B-$8CA3` | 73 | - | **code the tracer could not reach** - 38 instructions ending in `JMP $CA10` | not referenced by any instruction | | `$8CE9-$8D27` | 63 | `PlayResultTextPool` | 4 bytes of code at `$8CE9`, then 4 `$FF`-terminated play-result strings: `$8CED` " NOT 10 YARD", `$8CFB` " 10 YARD BACK", `$8D09` "PASS INTERCEPT", `$8D18` " 20 YARD BACK" | pointer `$8CED` built at `$8B80`/`$8B84` and pointer `$8D0A` (the "PASS INTERCEPT" string) at `$8B9B`/`$8B9F`, both drawn by `jsr SubC9152`; the other two strings have no pointer in the traced code | | `$8DD5-$8DE1` | 13 | `HalfTimeUpText` | one 13-tile nametable string, " HALF TIME UP" | `lda $8DD5,y` at `$8DC7`, written to PPUDATA | | `$8EBC-$8EC3` | 8 | `RandomFieldPositionTable` | 8 x 8-bit field positions picked at random | `lda $8EBC,y` at `$8EA0` (Y = PRNG value AND `$07`), stored to `ZpE9`/`Zp38` | | `$8FD6-$8FFB` | 38 | - | **code the tracer could not reach** - 20 instructions ending in `JMP $8FFC` | not referenced by any instruction | | `$90E5-$90FC` | 24 | `NametableAttributeRowTable` | 3 x 8-byte nametable attribute rows (`$90E5`, `$90ED`, `$90F5`) | `lda $90E5,y` at `$90D6`, `lda $90ED,y` at `$90B1`, `lda $90F5,y` at `$90C1`, written to PPUDATA | | `$91B2-$927A` | 201 | - | **code the tracer could not reach** | not referenced by any instruction | | `$92BC-$92D2` | 23 | - | **code the tracer could not reach** | not referenced by any instruction | | `$92F4-$9371` | 126 | `StatusMessageTextPool` | 5 `$FF`-terminated status strings: `$92F4` "QUARTER", `$92FC` "DEFENSE", `$9304` "OFFENSE 1ST DOWN GAME OVER", `$931C` "CONGRATULATIONS, YOU MADE IT.", `$9339` "IT WAS A FINE PLAY"; `$934C-$9371` is **code** | `lda $9304,x` at `$92D9` (copying the third string); pointers `$9312` ("GAME OVER"), `$931C` and `$9339` built at `$937A`, `$93BD` and `$93D0` for `jsr SubC9152` | | `$94D8-$94DB` | 4 | `PpuScrollPresetTable` | 3 x 16-bit little-endian scroll presets; the entry used is index 2 = (`$06`,`$00`) | `lda $94D8,y` at `$94CD` and `lda $94D9,y` at `$94D2` with Y = `$02` (`ldy #$02` at `$94CB`) | | `$9894-$98F3` | 96 | `ScoreboardSpriteLayoutTable` | 48 x 2-byte (OAM Y, tile index) pairs; the scoreboard digits use Y = `$C8` with tiles `$D1`-`$D6` | `lda $9894,x` at `$97C5` and `lda $9895,x` at `$97CB` (copied into the OAM shadow at `$025C`) | | `$9937-$998A` | 84 | `ObjectDefinitionPointerTable` | 34 x 16-bit little-endian pointers (into the `$32xx` RAM window and the `$Bxxx` PRG window); `$997B-$998A` is **code** | `lda $9937,x` at `$9911` and `lda $9938,x` at `$9917`; the code at `$997B` is read by `lda $997B,y` at `$9691` | | `$99C2-$99DF` | 30 | `LevelParameterByteTable` ($99C2), `LevelPositionPairTable` ($99D6) | 20 x 8-bit per-level parameters; 5 x 2-byte little-endian per-level position pairs | `lda $99C2,x` at `$99A7` (3 bytes copied to `$0514`); `lda $99D6,x` at `$99B7` and `lda $99D7,x` at `$99BC` (index = level AND `$0E`, stored to `ZpA8`/`ZpA9`) | | `$9A1A-$9A1E` | 5 | `TeamStartRowIndexTable` | 5 consecutive nametable row indices (`$24`-`$28`) | `lda $9A1A,y` at `$9A06`, copied to `$0548` | | `$9A37-$9DD6` | 928 | `NametableRowPointerTable` ($9A37), `NametableRowDataPool` ($9A8B), `NametableRowDescriptorTable` ($9D4A) | 42 x 16-bit little-endian pointers into the pool; 703 bytes of variable-length nametable row data; 141 bytes of per-row descriptors (row indices, then 8-byte records) | `lda $9A37,y` at `$95E7` and `lda $9A38,y` at `$95EC`; `lda $9D4A,x` at `$998D` (copied to `$0500`); `lda $9D92,y` at `$9A10` (copied to `$0548`) | | `$9E57-$9E76` | 32 | `EntityUpdateJumpTable` | 16 x 16-bit little-endian handler addresses (the entity/object update dispatch table) | `lda $9E57,y` at `$9E8B` and `lda $9E58,y` at `$9E90`, stored to `Zp10`/`Zp11` and dispatched by `jmp (Zp10)` at `$9ECC` | | `$9FBE-$A009` | 76 | `FieldObjectRotationOffsetTable` ($9FBE), `FieldObjectColumnTable` ($9FC2) | 4 x 8-bit rotation offsets (`$00`,`$12`,`$24`,`$36`); 72 bytes = 4 rotations of an 18-entry list of byte offsets into the `$0700` object array | `adc $9FBE,y` at `$9FB4`; `lda $9FC2,y` at `$9FB8` (result stored to `Zp14`) | | `$A0AB-$A1D5` | 299 | `SpriteAnimationTable` | 26 x 3-byte sprite-placement records plus an 8-byte tail; `$A0FB-$A1D5` is **code** | `lda $A0AB,y` at `$A9E8`, `lda $A0F3,y` at `$A03F`; the code at `$A0FB` is reached by `jmp (Zp10)` at `$9ECC` with the pointer from `$9E57` | | `$A298-$A317` | 128 | `CheckerDitherBitmap` | 128 bytes of `$FF`/`$00` - a 1024-bit checkerboard dither mask | `lda $A298,y` at `$A1FA`, at `$A273` and at `$B0A9` | | `$A3A8-$A3C4` | 29 | - | **code the tracer could not reach** - entity handler | pointer `$A3A8` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A3D4-$A3D7` | 4 | `ObjectIndexTable` | 4 x 8-bit object indices, one per object-page group | `lda $A3D4,y` at `$9F46` (Y = `Zp13` >> 4, the object-page selector) | | `$A3EC-$A414` | 41 | - | **code the tracer could not reach** - entity handler | pointer `$A3EC` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A456-$A533` | 222 | `SpritePatternPointerTable` | 21 x 8-bit values, the low halves of code addresses in the `$80xx`-`$95xx` range, with `$91` meaning "no pattern"; `$A46B-$A533` is **code** | `lda $A456,y` at `$A43F` (stored to the low half of the pointer `Zp12`/`Zp13`); the code at `$A46B` is reached by `jmp (Zp10)` at `$9ECC` with the pointer from `$9E57` | | `$A5A4-$A5D4` | 49 | - | **code the tracer could not reach** - 21 instructions | not referenced by any instruction | | `$A612-$A778` | 359 | - | **code the tracer could not reach** - entity handler | pointer `$A612` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A7F3-$A8A9` | 183 | - | **code the tracer could not reach** - entity handler | pointer `$A7F3` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A94F-$A97F` | 49 | - | **code the tracer could not reach** - entity handler | pointer `$A94F` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A99B-$A9A3` | 9 | - | **code the tracer could not reach** - entity handler | pointer `$A99B` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$A9AB-$A9C7` | 29 | - | not referenced by any instruction; 7 x 4-byte records that read as (Y, tile, X, flag) sprite entries | not referenced by any instruction | | `$AA99-$AACE` | 54 | `ObjectOffsetPointerTable` ($AA99), `ObjectBoundValueTable` ($AAC1) | 10 x 4-byte records (a 16-bit big-endian pointer into the nametable pool plus a 16-bit offset); 14 x 8-bit bound values | `lda $AA99,x` at `$AAD5`, `sbc $AA9C,x` at `$AAD8`, `lda $AA99,x` at `$AADE`, `adc $AA9C,x` at `$AAE1`, `lda $AA9A,x` at `$AAE7`; `lda $AAC1,y` at `$AA59` (stored to `Zp11`) | | `$AAF8-$AC3D` | 326 | - | **code the tracer could not reach** - entity handler | pointers `$AAF8` and `$AB20` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$AC7B-$ADE1` | 359 | - | **code the tracer could not reach** - entity handler | pointers `$AC7B` and `$AD1A` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$AE86-$AF03` | 126 | - | **code the tracer could not reach** - entity handler | pointers `$AE86` and `$AEA8` loaded from `$9E57` at `$9E8B`/`$9E90`, dispatched by `jmp (Zp10)` at `$9ECC` | | `$AF3E-$AFAC` | 111 | `EntityInitByteTable` | 8 bytes of per-entity init data at `$AF3E`; `$AF46-$AFAC` is **code** | `lda $AF3E,y` at `$AF23` (copied to `$0318`); the code at `$AF46` and `$AF77` is reached by `jmp (Zp10)` at `$9ECC` with the pointers from `$9E57` | | `$B126-$B62B` | 1286 | `FieldBitmapData` ($B126), `PlayerSpriteTileTable` ($B1A6), `FieldSpriteObjectTable` ($B206), `FieldObjectOffsetTable` ($B606) | 128 bytes of `$FF`/`$00` bitmap; 24 x 4-byte player sprite tile quads; 128 x 8-byte records (two 4-byte sprite entries each: Y, tile, attribute, X); 38 x 8-bit field-object offsets | `lda $B126,y` at `$B0A5`; `lda $B1A6,y` at `$9F5C` (index = 4 x n + 0..3); `lda $B606,x` at `$AA63` | | `$B94D-$BE8C` | 1344 | - | not referenced by any instruction; a run of 16-byte nametable records (`$F2`, eleven `$77`, `$2F`, three `$FF`) | not referenced by any instruction | | `$BE9F-$BEA2` | 4 | - | not referenced by any instruction; decodes as two instructions (`LDA $31` / `BNE $BE9C`), the tail of the routine at `$BE8D` | not referenced by any instruction | | `$BFAE-$BFC2` | 21 | - | not referenced by any instruction; 10 x 2-byte note/frequency entries plus a terminator, in the sound-driver area | not referenced by any instruction | | `$BFE7-$BFF6` | 16 | `SoundVolumeTable` | 16 x 8-bit volume levels for the sound driver | `lda $BFE7,y` at `$BFCF` (index = the sound entry's level byte minus `$F0`), stored to the channel volume `ZpCB` | | `$C00E-$C015` | 8 | `ApuChannelMaskTable` | 8 x 8-bit APU enable masks (`$01`,`$02`,`$04`,`$08`,`$0E`,`$0D`,`$0B`,`$07`) | `ora $C00E,x` at `$BFF9` and `and $C012,x` at `$C008`, written to APUSTATUS | | `$C182-$C336` | 437 | - | not referenced by any instruction operand; an unused nametable page of (tile, attribute) byte pairs - the CDL capture marks all 437 bytes as data read at run time | not referenced by any instruction | | `$C3F0-$C4F8` | 265 | `NametablePageData` ($C3F0), `CopyrightTextRow` ($C4B6), `CopyrightTextRow2` ($C4CB), `FieldBackgroundTileRow` ($C4D9) | 198 bytes of raw nametable tile/attribute data; a 21-tile copyright line "©1983 1985 IREM CORP."; a 14-tile copyright line "©1985 NINTENDO"; a 32-tile row of field background tiles | `lda $C4B6,x` at `$C38D` (21 tiles to PPUDATA at nametable row 24); `lda $C4CB,x` at `$C3A1` (14 tiles); `lda $C4D9,x` at `$C3C2` (32 tiles, copied to `ZpA3` first); the page data at `$C3F0` is not the operand of any instruction - the CDL capture marks all 265 bytes as data read at run time, and the nametable writer at `$C364` copies 256 bytes through an indirect pointer (`Zp10`),`y` | | `$C507-$C542` | 60 | `ScoreboardHeaderText` ($C507), `NametableAttributeData` ($C523) | a 28-tile scoreboard header, " PLAYER 1UP" and "2UP" among spaces; 32 bytes of nametable attribute bytes (`$00`/`$55` palettes) | `lda $C507,x` at `$C4FB` (7 tiles to PPUDATA); `lda $C523,y` at `$C3B5` (32 attribute bytes to PPUDATA) | | `$C5AF-$C5CE` | 32 | `PlayerMovementDeltaTable` | 8 x 4-byte records (16-bit X delta, 16-bit Y delta) for the player animation | `adc $C5AF,y` at `$C588`, `adc $C5B0,y` at `$C590`, `adc $C5B1,y` at `$C597` (added to `Zp19`, `Zp17`, `Zp18`) | | `$C65B-$C75E` | 260 | `PlaySequenceTable` | 65 x 4-byte records; byte 1 of a record is a state/command code (`$10` normal, `$F1` special) and bytes 2-3 are data | `lda $C65F,y` at `$C61E` (byte 1 of the record) and `ora $C65B,y` at `$C632` (byte 0 of the record) | | `$CA6B-$CB36` | 204 | `TeamSelectionTextPool` | 10 `$FF`-terminated menu strings: `$CA6B` "SELECT YOUR OPPONENT" + arrow tiles `$2E`/`$2F`, `$CA82` "SKILL LEVEL" + arrow tile `$27`, `$CA8F` "HIGH SCHOOL TEAM", `$CAA1` "COLLEGE TEAM", `$CAAF` "PROFESSIONAL TEAM", `$CAC1` "PLAYOFF TEAM", `$CACF` "SORRY" + tile `$28` + "THE GAME IS OVER", `$CAF7` "GO TO THE LOCKER ROOM.", `$CB0F` "YOUR ARE ON THE WAY TO", `$CB27` "THE SUPER BOLD" + arrow tile `$27` | pointers to `$CA6B`, `$CA82`, `$CA8F`, `$CAA1`, `$CAAF`, `$CAC1`, `$CACF` built at `$C914`, `$C927`, `$C93A`, `$C94D`, `$C960`, `$C973`, `$C986`; `$CAF7`, `$CB0F` and `$CB27` built at `$93A7`, `$CBDB` and `$CBEE` | | `$CB83-$CBBB` | 57 | `AlternateSpritePatternTable` ($CB83), `TeamLevelNamePointerTable` ($CBA8) | 32 bytes of sprite-pattern data copied to the same zero-page buffer `$00A3-$00C2` as `SpritePatternTable`; 5 x 4-byte records (a 16-bit X position plus a 16-bit pointer to the team name string) | `lda $CB83,x` at `$C901`; `lda $CBA3,y` at `$CB68`; `lda $CBA8,y` at `$C9E0`, `lda $CBA9,y` at `$C9E5`, `lda $CBAA,y` at `$C9EA`, `lda $CBAB,y` at `$C9EF` (index = team level x 2) | | `$CC0E-$FFFF` | 13298 | - | not referenced by any instruction operand; `$CC0E-$CC23` is the **OAM DMA routine** (`STA $CC18` / `STY $2001` / `LDA $0700,Y` / `STA $2004` / `JMP $945F`), `$CC24-$FFF9` is 13 386 bytes of `$FF` padding, and `$FFFA-$FFFF` holds the vectors (NMI `$8471`, RESET `$8000`, IRQ `$84FF`) | not referenced by any instruction | ### Notes on the names - `TeamLevelPresetPairTable`, `TeamLevelStatTable` and `TeamLevelSpriteOffsetTable` are the three tables `SubC83C6` loads for the selected team level. The ROM does not say what the numbers mean - the first pair table is only ever written (`ZpBD`/`ZpBE` are never read back), the stat table is only ever written (`ZpF5`), and the offset table reaches the sprite X byte through `ZpF6` - so they are named for the role the code gives them rather than for an invented game statistic. - `LevelParameterByteTable` and `LevelPositionPairTable` are the two halves of the per-level data that `SubC99A7` loads; the second half is indexed by `level AND $0E`, which can reach past the end of the block, so only the first five pairs are ever in range. - `SpritePatternTable` and `AlternateSpritePatternTable` are two different 32-byte patterns that are copied to the same zero-page buffer (`$00A3-$00C2`) at different points of the game (`$88CA` and `$C901`). - `FieldSpriteObjectTable` records are 8 bytes each and read as two 4-byte sprite entries; byte 2 is the palette attribute (`$00`/`$40`) and byte 3 the X column, but the order of the first two bytes (a Y-like value and the tile index) is not fixed by this dump. - `ObjectOffsetPointerTable` holds a 16-bit pointer into the nametable data pool in its first two bytes and a 16-bit offset in its second two; the code adds and subtracts the offset from the pointer at `$AAD5`-`$AAE7`. ## Address-derived entry points 115 of the 168 `jsr`/`jmp` entry points now carry a semantic name. **53 remain address-derived**, and the dump does not reveal what they are for. ### The sound engine's voice set-up (45) `SubCBFC3`, `SubCBFD2`, `SubCC006`, `SubCC4F9`, `SubCC543`, `SubCC5F3`, `SubCC75F`, `SubCC82B`, `SubCC85A`, `SubCCA15`, `SubCCA38`, `SubCCA59`, `SubC9FA9`, `SubC9E04`, `SubC9A00`, `SubC998B`, `SubC98F4`, `SubC96E8`, `SubC968F`, `SubC9633`, `SubC95B7`, `SubC9465`, `SubC93EA`, `SubC929E`, `SubC9298`, `SubC92AD`, `SubC92B0`, `SubC9109`, `SubC90D2`, `SubC903C`, `SubC8F00`, `SubC8EFC`, `SubC8D73`, `SubC8A95`, `SubC8953`, `SubC88FB`, `SubC88C8`, `SubC888D`, `SubC85B0`, `SubC8549`, `SubC853B`, `SubC84F3`, `SubC8456`, `SubC8444`, `SubC815A` The sound engine runs four voices, and each voice is a small state machine whose note pointer lives in `ZpD7`/`ZpDB` and `ZpDA`/`ZpDE`. The entries that start a voice (`StartSoundVoiceOne` … `StartSoundVoiceThirteen`) name the thirteen note lists the game uses; the residue here is the code that decides *which* of them a given event plays, and the tables that hold the per-channel register values, which the dump does not tie to a named channel or effect. ### The field, the ball and the players (8) `SubCA318`, `SubCA905`, `SubCA9A4`, `SubCAACF`, `SubCAAF3`, `SubCAC3E`, `SubCAF04`, `SubCAF21` These are the short helpers that prepare one field of the play state - the scroll offset, the ball's position, a player's screen position - for the routine that uses it. The player's records live at `$0300` and the ball's position in `Zp4D`/`Zp4E`, so the fields are known, but which object each helper belongs to is not: the same helpers serve both teams and the dump does not separate them. ## Open work - **Pass 1** - run `nesdis.py` over `prg.bin` to produce the code/data split. The tracer reads the vectors from the last six bytes of the PRG image, so the split seeds correctly. - **Pass 1** must emit the canonical audit comment `; CPU:$C123 PRG:0123 AD 21 03` at column 35 for every instruction. - **Pass 2** - replace the address-derived `Label_XXXX` names and the raw `$XXXX` call operands. - **Pass 3** - semantic zero-page aliases (applied only at the sites where their role is proven) and named data tables. - **Promotion** to `NROM//` once Pass 3 is done, as `git mv`. ## Files | File | Purpose | |------|---------| | `prg.s` | Pass 0 PRG include (replaced by the Pass 1 disassembly) | | `header.s` | iNES header include | | `chr.s` | CHR include | | `prg.bin` | 32768 bytes (32 KB) PRG image | | `chr.bin` | 8192 bytes (8 KB) CHR image | | `rom.nes` | byte-identical copy of the original ROM | | `linker.cfg` | HEADER / PRG / CHR memory areas | | `symbols.inc` | NES hardware register names | | `locals.inc` | zero-page aliases (empty at Pass 0) | | `Makefile` | build and byte-identity check |