# Stack-Up (JU) ## Status **Pass 3 complete; promoted.** `prg.s` is a traced disassembly with all address-derived labels replaced, all `jsr`/`jmp` operands symbolic, hardware registers named via `symbols.inc`, and `apply_symbols.py` reporting 0 residue. Code coverage: 10,586 / 32,768 bytes (32.3%). `make` assembles and verifies byte-identical to `rom.nes`. Data tables: all 40 data blocks in the PRG are interpreted in the [Pass 3 data-table inventory](#pass-3-data-table-inventory) below. 31 of them carry a name (39 labels in all); the 9 that carry none are recorded as unreferenced data or as 6502 code the tracer could not reach. The 13 `.byte` rows whose audit comment carried a PRG offset computed with the wrong base were repaired to the canonical `; CPU:$XXXX PRG:XXXX AA BB` form; the bytes themselves are untouched. ## 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 `$8100` (`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 | |---------|---------| | `$810A` | `Reset_OnNonnegative` (falls through) | | `$811D` | `Reset_OnNonzero` (falls through) | | `$812B` | `Reset_Loop` (falls through) | | `$8266` | `Sub_8266` | | `$82BA` | `Sub_82BA` | | `$8154` | `Reset_OnZero` (falls through) | | `$8271` | `Sub_8271` | | `$8457` | `Sub_8457` | | `$81E7` | `Sub_81E7` | | `$815F` | `Sub_815F` | **NMI** is at `$81AD` (`NmiHandler`). It is the per-frame handler; what it calls: | Address | Routine | |---------|---------| | `$82C5` | `Sub_82C5` | | `$8413` | `Sub_8413` | | `$84CF` | `Sub_84CF` | | `$83BA` | `Sub_83BA` | **IRQ** is at `$81E6` (`IrqHandler`) - a different address from RESET. ## ROM | Property | Value | |----------|-------| | Format | iNES | | Mapper | 0 (NROM) | | PRG | 32 KB | | CHR | 8 KB | | Mirroring | Horizontal | | NMI vector | $81AD | | RESET vector | $8100 | | IRQ vector | $81E6 | ## Power-on flow RESET enters at `$8100`: cld ; CPU:$8100 PRG:0100 D8 sei ; CPU:$8101 PRG:0101 78 ldx #$00 ; CPU:$8102 PRG:0102 A2 00 stx PPUCTRL ; CPU:$8104 PRG:0104 8E 00 20 stx PPUMASK ; CPU:$8107 PRG:0107 8E 01 20 lda PPUSTATUS ; CPU:$810A PRG:010A AD 02 20 bpl Reset_OnNonnegative ; CPU:$810D PRG:010D 10 FB dex ; CPU:$810F PRG:010F CA txs ; CPU:$8110 PRG:0110 9A ldx Zp2F ; CPU:$8111 PRG:0111 A6 2F ldy #$07 ; CPU:$8113 PRG:0113 A0 07 sty Zp01 ; CPU:$8115 PRG:0115 84 01 NMI handler at `$81AD`: pha ; CPU:$81AD PRG:01AD 48 txa ; CPU:$81AE PRG:01AE 8A pha ; CPU:$81AF PRG:01AF 48 tya ; CPU:$81B0 PRG:01B0 98 pha ; CPU:$81B1 PRG:01B1 48 lda #$00 ; CPU:$81B2 PRG:01B2 A9 00 sta OAMADDR ; CPU:$81B4 PRG:01B4 8D 03 20 lda #$02 ; CPU:$81B7 PRG:01B7 A9 02 ## Pass 3 data-table inventory Every data block in the PRG is listed below. The block boundaries are the tracer's (`; ---- data $XXXX-$YYYY` markers in `prg.s`); where a block holds more than one structure the sub-labels in `prg.s` mark the split. Stack-Up is a Q*bert-style maze game: the player pushes blocks around a board and they pile up. Most of the data below is therefore tile indices, sprite attributes and per-board-column numbers. | Address | Size | Name | Structure | Read by | |---------|------|------|-----------|---------| | `$8000-$80FF` | 256 | `CopyrightText` | 16 lines of 16 ASCII characters - the staff credits: "Programed by T.NAKAMURA", "6/24 is my birthday.", "1985/6/24 TOMOYO chan", "ROBOT 1", "1985/6/24". Spaces are the padding; the text is the only printable content | **no instruction in this dump reads it** and no 16-bit pointer to `$8000` exists in the PRG. Unreferenced data, ROM offset `$0000` - the block sits in front of the reset stub at `$8100` and is the only ASCII in the ROM | | `$82EA-$8309` | 32 | `BlockShapePointerTable` | 16 little-endian 16-bit pointers into the shape data at `$B574`, `$B598`, `$B5AC`, `$B598`, `$B5C0`, `$B5D4`, `$B5E8`, `$B608`, `$B61C`, `$B640`, `$B654`, `$B65C`, `$B664`, `$B66C`, `$B674`, `$B698` - one pointer per block shape | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$02EA` | | `$8827-$8875` | 79 | *(unreferenced)* | 39 little-endian 16-bit values drawn from `$0000`, `$0030`, `$0050`, `$0070`, `$0090`, `$0110`, `$0190` - every non-zero value is a multiple of 16, so these are screen positions or row offsets rather than addresses. The layout is not established | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$0827` | | `$8BFD-$8C04` | 8 | `ColumnStackHeightTable` | 8 single-byte values (`$05`,`$02`,`$01`,`$06`,`$03`,`$01`,`$02`,`$04`), one per board column | `lda $8BFD,x` at `$8BE9`; X is the column index (7 down to 0, chosen by the bit tests at `$8BD0`/`$8BD5`), and the value is passed to the routine at `$B1DE` | | `$8C3A-$8C69` | 48 | `BlockShapeTileListTable` | 6 lists of 5 tile indices, each list terminated by `$FF`: (`$0A`,`$12`,`$1A`,`$22`,`$2A`), (`$0B`,`$13`,`$1B`,`$23`,`$2B`), (`$0D`,`$15`,`$1D`,`$25`,`$2D`), (`$0E`,`$16`,`$1E`,`$26`,`$2E`), (`$0A`,`$0B`,`$0C`,`$0D`,`$0E`), (`$12`,`$13`,`$14`,`$15`,`$16`), (`$22`..`$26`), (`$2A`..`$2E`) - the tiles that make up one of the six block shapes | `ldx $8C3A,y` at `$8C17`; the list is walked with Y and `$FF` ends it, the tile index then selects the board cell in `$0400` | | `$8FCF-$8FE3` | 21 | `BlockShiftParameterTable` | two groups of 5 byte pairs, each group terminated by `$AA`: (`$00`,`$D0`), (`$C8`,`$60`), (`$80`,`$20`), (`$C8`,`$98`), (`$C4`,`$82`) and (`$A5`,`$2D`), (`$D0`,`$05`), (`$20`,`$76`), (`$88`,`$85`), (`$3C`,`$60`). The two fields are read into separate zero-page cells (`Zp1A` and `Zp3E`); their units are not established | `lda $8FCF,y` at `$8FAC` and `$8FB6`, the pair loop ending on the `$AA` marker | | `$9017-$9056` | 64 | `GameStateParameterTable` | two 32-byte parameter vectors. The first 32 bytes are copied into `$0300-$031F`, the second 32 into `$0320-$033F`; the code selects which half to copy by the state of `GameState` (`$49`) and `BoardState` (`$40`) | `lda $9017,y` at `$8FFA` -> `$0300,x` and `lda $9017,y` at `$900C` -> `$0320,x`, both loops running Y and X from 15 down to 0 | | `$9057-$9066` | 16 | `GameStateParameterTableB` | the remainder of the 80-byte parameter block | as above (only the first 64 bytes are copied) | | `$9090-$9317` | 648 | *(unreferenced - unreachable code)* | a coherent 6502 routine: `JSR $93BA`, `LDX $4A`, `LDA $0317,x`, `BNE`, `STA $0312,x`, `LDA #$01`, `JMP`, `LDA ($14),y` - the routine that places a block on the board | **no instruction operand lands in this block**, so the tracer never reached it. The bytes decode as instructions throughout (`$9090` is 3 bytes of padding in front of the entry at `$9093`). Unreached code, ROM offset `$1090` | | `$9344-$9350` | 13 | `BlockColorIndexTable` | 13 colour-index bytes (`$13`,`$0B`,`$03`,`$13`,`$1B`,`$00`,`$00`,`$00`,`$0B`,`$03`,`$13`,`$1B`,`$2B`) | `lda $9344,y` at `$9B22` and `$9BFC`; the value is written to `$0345` and handed to `Sub_B2A1`, which turns it into the sprite attribute actually used | | `$9351-$9358` | 8 | `BlockPaletteLookupTable` | 8 palette bytes (`$27`,`$23`,`$2B`,`$2F`,`$00`,`$00`,`$00`,`$00`) | `lda $9351,x` at `$9B39` and `$9C25`, indexed by the low 3 bits of the colour index at `$0341` | | `$943F-$9474` | 54 | `LevelBlockLayoutTable` | 27 little-endian 16-bit pointers to the per-level layouts at `$9475`, `$94B4`, `$94FF`, `$954A`, `$9595`, `$95E0`, `$9626`, `$966C`, `$96AE`, `$96F0`, `$973B`, `$9786`, `$97D1`, `$981C`, `$986F`, `$98C2`, `$9915`, `$96F0`, `$973B`, `$9786`, `$97D1`, `$981C`, `$986F`, `$98C2`, `$9915`, `$9968`, `$99B3` (several levels share a layout) | `lda $943F,y` at `$9365` and `lda $9440,y` at `$936A`, with Y = 2 x the level number at `$030D,x`; the pointer becomes `BlockPtrLo`/`BlockPtrHi` and the layout is then read through it | | `$9475-$99FD` | 1417 | `LevelBlockLayoutData` | the level layouts themselves: runs of (tile index, sprite attribute) pairs - e.g. `($00,$00)`,`($03,$00)`,`($FF,$00)`,`($FE,$00)` - ended by the `$AA` marker | `lda (BlockPtrLo),y` at `$9372`; the `$AA` test at `$9374` ends the layout | | `$9A2C-$9A96` | 107 | `BlockColorTable` | groups of colour values, each group terminated by `$FF`: `$00`; `$01`,`$02`,`$03`,`$03`,`$03`,`$04`; `$08`,`$05`,`$06`,`$07`,`$07`,`$07`,`$08`; `$10`,`$09`,`$0A`,`$0B`,`$0B`,`$0B`,`$0C`; `$18`..`$10`; then two- and four-value groups up to `$65` | `lda $9A2C,y` at `$9A1E` walks the groups (the `$FF` test at `$9A21` ends a group) and `lda $9A2C,y` at `$9A15` copies them into `$0305`/`$0306` | | `$9AB4-$9AC7` | 20 | *(unreferenced)* | 20 bytes, 18 of them `$00` and two `$04` at `$9ABE` | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$1AB4` | | `$9C52-$9C5E` | 13 | `BlockSizeTable` | 12 size values (`$01`,`$01`,`$01`,`$03`,`$03`,`$03`,`$02`,`$02`,`$02`,`$04`,`$04`,`$04`) terminated by `$FF` - the size in board cells of each block type | `lda $9C52,x` at `$9BE8` and `$9BF1`; the `$FF` test at `$9BEB` ends the list | | `$9CC8-$9CE7` | 32 | `BoardTileIndexTable` | 32 tile indices, one per board position (`$09`,`$09`,`$11`,`$19`,`$21`,`$29`,`$29`,`$00`,`$0F`,...) | `lda $9CC8,y` at `$9C7F`, with Y = `$0618` masked to 5 bits - the tile the next board cell must show | | `$9D08-$9D2F` | 40 | *(unreferenced - unreachable code)* | 6502 code: `DEC $0339`, `BNE`, `LDA #$00`, `STA $0321`, `LDA #$28`, `STA $0333`, `JMP $830A`, then `INC $0707`, `LDA $2F`, `AND #$04` | **no instruction operand lands in this block.** Unreached code, ROM offset `$1D08` | | `$9D30-$9D3C` | 13 | *(unreferenced)* | 13 bytes, 9 of them `$00`, then `$0A`,`$09`,`$0C`,`$0B`,`$0F`,`$10`,`$0D`,`$0E` | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$1D30` | | `$9E37-$9E40` | 10 | `SoundParameterTable` | 10 bytes (`$01`,`$00`,`$16`,`$00`,`$00`,`$4D`,`$44`,`$01`,`$80`,`$80`) | `lda $9E37,y` at `$9E2D` copies the ten bytes into `$0360-$0369` | | `$9E43-$9E56` | 20 | *(unreferenced)* | 20 bytes, all `$00` | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$1E43` | | `$A16E-$A17D` | 16 | `SpriteVerticalOffsetTable` | two identical rows of 7 vertical offsets in pixels (`$38`,`$50`,`$68`,`$80`,`$98`,`$B0`,`$C8`) followed by a `$00` terminator | `lda $A16E,y` at `$A1F8`; the value becomes the sprite's Y position at `$0388`/`$0398` | | `$A17E-$A18D` | 16 | `SpriteHorizontalOffsetTable` | a row of 9 horizontal offsets in pixels (`$10`,`$20`,`$40`,`$60`,`$80`,`$A0`,`$C0`,`$E0`) plus `$00`, and then `$00`,`$01`,`$FC` | `lda $A17E,y` at `$A207`; the value becomes the sprite's X position at `$0389`/`$0399` | | `$A186-$A18E` | 9 | `SpriteAttributeOffsetTable` | the remaining bytes `$00`,`$01`,`$FC`,`$05`,`$02`,`$00`,`$2E`,`$01` | `lda $A186,y`, `lda $A187,y` and `lda $A188,y` at `$A21F`, `$A225` and `$A22B` | | `$A339-$A33D` | 5 | `SpriteCenterOffsetTable` | 5 horizontal offsets in pixels (`$40`,`$60`,`$80`,`$A0`,`$C0`) | `lda $A339,y` at `$A30B` -> `$0388`/`$0398` | | `$A3CB-$A3D6` | 12 | `SpritePositionTable` | a row of 4 vertical offsets (`$38`,`$50`,`$68`,`$80`) + `$00`, then `$01`,`$02`, then a row of 4 horizontal offsets (`$50`,`$70`,`$90`,`$B0`) + `$00` | `lda $A3CB,y` at `$A34E` and `lda $A3CF,y` at `$A35D` -> the sprite's X and Y positions | | `$A4A0-$A4E9` | 74 | `BlockFallScriptData` | a byte-code: `$FE`/`$FF`/`$00`/`$01` are plain values, `$AA`, `$AB` and `$AC` are the three control opcodes (they are tested at `$A401`, `$A405` and `$A409`), and the `$AE`/`$AD`/`$AC` bytes act as per-entry markers | `lda $A4A0,y` at `$A3FE`, walked with Y as the block's animation step counter | | `$A697-$A716` | 128 | `SpriteTileAttributeTable` (pointer half) | 64 little-endian 16-bit pointers into the sprite data that follows ($A6E3, $A6EF, $A6FB, $A707, $A713, $A71F, $A72B, $A737, $A743, $A74F, $A75B, $A75F, $A763, $A767, $A76B, $A76F, ...) | `lda $A697,y` at `$A68C` and `lda $A698,y` at `$A691`, with Y = 2 x the tile index; the pointer becomes `BlockPtrLo`/`BlockPtrHi` | | `$A717-$A8E2` | 460 | `SpriteTileAttributeData` | the sprite data the pointers address: runs of (tile index, sprite attribute) byte pairs - the attribute bytes `$20`-`$24` are NES palette numbers, so each pair says "draw this tile in that palette" | `lda $A8D3,x` / `lda $A8D4,x` at `$A556`/`$A55B` and `$A593`/`$A598`, and `lda $A853,x` / `lda $A854,x` at `$A568`/`$A56D` and `$A5BA`/`$A5BF`, read as VRAM addresses | | `$AA86-$AAA5` | 32 | `DirectionIndexTable` | 16 index values that reverse the order inside each group of 4 (`$03`,`$02`,`$01`,`$00`, `$07`,`$06`,`$05`,`$04`, `$0B`,`$0A`,`$09`,`$08`, `$0F`,`$0E`,`$0D`,`$0C`) followed by 16 identity values `$01`..`$10` - the lookup used to turn a direction into the matching board index | `lda $AA86,x` at `$AA7D`, indexed by the running counter `Zp52` | | `$AABA-$AABE` | 5 | *(unreferenced)* | 5 bytes (`$22`,`$FD`,`$24`,`$FE`,`$24`) | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$2ABA` | | `$AC98-$ACD7` | 64 | `SpriteScreenOffsetTable` | a run of 6 X offsets in pixels (`$00`,`$04`,`$08`,`$0C`,`$10`,`$14`), a run of Y offsets (`$71`,`$70`,`$72`,`$03`), and then 30 sprite-attribute bytes (`$B0`/`$2A`,`$B1`/`$2A`,...,`$30`/`$2B`,`$31`/`$2B`,...) that give each sprite its palette | `lda $AC9B,y` at `$AC35`, `lda $AC9A,y` at `$AC3B`, `lda $ACD2,y` at `$AC4F`, `lda $AC98,y` at `$AC62`, `lda $AC9D,x` at `$AC8B` and `lda $ACA0,x` at `$AC91` | | `$AD1F-$AD3C` | 30 | `RequiredBlockCountTable` | 6 records of 5 bytes; four bytes of `$00` and then the record number - record 1 asks for 1 block, record 2 for 2, and so on | `lda $AD1F,y` at `$AD05`, copying the 30 bytes into `$0520-$053D` | | `$AD90-$ADAA` | 27 | `ThresholdValueTable` | 27 threshold bytes (`$00`,`$03`,`$03`,`$0A`,`$0A`,`$0A`,`$0F` x4, `$00` x6, `$0F`,`$19` x9,`$28`) | `cmp $AD90,y` at `$AD7C`, comparing the counter at `$0566` against the threshold | | `$AF72-$B031` | 192 | `BoardTileMapData` | six rows of 32 tile indices, `$FF` marking an empty cell; the non-`$FF` cells are `$02`,`$03`,`$01` at row 2 columns 3-5, `$05`,`$04`,`$06` at row 3 columns 3-5, and a few `$00` runs | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$2F72` | | `$B33A-$B379` | 64 | `SpriteGraphicPointerTable` | 32 little-endian 16-bit pointers to the sprite run-length data that follows ($B492, $B37A, $B387, $B394, $B49F, $B3A1, $B3AE, $B3BB, $B4AC, $B3C8, $B3DA, $B3EC, $B4BE, $B3FE, $B410, $B422, $B4D0, $B434, $B441, $B44E, $B4DD, $B45B, $B468, $B475, $B4AC, $B3C8, $B3DA, $B3EC, $B4BE, $B3FE, $B410, $B422) | `lda $B33A,y` at `$B302` and `ldx $B33B,y` at `$B305`; the pointer becomes `BlockPtrLo`/`BlockPtrHi` | | `$B37A-$B4E9` | 368 | `SpriteGraphicData` | the sprite graphics in a compressed form: groups of (tile index, attribute) bytes started by a `$23` separator and ended by `$FF` - e.g. `$23 $C9 $03 $6F $9F $AF $23 $F1 $03 $60 $90 $A0 $FF` | `lda $B482,y` at `$B31C` and `lda $B483,y` at `$B321` read a second pointer set ($B492, $B49F, $B4AC, $B4BE) that lands in the same data | | `$B542-$B549` | 8 | `DirectionBitMaskTable` | the eight single-bit masks `$01`,`$02`,`$04`,`$08`,`$10`,`$20`,`$40`,`$80`, one per direction | `lda $B542,x` at `$B4FC` and `$B510`, indexed by the direction held in `Zp11`; the mask is OR-ed into the state byte `Zp61` | | `$B564-$B573` | 16 | `BlockShapeParameterTable` | two rows of 8 bytes: `$0A`,`$0B`,`$0D`,`$0E`,`$0A`,`$12`,`$22`,`$2A` and `$08`,`$08`,`$08`,`$08`,`$01`,`$01`,`$01`,`$01` | `ldy $B564,x` at `$B551` and `lda $B56C,x` at `$B54C`, indexed by the block number | | `$B574-$D57C` | 8,009 | `BlockShapeDefinitionData` | the block-shape and sprite data the `$82EA` pointer table addresses: NUL-terminated lists of tile indices (`$B574` = `$3F $00 $20 $0F $31 $1C $0C $0F $24 $28 $1A $0F $2A $21 $1A $0F`), 16-bit pointers embedded in the blob (`$B6B8` = `$B6C2`, `$B6BA` = `$B70F`, `$B6BC` = `$B75C`), and (tile, attribute) sprite runs | `lda $B6BC,y` at `$8554` and `lda $B6BD,y` at `$8559` read the embedded pointer table; the shape lists themselves are reached through `BlockShapePointerTable` at `$82EA`, which no instruction in this dump uses | | `$D58B-$F393` | 7,689 | `LevelSpriteGraphicData` | a long run of sprite and level data in the same compressed form as `$B37A`: `$23`-separated groups of (tile, attribute) bytes closed by `$FF`, mixed with plain tile runs | `lda $F300,y` at `$F4AA` and `$F571`, `lda $F301,y` at `$F4A2` and `$F569` and `lda $F374,y` at `$F47C` read into the last part of the block; the bulk of it is reached through pointers built at run time | | `$F3F4-$F3FF` | 12 | *(padding)* | 12 bytes of `$FF` | none - fill in front of the noise-effect records | | `$F400-$F40B` | 12 | `NoiseEffectTable` | 4 records of 3 bytes - (noise enable, period, length): (`$10`,`$00`,`$18`), (`$10`,`$01`,`$18`), (`$00`,`$01`,`$88`), (`$02`,`$02`,`$40`) | `lda $F400,y` at `$F503`, `lda $F401,y` at `$F509` and `lda $F402,y` at `$F50F` - the three bytes go to `$400C`, `$400E` and `$400F` | | `$F40C-$F411` | 6 | `NoiseEffectTable` (tail) | the remaining 6 bytes (`$00`,`$0A`,`$C0`,`$04`,`$07`,`$40`) | not read by the noise routine above | | `$F69B-$F6A6` | 12 | *(unreferenced)* | 12 bytes (`$82`,`$6A`,`$02`,`$00`,`$83`,`$6E`,`$02`,`$6E`,`$02`,`$6E`,`$02`,`$00`) - the note/length bytes of one sound effect | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$369B` | | `$F6E2-$F6FB` | 26 | *(unreferenced)* | 26 bytes (`$83`,`$12`,`$02`,`$6E`,`$02`,`$12`, ... `$00`) - the same note/length encoding, a longer sequence | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$36E2` | | `$F733-$F73A` | 8 | `Pulse2EnvelopeTable` | 4 records of 2 bytes: (`$3A`,`$B9`), (`$B8`,`$F9`), (`$34`,`$BD`), (`$56`,`$20`) | `lda $F733,y` at `$F783`, with Y = `$07E2` masked to 2 bits; the byte goes to the pulse-2 control register `$4004` | | `$F74C-$F757` | 12 | `Pulse2SweepTable` | 6 bytes of sweep settings (`$83`,`$DC`,`$B5`,`$9A`,`$06`,`$08`) followed by `$0E`,`$00`,`$BD`,`$7F`,`$FF`,`$01` | `lda $F74C,y` at `$F7EA` -> `$4005` (pulse-2 sweep) and `lda $F750,y` at `$F7F0` -> the note period | | `$F818-$F827` | 16 | `Pulse2NoteTable` | 16 bytes of pulse-2 note data (`$83`,`$AB`,`$93`,`$9A`,`$03`,`$06`,`$03`,`$00`,`$F6`,`$7F`,`$C8`,`$00`,`$09`,`$7F`,`$32`,`$38`) | `lda $F818,y` at `$F7F6` -> `$4005` and `lda $F81C,y` at `$F7FC` -> the note period | | `$F88F-$F892` | 4 | *(unreferenced)* | 4 bytes (`$07`,`$7F`,`$34`,`$38`) | **no instruction in this dump reads it.** Unreferenced data, ROM offset `$388F` | | `$F989-$FFF6` | 1,646 | *(unreferenced - unreachable code)* | a 6502 dispatcher: a table of little-endian code addresses (`$FA51`, `$FADE`, `$FAE0`, `$FA59`, ...) followed by the routines they select - `LDA ($xx),y`, `STA ($xx),y`, `JMP` and `RTI` sequences | **no instruction operand lands in this block.** Unreached code, ROM offset `$3989` | | `$FFF7-$FFF9` | 3 | *(unreferenced)* | 3 bytes of `$FF` | none - fill in front of the vectors | | `$FFFA-$FFFF` | 6 | `CpuVectorTable` | 3 little-endian 16-bit vectors: NMI `$81AD`, RESET `$8100`, IRQ `$81E6` | the CPU reads them out of the vector table | ## Build ``` Byte-identical ROM verified. ``` --- ## Entry-point naming (2026-10-21) Every `jsr`/`jmp` target that carried an address-derived `Sub_xxxx` name was reviewed against the routine it points at, the code that calls it and the RAM fields it touches. | | count | |---|---| | Address-derived entry points before | 188 | | Entry points now carrying a semantic name | **101** | | Entry points still address-derived | **87** | The names now in `prg.s` cover: * **PPU and VRAM** — `SetVramBase20`, `SetVramBase28`, `SetVramAddressFromTable`, `SetVramWritePointer`, `SetAttributeWritePointer`, `ResetVramWritePointer`, `AdvanceVramRow`, `RetreatVramRow`, `SplitVramAddress`, `WriteVramByte`, `WriteAttributeByte`, `SetAttributeIndex`, `SetTextWritePointer`. * **Sprites and the board** — `ClearSpriteBuffer`, `ClearSpriteOffsets`, `InitScreenAndSprites`, `UpdateGame`, `RunGameUpdate`, `UpdateGameFrame`, `UpdateGameAfterNmi`, `SetDrawOrigin`, `ResetDrawOrigin`, `GetBoardDimensions`, `SetBoardLevelParams`, `ResetBoardState`, `ResetBoardAddress`, `DrawPlayerSprite`, `DrawBlockSprite`, `DrawBoardCellSprite`, `GetSpriteAddress`, `GetSpriteAddressAlt`, `GetSpriteDataPointer`, `StartSpriteList`, `SetSpritePalette`, `SetBackgroundPalette`, `SetPaletteAfterBlock`, `SetBgPaletteSlot1`, `SetBgPaletteSlot2`, `SetBgPaletteSlot3`, `SetBgPaletteSlot4`, `GetTextRow`. * **Blocks** — `GetBlockShapePointer`, `GetBlockShapeIndex`, `GetLevelLayoutPointer`, `SetBlockFlags`, `GetBlockRow`, `GetBlockSlotFromAddress`, `ReadBlockColour`, `ReadNeighbourBlockColour`, `WriteBlockAttribute`, `SetBlockTileIndex`, `SpawnBlock`, `SpawnBlockAlt`, `UpdateBlockTimer`, `TickBlockTimer`, `UpdateFallingBlocks`, `RunFallingBlockAnimation`, `RunBlockFallScript`, `ClearBlockType`, `ClearBlockPairFlags`, `LinkBlocks`, `ResetFallingBlock`, `ResetBlockTimer`, `UpdateBlockHeight`, `StartBlockFall`, `TickBlockFallTimer`, `TickBlockCountdown`, `TickGameCounter`, `TickSoundCounter`, `UpdateEffects`, `GetOppositeDirection`, `ClearDirectionState`, `GetDirectionFlags`, `SetPlayerIndex`. * **Sound** — `UpdateSoundEngine`, `StartSoundEffect`, `PlaySoundEffectNote`, `PlayNextSoundNote`, `UpdateSoundDuration`, `IsSoundPlaying`, `UpdateSoundVoice`, `UpdateSoundVoiceAlt`, `UpdateSoundVoiceAlt2`, `StartSoundSequence`, `StartSoundSequenceAlt`. **Residue — 87 entry points remain address-derived.** Most of them are the fragments of the game's sound engine - the note tables it walks, the per-voice dispatchers and the register writes it makes - and the rest are the one-instruction helpers of the block and sprite state machines. The dump does not reveal a role that would distinguish them from their neighbours, so they keep their address-derived names. They are `Sub_81E7`, `Sub_83C8`, `Sub_83F0`, `Sub_8457`, `Sub_850A`, `Sub_85F5`, `Sub_8981`, `Sub_8E70`, `Sub_9067`, `Sub_9318`, `Sub_931D`, `Sub_9A97`, `Sub_9B88`, `Sub_9C5F`, `Sub_9D3D`, `Sub_9E27`, `Sub_9E58`, `Sub_A18F`, `Sub_A54F`, `Sub_A58B`, `Sub_A8E3`, `Sub_AA44`, `Sub_AABF`, `Sub_ABF3`, `Sub_ACFD`, `Sub_AD3D`, `Sub_ADAB`, `Sub_AE0F`, `Sub_AE81`, `Sub_AEAB`, `Sub_AEDC`, `Sub_AF17`, `Sub_AF27`, `Sub_AF34`, `Sub_AF67`, `Sub_B10C`, `Sub_B148`, `Sub_B1E7`, `Sub_B257`, `Sub_B26F`, `Sub_B273`, `Sub_B278`, `Sub_B27C`, `Sub_B280`, `Sub_B284`, `Sub_B288`, `Sub_B28C`, `Sub_B290`, `Sub_B294`, `Sub_B299`, `Sub_B2A1`, `Sub_B2A5`, `Sub_B2A9`, `Sub_B2B1`, `Sub_B2B5`, `Sub_B2BA`, `Sub_B2BE`, `Sub_B2C2`, `Sub_B2C6`, `Sub_B2CA`, `Sub_B2CE`, `Sub_B2ED`, `Sub_B326`, `Sub_B4EA`, `Sub_B54A`, `Sub_F394`, `Sub_F398`, `Sub_F3A0`, `Sub_F3E7`, `Sub_F416`, `Sub_F443`, `Sub_F473`, `Sub_F487`, `Sub_F4D1`, `Sub_F518`, `Sub_F647`, `Sub_F6A7`, `Sub_F714`, `Sub_F73B`, `Sub_F7C5`, `Sub_F7FF`, `Sub_F85C`, `Sub_F8CB`, `Sub_F944`, `Sub_F94D`, `Sub_F95E`, `Sub_FFF7`.