# Tag Team Wrestling (U) ## 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: 17,170 / 32,768 bytes (52.4%). `make` assembles and verifies byte-identical to `rom.nes`. Every one of the 48 data blocks in the PRG is now interpreted and listed in the data-table inventory below: 41 blocks are named and explained, 6 are recorded as unreferenced or unreached, and the one remaining block is the interrupt vector area. The audit trail's PRG offsets, which the Pass 1 emitter had numbered from `$C000` for the first twelve data blocks, now agree with the `$8000` base the rest of the file uses. ## 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 `$FD43` (`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 | |---------|---------| | `$FD4D` | `Reset_OnNonnegative` (falls through) | | `$FD52` | `Reset_OnNonnegative2` (falls through) | | `$FD9C` | `ResetTileScript` | | `$A9F1` | `InitRingGame` | | `$FDC8` | `Reset_OnZero` | | `$FDA4` | `ReadNametableTile` | | `$FD85` | `DispatchGameMode` (falls through) | | `$FDE3` | `SetBasePalettesAlt` | | `$AA1D` | `CheckRingGameInit` | | `$FF53` | `SetVramAddressAlt` | | `$FDB2` | `Reset_OnNonzero` (falls through) | | `$FDC8` | `Reset_OnZero` | | `$A9F4` | `InitRingGameAlt` | | `$FE0D` | `SetPaletteBaseAlt` | | `$FE0D` | `SetPaletteBaseAlt` | | `$FDF1` | `SetVramAddress2000Alt` | | `$9BF3` | `ClearRingEntrance` | | `$AA7C` | `ReturnImmediately` | **NMI** is at `$FFCD` (`NmiHandler`). It is the per-frame handler; what it calls: | Address | Routine | |---------|---------| | `$A9F7` | `UpdateRingGame` | **IRQ** is at `$FD43` (`Reset`) - the same address as RESET, so the IRQ vector reaches the reset path. ## ROM | Property | Value | |----------|-------| | Format | iNES | | Mapper | 0 (NROM) | | PRG | 32 KB | | CHR | 8 KB | | Mirroring | Horizontal | | NMI vector | $FFCD | | RESET vector | $FD43 | | IRQ vector | $FD43 | ## Power-on flow RESET enters at `$FD43`: sei ; CPU:$FD43 PRG:7D43 78 cld ; CPU:$FD44 PRG:7D44 D8 lda #$00 ; CPU:$FD45 PRG:7D45 A9 00 sta PPUCTRL ; CPU:$FD47 PRG:7D47 8D 00 20 sta PPUMASK ; CPU:$FD4A PRG:7D4A 8D 01 20 lda PPUSTATUS ; CPU:$FD4D PRG:7D4D AD 02 20 bpl Reset_OnNonnegative ; CPU:$FD50 PRG:7D50 10 FB lda PPUSTATUS ; CPU:$FD52 PRG:7D52 AD 02 20 bpl Reset_OnNonnegative2 ; CPU:$FD55 PRG:7D55 10 FB lda #$00 ; CPU:$FD57 PRG:7D57 A9 00 sta Zp0F ; CPU:$FD59 PRG:7D59 85 0F sta Zp10 ; CPU:$FD5B PRG:7D5B 85 10 NMI handler at `$FFCD`: pha ; CPU:$FFCD PRG:7FCD 48 txa ; CPU:$FFCE PRG:7FCE 8A pha ; CPU:$FFCF PRG:7FCF 48 tya ; CPU:$FFD0 PRG:7FD0 98 pha ; CPU:$FFD1 PRG:7FD1 48 lda #$00 ; CPU:$FFD2 PRG:7FD2 A9 00 sta OAMADDR ; CPU:$FFD4 PRG:7FD4 8D 03 20 lda #$07 ; CPU:$FFD7 PRG:7FD7 A9 07 ## Data-table inventory (Pass 3) The game has two kinds of ROM data: **nametable drawing scripts** and **plain byte tables**. A drawing script is a run of bytes of the form ` $FF`, where the two header bytes are the nametable address the tiles are written to, every other byte is a tile index (ASCII minus `$20` for the game's font, so `$41` = 'A' is tile `$21`), and `$1F` means "move to the next nametable row". The routine that prints them is `Sub_FD3A` (`$FD3A` → `$FF65`), and it is normally called with the script address in X:Y as an immediate. All of that is what the "structure" column below records. | Address | Size | Name | Structure | Read by | |---------|------|------|-----------|---------| | `$8049-$8786` | 1854 | `RingEntranceDpcmPointerTable` (`$8049-$8064`), `RingEntranceDpcmSampleData` (`$8065-$8786`) | `$8049-$8056` = 7 little-endian 16-bit DPCM sample addresses (`$8065`, `$8425`, `$8805`, `$8CDA`, `$913B`, `$942B`, `$97EB`); `$8057-$8064` = the same list again, ending with the last sample's end address `$9BEA`. `$8065` onwards is the delta-encoded DPCM sample data (7 samples of 960-1237 bytes each). | `lda $8055,y` at `$800E` and `lda $8056,y` at `$8013` load the end address of the run to play; the sample bytes themselves are read indirectly by `lda (RingEntrancePtrLo),y` at `$801A`, which converts each byte to a DMC rate and writes it to `$4011` 64 at a time until the pointer reaches the end address | | `$8792-$9BEF` | 5214 | `RingEntranceDpcmSampleData2` | The tail of DPCM sample 2 (`$8792-$8804`) followed by samples 3-7 (`$8805-$9BEF`), same delta encoding as above | read indirectly by `lda (RingEntrancePtrLo),y` at `$801A` through the pointers at `$8049` | | `$9DC5-$9DCB` | 7 | `MessageHoldFrameTable` | 7 single-byte frame counts (`11, 11, 14, 14, 8, 11, 11`) - how many frames each on-screen message is held | `lda $9DC5,y` at `$9DB6` (Y = message index - 1) stores the count to `$066D`, which the frame handler decrements at `$9DBE` | | `$9F44-$9F4B` | 8 | `BitMaskByBitIndexTable` | 8 single-byte masks `$80, $40, $20, $10, $08, $04, $02, $01`; entry *i* masks bit (7-*i*) of a byte | `lda $9F44,y` at `$9F38` (Y = bit count & 7) ANDs the selected bit out of a byte fetched through `RingPtrLo`; `bit $9F49` at `$9DCC` tests entry 5 (`$04` = bit 2) | | `$A281-$A302` | 130 | (unnamed) | **Unreached code.** The bytes decode as instructions: a value-to-table dispatcher at `$A281` (`lda #$30 / bne / lda #$70 / bne / lda #$B0 / bne / lda #$F0 / sta $0612 / iny / rts`), a move-data reader at `$A2B6` and a flag-clearing sequence at `$A2EF` | no instruction in this dump references it - the tracer never reached it | | `$A30A-$A35B` | 82 | `WrestlerMoveHandlerPointerTable` | 41 little-endian 16-bit addresses, all inside the move-handler code at `$A131-$A303` | `lda $A30A,y` at `$A35E` and `lda $A30B,y` at `$A363` (Y = handler id x 2) load the address; `jmp (HandlerPtrLo)` at `$A36C` dispatches to it | | `$A377-$A9F0` | 1658 | `WrestlerMoveParameterData` | A mixed parameter blob. `$A377-$A406` = 72 little-endian 16-bit RAM offsets, descending from `$06B8` to `$001C`. `$A409-$A428` = 16 pointers to move descriptors at `$A7FF-$A841`. `$A429-$A430` and `$A431-$A438` = two 8-byte animation-speed tables (`4,8,12,16,24,32,40,64` and `5,10,15,20,30,40,60,80`). From `$A439` on: further lists of 16-bit pointers, each list terminated by `$0080` | `lda $A377,y` / `lda $A378,y` at `$A0E9`/`$A0E4` copy one 16-bit offset into `$065C`/`$065D`; `lda $A409,y` / `lda $A40A,y` at `$9E06`/`$9E0B` load a move-descriptor pointer into `RingPtrLo`/`RingPtrHi`; `lda $A431,y` at `$9FC1` and `lda $A429,y` at `$9FCC` copy the two speed tables to `$06B1` | | `$A9FA-$AA1C` | 35 | `GameModeDispatchPointerTable` (`$A9FD-$AA1C`) | `$A9FA-$A9FC` is a 3-byte `jmp $F2EE` stub. `$A9FD-$AA1C` = 17 little-endian 16-bit addresses (`$AA7D`, `$ABF0`, `$AC3A`, `$AD48`, `$AD8C`, `$AE0D`, `$AEAE`, `$B0B4`, `$B0D5`, `$B22E`, `$B303`, `$B682`, `$B780`, `$B83D`, `$B88B`, `$B8BE`) - one handler per game screen | `lda $A9FD,x` at `$FD8F` and `lda $A9FE,x` at `$FD94` (X = screen id x 2); `jmp (Zp04)` at `$FD99` | | `$AB05-$AC7E` | 378 | `TitleScreenTextScripts` | A run of nametable drawing scripts: the four-row title logo (address `$20E7`) and the title/menu text "!WRESTLING" (`$AB48`), "!1 PLAYER" (`$AB54`), "2 PLAYERS" (`$AB6A`), "!LICENSED BY / NINTENDO OF AMERICA INC. / ^ 1986 DATA EAST U.S.A. INC." (`$AB72`), "b 1P" (`$ABBB`), " l CHAMP" (`$ABC4`) | printed by `jsr Sub_FD3A` at `$AA9C`, `$AAA3`, `$AAAA`, `$AAB1`, `$AAB8`, `$AABF`, `$AAD3`, `$AAE4` and `$AAEB` with X:Y = `$AB05`, `$AB48`, `$AB54`, `$AB6A`, `$AB72`, `$ABC4`, `$ABBB`, `$ABD0`, `$ABEB` | | `$ACC6-$AD0B` | 70 | `RingPalette` | `$ACC6-$ACD5` = 16 bytes = one complete NES palette (four background colours plus the three 4-colour sprite palettes). The rest of the block is code | copied to palette RAM by `jsr Sub_FD28` at `$AA95` with X:Y = `$ACC6`; `Sub_FD28` (`$FE34`) writes the 16 bytes to `$3F00` | | `$AD3E-$AD9C` | 95 | (unnamed) | **Unreferenced.** The first 10 bytes (`$10 $80 $20 $40 $20 $80 $10 $40 $01 $02`) look like a 4x2 grid of movement multipliers, but the ROM does not settle what they mean; the rest of the block decodes as instructions | no instruction in this dump references it | | `$AE01-$AF9F` | 415 | `WrestlerSlotParameterTable` | `$AE01-$AE0C` = six 2-byte records (tier, wrestler slot) = `(3,6) (2,6) (1,6) (0,9) (0,4) (0,1)`. The rest of the block is code and the message scripts "!PLAYER READY!" (`$AE62`), "!2 PLAYER READY!" (`$AE72`), "*!FIRST MATCH" (`$AE83`), "*!SECOND MATCH" (`$AE91`), "*!THIRD MATCH" (`$AEA0`) | `lda $AE01,x` at `$ADD0` and `lda $AE02,x` at `$ADD5` load the tier into `Zp84` and the slot index into `Zp83` | | `$B017-$B0C0` | 170 | `MatchScoreTileTable` (`$B017-$B030`), `ScoreboardPanelScript` (`$B031-$B0C0`) | `$B017-$B030` = 26 raw nametable tile indices forming the score readout row. `$B031-$B0C0` = a drawing script (address `$2042`) that paints the "1P / CHAMP / ROUND / CP" panel, mixing ASCII text with solid graphic tiles (`$FD` -> tile `$DD`) | the only entry read directly is `$B028`, by `ldy $B028` at `$D8EA`, which becomes the tile index of a score sprite; the panel is printed by `jsr Sub_FD3A` at `$AFEA`, `$AFF7` and `$AFFE` (X:Y = `$B031`, `$B0A7`, `$B0AF`) | | `$B224-$B2C1` | 158 | `WrestlerPinCountTable` | 10 single-byte pin counts (`5,5,5,5,5,4,4,4,3,3`) - how many falls the wrestler in that slot needs to take the match. The rest of the block is code | `ldy $B224,x` at `$B186` (X = `Zp83`, the wrestler slot) gives the number of pins required for that slot, stored to `ZpA0` | | `$B2E5-$B3BF` | 219 | (unnamed) | **Unreferenced.** The first 23 bytes are the "!WINNER IS RICKY FIGHTERS" drawing script (address `$2168`, ASCII text, `$FF` terminator) - a copy of the message the ROM never prints, since the winner screen only ever names "STRONG BADS" (`$B765`). The rest of the block decodes as instructions | no instruction in this dump references it | | `$B431-$B697` | 615 | `RankingScreenPaletteTable` (`$B431-$B440`), `RankingScreenAltPaletteTable` (`$B441-$B450`), plus the ranking-screen scripts and pictures | `$B431-$B440` = 16 bytes = one NES palette; `$B441-$B450` = a second NES palette. `$B451-$B464` = 10 pointers to the ten ranking title scripts. `$B465-$B485` = a byte table of descending position values. `$B486-$B544` = the ten title scripts ("REGIONAL RANKING", "AMERICAN RANKING", "EUROPEAN RANKING", "WORLD RANKING", "SUPER RANKING" and the matching "... CHAMPION" set). `$B546-$B557` = 6 pointers to the belt pictures. `$B558-$B697` = the six belt pictures, each a run of tile bytes with `$1F` row separators | `lda $B472,x` at `$B3C4` and `lda $B47C,x` at `$B3CC`/`$B3D4` read the byte table; `ldy $B451,x` / `lda $B452,x` at `$B3DC`/`$B3DF` load a title script and `ldy $B546,x` / `lda $B547,x` at `$B3E8`/`$B3EB` load a belt picture, both printed with `jsr Sub_FD3A` at `$B3E3`/`$B3EF`; the two palettes are written with `jsr Sub_FD28` at `$B423`/`$B42B` (X:Y = `$B431`/`$B441`) | | `$B765-$B7C6` | 98 | `WinnerIsStrongBadsMessage` | A drawing script: address `$2168`, then the ASCII text "!WINNER IS STRONG BADS" and the `$FF` terminator. The rest of the block is code | printed by `jsr Sub_FD3A` at `$B6D7` and `$B811` (X:Y = `$B765`) | | `$B901-$B90C` | 12 | `GameOverMessage` | A drawing script: address `$21CC`, then the ASCII text "!GAME OVER" and the `$FF` terminator. The rest of the block is code | printed by `jsr Sub_FD3A` at `$B8D7` (X:Y = `$B901`) | | `$B97B-$B9BF` | 69 | `RankingRegionLabelTable` | 5 pointers (`$B985`, `$B98B`, `$B991`, `$B999`, `$B9A1`) to the region label scripts " REG", " USA", " EUROP", " WORLD" and " SUPER" (address `$208C`, or `$20AD` for the last). The block also holds the " CHAMP" script at `$B9A9` and the code that prints them | `ldy $B97B,x` / `lda $B97C,x` at `$B92D`/`$B930` (X = label id x 2) and `lda $B9B1,x` / `lda $B9B2,x` at `$B95B`/`$B960`, followed by `jsr Sub_FD3A` at `$B934`/`$B951` | | `$B9E2-$BA6F` | 142 | `RankingScreenGraphicScriptTable` | 10 pointers to short drawing scripts that paint the belt and medal graphics at `$218E`, `$21AB` and `$21C0`; each script is an address plus one to four tile bytes and a `$FF` terminator | `ldy $B9E2,x` / `lda $B9E3,x` at `$B9CC`/`$B9CF` (X = screen id x 2), then `jsr Sub_FD3A` at `$B9D3` | | `$BFF0-$C00C` | 29 | `WrestlerPoseHandlerTable` | `$BFF0-$BFF2` = 3 single-byte values (1, 2, 3). `$BFF3-$C00C` = 13 little-endian 16-bit handler addresses (`$BDC3`, `$BDF9` x3, `$BF3F`, `$BF61`, `$BF68`, `$BF8A`, `$BFAB`, `$BFE8` x3, `$BFC0`) | `cmp $BFF0,x` at `$BDEE` compares the low nibble of a wrestler flag against the three values; `lda $BFF3,x` / `lda $BFF4,x` at `$BDB6`/`$BDBB` (X = (sprite tile & `$3F`) x 2) load a handler and `jmp (Zp22)` at `$BDC0` dispatches to it | | `$C385-$C39E` | 26 | `WrestlerPoseHandlerTable2` | 13 little-endian 16-bit handler addresses (`$C02C` x3, `$C2BE`, `$C2E0`, `$C2E7`, `$C309`, `$C341`, `$C37E` x3, `$C356`) | `lda $C385,x` / `lda $C386,x` at `$C01F`/`$C024` (X = (sprite tile & `$3F`) x 2) and `jmp (Zp22)` at `$C029` | | `$C6A4-$C6CD` | 42 | `PlayerXByGameStateTable` (`$C6A7-$C6B3`), `WrestlerPoseHandlerTable3` (`$C6B4-$C6CD`) | `$C6A4-$C6A6` = 3 bytes no instruction reads. `$C6A7-$C6B3` = 13 single-byte screen X positions (`120, 112, 104, 96, 104, 112, 120, 128, 136, 144, 152, 160, 202`) - where the wrestler stands in each game state. `$C6B4-$C6CD` = 13 little-endian 16-bit handler addresses (`$C3CA`, `$C3CD`, `$C3D0`, `$C5E9`, `$C60B`, `$C612`, `$C634`, `$C655`, `$C692` x4, `$C66A`) | `lda $C6A7,y` at `$BF6C`, `$C2EB` and `$C616` (Y = game state) stores the position to `PlayerX`; `lda $C6B4,x` / `lda $C6B5,x` at `$C3BD`/`$C3C2` and `jmp (Zp22)` at `$C3C7` | | `$C7D1-$C7F8` | 40 | `WrestlerMoveStateTable` | Five 8-byte tables, one per wrestler slot (0-7), giving the state a wrestler moves to next: `$C7D1` = `2,1,0,4,3,6,5,5`; `$C7D9` = `1,0,5,3,6,2,4,4`; `$C7E1` = `0,1,2,3,4,5,6,6`; `$C7E9` = `0,2,1,4,3,5,6,6`; `$C7F1` = `0,0,0,0,4,4,4,$0C` | `lda $C7D1,x` at `$C75E`, `lda $C7D9,x` at `$C773`, `lda $C7E1,x` at `$C78E`, `lda $C7E9,x` at `$C7A3` and `lda $C7F1,x` at `$C74B` (X = wrestler slot) each load one value into Y | | `$D449-$D4AD` | 101 | `WrestlerSpriteTileTable` | `$D449-$D48E` = 35 (tile, attribute) pairs giving the sprite tile and OAM attribute of each wrestler pose (`$C0`/`$C7`, `$87`, `$80`, `$00`, `$01`-`$04`, `$3F`, ...). `$D48F` = 1 byte. `$D490-$D4AD` = 15 little-endian 16-bit handler addresses (`$C83F`, `$C8DD`, `$C8E0` x2, `$CA35`, `$CA7B`, `$CAC3`, `$CAF4`, `$CB08`, `$CC39`, `$CE3C`, `$CF71`, `$D08F`, `$D12D`, `$D160`) | `lda $D449,x` / `lda $D44A,x` at `$D19F`/`$D1A3` (X = pose x 2 + wrestler) load the tile and the attribute; `lda $D481,x` at `$D29E`; `lda $D490,x` / `lda $D491,x` at `$C832`/`$C837` and `jmp (Zp22)` at `$C83C` | | `$D7AA-$D7B2` | 9 | `WrestlerStartPositionTable` | Four (X, Y) start-position pairs for the wrestlers - (144, 72), (136, 68), (128, 58), (136, 52) - plus the X byte of a fifth pair | `lda $D7AA,y` / `lda $D7AB,y` at `$D660`/`$D665` (Y = game state & `$FE`) store the start X and Y to `PlayerX`/`PlayerY` | | `$D93B-$D947` | 13 | `RingOutMessage` | A drawing script: address `$218B`, then the ASCII text "!RING OUT!" and the `$FF` terminator | printed by `jsr Sub_FD3A` at `$D910` (X:Y = `$D93B`) | | `$D9C8-$D9E5` | 30 | (unnamed) | **Unreferenced.** Two copies of the " TIME OVER " message script (addresses `$216A` and `$212A`). The copy the game prints is the second one, at `$D9D7`, so the first is dead data | no instruction in this dump references `$D9C8`; the printed copy at `$D9D7` is reached by the immediate address in `jsr Sub_FD3A` at `$D9B9` | | `$DA82-$DA9B` | 26 | `Wrestler1PoseHandlerTable` | 13 little-endian 16-bit handler addresses (`$DA02` x3, `$DA29` x2, `$DA2E` x2, `$DA33`, `$DA47`, `$DA48`, `$DA49`, `$DA4A`, `$DA57`) | `lda $DA82,x` / `lda $DA83,x` at `$D9F5`/`$D9FA` (X = (sprite tile & `$3F`) x 2) and `jmp (Zp22)` at `$D9FF`; the top two bits of the sprite tile (`$C0`) select the left- or right-facing variant | | `$DB21-$DB3A` | 26 | `Wrestler2PoseHandlerTable` | 13 little-endian 16-bit handler addresses (`$DAB8` x3, `$DADF` x2, `$DAE4` x2, `$DAE9`, `$DAFD`, `$DAFE`, `$DAFF`, `$DB00`, `$DB0D`) | `lda $DB21,x` / `lda $DB22,x` at `$DAAB`/`$DAB0` and `jmp (Zp22)` at `$DAB5` | | `$DC5B-$DC63` | 9 | `AttackPromptTileRow` | 9 raw nametable tile indices (`0, $21, $34, $34, $21, $23, $2B, $01, 0`) which spell " ATTACK! " in the game's font, where the tile index is the ASCII code minus `$20` | `lda $DC5B,x` at `$DC33` writes the nine bytes straight to `$2007` for X = 0-8 | | `$DE38-$DEBB` | 132 | (unnamed) | **Unreached code.** The bytes decode as a run of 69 instructions: a `jmp $DEBC` dispatcher, a game-state test with a `jsr $DFF3` call at `$DE3B`, and the wrestler-movement code that recomputes `PlayerX`/`PlayerY` from `$DE46` on | no instruction in this dump references it - the tracer never reached it | | `$E050-$E1A9` | 346 | `SoundEffectMusicData` (`$E050-$E18B`), `SoundMusicHandlerPointerTable` (`$E18C-$E1A9`) | `$E050-$E18B` = music and sound-effect sequence data in the APU driver's own format: a duration byte followed by note and volume bytes (e.g. `$14 $40 $3C $18 $03`). `$E18C-$E1A9` = 15 little-endian 16-bit addresses into the sound code (`$DC9C`, `$DC9F`, `$DCDA`, `$DCDD`, `$DDE0`, `$DDE3`, `$DDE6`, `$DDE9`, `$DDFB`, `$DE07`, `$DE35`, `$DE38`, `$DE3B`, `$DE47`, `$DEA5`) | `lda $E18C,x` / `lda $E18D,x` at `$DC8F`/`$DC94` (X = (effect id & `$1F`) x 2) load a handler and `jmp (Zp22)` at `$DC99` dispatches to it | | `$E256-$E2D1` | 124 | `RingHudTileRowData` | Raw nametable tile rows for the ring furniture: ten tiles `$CA` then fifteen tiles `$FF`, then nine tiles `$44` capped with `$58`, then the `$AC`/`$AD`/`$AF`/`$AE` corner tiles, then a 19-tile row of assorted tiles and a long run of the repeated pair `$43 $4B` | `lda $E256,x` at `$E1C9` and again at `$E1E4` copy the rows to `$2007` with the nametable address set to `$226B` by `jsr Sub_FD34` at `$E1D7` | | `$E669-$E6FE` | 150 | `RingPostTileRowData` | 150 raw nametable tile bytes, almost all `$00` with a few `$E0`-`$E3` tiles, forming the ring-post and rope graphic | `lda $E669,y` at `$E65E` writes them to `$2007` | | `$E753-$E7BE` | 108 | `RingSpriteNametableAddressTable` (`$E753-$E772`), `RingSpriteTileAttributeTable` (`$E773-$E792`), four belt pictures (`$E793`, `$E79D`, `$E7A8`, `$E7B3`) | `$E753-$E772` = 16 little-endian nametable addresses (`$20E2`, `$20EB`, `$20F4`, `$20FC`, `$2121`, `$213D`, `$2160`, `$217E`, `$21C5`, `$21CC`, `$21D2`, `$21D9`, `$21E1`, `$21FD`, `$2221`, `$223D`). `$E773-$E792` = 16 (tile, OAM attribute) pairs. `$E793-$E7BE` = four two-row tile pictures at `$236A` and `$2372` | the picture scripts are printed by `jsr Sub_FD3A` at `$E73C` and `$E74D` (X:Y = `$E79D` and `$E7B3`); the two tables are handed to the sprite-placing routine at `$F030` as an address pair - `$E753`/`$E773`, or `$E763`/`$E783` when the game state is negative | | `$E7F0-$E82F` | 64 | (unnamed) | **Unreferenced.** 16 little-endian nametable addresses (`$20E7`, `$20EF`, `$20F7`, `$2101`, `$211D`, `$2140`, `$215E`, `$21A0`, `$21C1`, `$21C8`, `$21D5`, `$21DD`, `$2201`, `$221D`, `$2241`, `$225D`) followed by 16 (tile, attribute) pairs - the same two-table shape as `$E753`/`$E773`, but with no reader in this dump | no instruction in this dump references it | | `$E893-$E8B2` | 32 | (unnamed) | **Unreferenced.** Eight little-endian nametable addresses (`$2363`, `$2368`, `$236F`, `$2376`, `$237A`, `$2386`, `$238E`, `$2396`) followed by eight (tile, attribute) pairs, all `$CD`/`$CF` | no instruction in this dump references it | | `$E956-$E9C5` | 112 | `LastSecondsMessageScripts` | Five drawing scripts that print the "!LAST 60 SEC.", "*!LAST 60 SEC.", "!LAST 30 SEC." and "*!LAST 30 SEC." warnings at `$216A` and `$212A`, followed by an 18-byte countdown table at `$E992` (the first pair is `$11,$10`, the rest are attribute `$00` with the tile descending `$19` to `$11`) and two bar scripts - a row of 14 identical tiles at `$216A` and a row of 12 identical tiles at `$212A` | `lda $E992,x` / `lda $E993,x` at `$E923`/`$E929` write the two countdown bytes to `$2007`; the message scripts are printed by `jsr Sub_FD3A` at `$E8FB`, `$E90D`, `$E94D`, `$D313` and `$D4CB` (X:Y = `$E983`, `$E965`, `$E9B7`, `$E9A8`) | | `$EBDD-$EBE3` | 7 | `WrestlerFacingTable` | 7 single-byte values (`0, 1, 0, 1, 0, 2, 0`) - the ring side a wrestler stands on | `lda $EBDD,x` at `$EAE3` (X = wrestler slot) loads the side into `Zp1B`; the code overrides it with 2 for the second player | | `$ED2A-$ED4C` | 35 | `WrestlerMoveFlagTable` (`$ED2A-$ED3C`), `WrestlerMoveParameterTable` (`$ED3D-$ED4C`) | `$ED2A-$ED3C` = 19 single-byte flags (0 or 1), one per wrestler move. `$ED3D-$ED4C` = 16 single-byte parameters (`6, 0, 7, 0, 3, 4, 7, 0, 1, 5, 3, 7, 2, 0, 8, 3`) | `lda $ED3D,x` at `$ECFC` (X = move id) loads one parameter into `Zp94` | | `$EE75-$EE86` | 18 | `SoundEffectHandlerPointerTable` | 9 little-endian 16-bit addresses into the sound code (`$EDC4`, `$EDC7`, `$EDCD`, `$EDD6`, `$EDDC`, `$EDE5`, `$EDEB`, `$EDF4`, `$EDFA`) | `lda $EE75,x` / `lda $EE76,x` at `$EDB7`/`$EDBC` (X = effect id x 2) and `jmp (Zp24)` at `$EDC1` | | `$EEB7-$EEC4` | 14 | `NotePitchHandlerAddressTable` | 7 little-endian 16-bit code addresses (`$C927`, `$C729`, `$C42C`, `$C22E`, `$C12F`, `$C030`, `$C030`), picked by how high the note being played is | `lda $EEB7,x` / `ldy $EEB8,x` at `$EEAF`/`$EEB2` return the address in X:Y after the code has counted how many of the thresholds `$88`, `$78`, `$70`, `$60`, `$50` the note exceeds | | `$EF2C-$EF2E` | 3 | `SpriteTileIndexList` | 3 single-byte tile indices (`$FC`, `$FD`, `$FE`) - the three sprites one wrestler is drawn from | `lda $EF2C,y` at `$EEF3` (Y = sprite 0-2) supplies the tile of each sprite written into the `$0714` OAM buffer | | `$EF89-$EF8C` | 4 | (unnamed) | **Unreferenced.** Four single-byte values (`$F3`, `$F4`, `$F5`, `$F6`) that look like four sprite tile indices, but the ROM does not settle it | no instruction in this dump references it | | `$F119-$F120` | 8 | `TimerLabelTileRow` | 8 raw nametable tile indices (`$34, $29, $2D, $25, $00, $00, $1D, $00`) spelling "TIME = " in the game's font | `lda $F119,x` at `$F0DE` writes the eight bytes to `$2007` for X = 0-7 | | `$F2D6-$FD12` | 2621 | `SoundSequencePointerTable` (`$F2D6-$F2E5`), `SoundEffectParameterTable` (`$F2EF-$F36F`), plus the effect data itself | `$F2D6-$F2E5` = 8 little-endian 16-bit addresses into the sound data (`$F255`, `$F272`, `$F27F`, `$F28C`, `$F299`, `$F2AC`, `$F2BB`, `$F2C1`). `$F2EF-$F36F` = 64 little-endian 16-bit entries, each the address of a sound definition (the first three are `$F2F5`, `$F5F5` and `$F55B`; the rest point into the effect tables that follow). The remainder of the block is that effect data - period and noise tables and note sequences | `lda $F2EF,x` / `lda $F2F0,x` at `$EA6C`/`$EA71` (X = (effect id & `$7F`) x 2) load a definition address, and the code reads its two header bytes through `lda (Zp22),y` at `$EA78`/`$EA7D` | | `$FFEE-$FFFF` | 18 | (unnamed) | The tail of the sound data ($FFEE-$FFF9) followed by the three interrupt vectors: NMI = `$FFCD`, RESET = `$FD43`, IRQ = `$FD43` | no instruction in this dump references it; the vectors are read by the CPU, not by the program | ## Entry-point naming (2026-10-21) The 302 address-derived entry points (`Sub_`) - every `jsr`/`jmp` target that carried no semantic name - are now named, together with the 154 `SubC` local labels of the same kind. Each new name says what the code does **in Tag Team Wrestling**, read off the routine's own body and the caller that reaches it: | Old | New | What the code shows | |-----|-----|----------------------| | `Sub_8000` | `SetRingEntrancePointers` | takes the entrance index and loads the two ring-entrance script pointers | | `Sub_9C1A` | `UpdateRingEntranceState` | the ring-entrance state machine: the timer, the sound and the sprite | | `Sub_9FEB` | `UpdateRingEntranceSprite` | moves the entrance sprite, applies the speed and clamps it to the ring | | `Sub_A35C` | `CallRingMoveHandler` | the wrestler-move dispatcher: `WrestlerMoveHandlerPointerTable` at `$A30A` | | `Sub_A131` | `PushRingPointer` | the ring script interpreter's stack push | | `Sub_A36F` | `AdvanceRingScriptIndex` | the ring script interpreter's operand fetch | | `Sub_B3D7` | `DrawRingHud` | draws the ring HUD row and the timer | | `Sub_D9E6` | `CallWrestlerPoseHandler` | the wrestler-pose dispatcher: `Wrestler1PoseHandlerTable` at `$DA82` | | `Sub_DA9C` | `CallWrestlerPoseHandler2` | the same for the second wrestler: `Wrestler2PoseHandlerTable` at `$DB21` | | `Sub_BCA6` | `StoreRingSpritePositions` | writes the two wrestlers' X and Y back into the player RAM | | `Sub_E4CD` | `BuildRingSpriteList` | fills the `$0700` sprite list with the two wrestlers' four sprites | | `Sub_E830` | `WriteRingNameTiles` | writes the two wrestlers' names into the nametable | | `Sub_EEED` | `BuildRingMoveList` | fills the `$0714` OAM buffer for a wrestler move | | `Sub_F03D` | `DrawRingEntrance` | points the ring-entance pointers and redraws with NMI off | | `Sub_FD3A` | `WriteGraphicScript` | the graphic-script writer: `[address][tiles][$FF]` | | `Sub_FD85` | `DispatchGameMode` | the game-mode dispatcher: `GameModeDispatchPointerTable` at `$A9FD` | | `Sub_FF53` | `SetVramAddress` | writes X and Y to the two PPUADDR registers | **Residue: 0 `jsr`/`jmp` entry points remain address-derived.** Eleven `SubC` labels are still address-derived, but none of them is an entry point and none of them is code: * `SubC8787` ($8787) sits on the five bytes between the two DPCM sample blocks; the tracer decoded the last three of them as an indirect jump. * `SubCED0D`, `SubCED0E`, `SubCED0F`, `SubCED14`, `SubCED15`, `SubCED16`, `SubCED1B`, `SubCED22` and `SubCED23` ($ED0D-$ED29) are the 29 bytes that precede `WrestlerMoveFlagTable` at `$ED2A`; the tracer decoded them as `BRK` and `ORA (zp,x)` sequences. The dump does not reveal what they are, so they are recorded here rather than given a guessed name. Not covered is the separate set of internal branch labels (`Sub_Loop`, `Sub_OnNonzero` and so on, 809 of them). They are branch targets rather than entry points, and they are still address-derived; naming them is the next piece of work. ## Build ``` Byte-identical ROM verified. ```