# Xevious (U) ## Status **Pass 3 complete, with a Pass 1 correction applied on 2026-10-21 and the data-table interpretation added on 2026-10-21.** The original static-trace split missed 1,158 bytes of code reached through computed dispatch; the Mesen CDL capture `xevious_mesen.cdl` (present in this folder) was applied with `_tools/cdl_reclass.py`, which re-split the file (1,158 data→code, 48 code→data). The 45 entry points that the correction recovered now carry `Sub_XXXX` names, so there is no `Label_XXXX` residue. Six raw `$XXXX` call operands remain, all inside regions the CDL never observed (listed under **Pass 1 notes**). Every one of the 129 data blocks the tracer emitted is now accounted for: 46 blocks carry a semantic name and a description of what their bytes are and which instruction reads them, one more ($C30E) is read as the last byte of the table at $C28F, 44 are recorded as unreferenced data with their ROM provenance, and 38 are recorded as code the tracer could not reach (their bytes decode as instructions, but the CDL capture never fetched them). The full list is in **Pass 3 data-table inventory** below. `make` assembles `header.s`, `prg.s`, `chr.s`, links them with `ld65` and compares the result against `rom.nes`: ``` Byte-identical ROM verified. ``` ### Pass 1 results | Metric | Value | |--------|-------| | PRG size | 32768 bytes (32 KB) at $8000-$FFFF | | Code | 12455 bytes (38.0%) | | Data | 20313 bytes (62.0%) | | Instructions | 6002 | | Label definitions | 868 (624 `Sub_XXXX` internal) | | Zero-page aliases | 156 (in `locals.inc`) | | Indirect dispatches | `jmp ($fe)` at $BA88 (table $BA8B, 16 entries), `jmp ($4)` at $CA07 (table $CA0A, 44 entries) | ### Pass 2 results | Metric | Value | |--------|-------| | `Label_XXXX` names replaced | 781 at Pass 2 + 45 recovered by the CDL re-split | | Raw `$XXXX` jsr/jmp operands replaced | 466 at Pass 2; every re-split operand on an instruction boundary now uses a label | | Remaining raw `$XXXX` jsr/jmp | 6 (inside CDL-silent misdecoded regions — see Pass 1 notes) | | Semantic zero-page aliases | ~20 (in `locals.inc`) | ### Pass 3 results | Metric | Value | |--------|-------| | Semantic entry-point names | 143 (Reset, NmiHandler, IrqHandler, InputRead, ObjInitCall, ObjMoveCall, ObjDrawCall, ObjUpdateCall, SetOamPtrs, WaitVblank, GameModeDispatch, ObjSpriteSetup, ObjCommonUpdate, etc.) | | Internal branch labels | 624 (`Sub_XXXX` address-based, local to routines) | | Named data tables | 46 (every block with a known purpose; see **Pass 3 data-table inventory**) | | Data blocks interpreted | 129 of 129 (46 named, 1 referenced tail, 44 unreferenced data, 38 unreached code) | | Semantic zero-page aliases | ~20 (PPUCTRLShadow, ObjectX, ObjectY, ObjPtr, GameMode, Joypad1Cur, etc.) | ## Pass 3 data-table inventory Every data block the tracer emitted, with what its bytes are and the instruction that reads them. "Not referenced by any instruction" means no operand in this dump lands inside the block; such a block is either **unreferenced data** (recorded with its ROM provenance) or **code the tracer could not reach** (its bytes decode as a run of instructions, but the Mesen CDL capture never fetched them). The CDL column in the structure text records what `xevious_mesen.cdl` saw at those addresses. | Address | Size | Name | Structure | Read by | |---------|------|------|-----------|---------| | `$8000-$A2BF` | 8896 B | `LevelTilemapData, TerrainOverlayTableA, TerrainOverlayTableB, TerrainOverlayTableC` | the level's background tilemap - 8192 bytes = 32 columns x 256 rows of tile indices for the $1000 (background) pattern table; the first and last rows are a jagged run of $6F-$72 (terrain shapes), long runs of $0C/$0D/$CD are the sky gradients - then the four 247-byte overlay tables at $A000, $A0F7, $A1EE and $A2E5 | `lda $A1EE,x` at $F44C/$F47A, `lda $A000,x` at $F4AF/$F4DD, `lda $A0F7,x` at $F4B6/$F4E4 - all indexed by a tile byte read from the nametable at $8000+; the `bit $8481` and `jsr $9848` operands are mis-decodes | | `$A2C3-$A405` | 323 B | `TerrainOverlayTableD` | continuation of the overlay tables: the fourth 247-byte table at $A2E5, then a table of 16-bit code addresses at $A3DC-$A3FF | `lda $A2E5,x` at $F453/$F481, `lda $A3F0,x`/`lda $A3F1,x` at $F214/$F218, `cmp $A3DC,x`/`lda $A3DD,x` at $F52E/$F538 | | `$A43E-$A440` | 3 B | `-` | unreferenced data - three bytes ($20, $7F, $F8) between two routines; CDL: none of the 3 bytes was touched by the capture | not referenced by any instruction | | `$A50B-$A51A` | 16 B | `EdgeSpriteLayout` | four 4-byte sprite records (Y, tile, attribute, X); the two halves are mirror images (X = $CD and $24) | `lda $A50B,x` at $A4F6 | | `$A541-$A550` | 16 B | `VramAddrSeedTable` | eight 16-bit constants copied to $0720-$072F | `lda $A541,x` at $A553 | | `$A62A-$A659` | 48 B | `StageSpriteLayout` | twelve 4-byte sprite records (Y, tile, attribute, X) | `lda $A62A,x` at $A5B4, `lda $A652,x` at $A61B | | `$A6CE-$A6D6` | 9 B | `TitleSpriteLayout` | two 4-byte sprite records (Y, tile, attribute, X) plus one spare byte | `lda $A6CE,x` at $A68F | | `$A74B-$A768` | 30 B | `VramWritePtrTable` | 15 x 16-bit pointers to the VRAM write descriptors below | `lda $A74B,x` at $A6E1 and $A6E7 | | `$A769-$A8D4` | 364 B | `VramWriteData, LogoSpriteLayout` | VRAM write descriptors [addrLo, addrHi, count, data...] - 15 of them, writing the initial nametable contents ($2063, $206C, $2075, $2104-$2363) and the $23C0 attribute table; the last 20 bytes are the logo sprite records | `lda $A7AC,x` at $A41C (the logo records only); the descriptors are reached through the pointer table at $A74B | | `$A8D5-$A8F4` | 32 B | `StageScriptPtrTable` | 16 x 16-bit pointers to the stage scripts | `lda $A8D5,x` at $F3E4, `lda $A8D6,x` at $F3E9 | | `$A8F5-$A9BA` | 198 B | `ObjSpritePtrTable` | 99 x 16-bit pointers to the per-object sprite data | `lda $A8F5,y` at $C353, `lda $A8F6,y` at $C359 | | `$A9BB-$ACFA` | 832 B | `ObjSpriteData` | the per-object sprite data the 99 pointers of $A8F5 address | not referenced by any instruction - reached through the pointer stored in the object at $050A/$050B | | `$ACFB-$B8AA` | 2992 B | `StageScriptData, ObjectBitMaskTable` | 16 bytecode scripts laid end to end, each prefixed with its length byte; the last 12 bytes are the object bit masks | `lda $B89F,y` at $CBDF and $CBF9 (the masks only); the scripts are reached through the pointer table at $A8D5 | | `$BA8B-$BAAA` | 32 B | `IndDispatchFeTable` | 16 x 16-bit code addresses for the `jmp ($fe)` dispatch at $BA88 | `lda $BA8B,x` at $BA7E, `lda $BA8C,x` at $BA83 | | `$BB55-$BEFA` | 934 B | `SpriteAttrTable, CopyrightString` | sprite attribute words (16-bit, indexed by the high nibble of the packed attribute byte), then CDL-silent sprite code and data, then the 54-byte Namco copyright string at $BEC9 | `lda $BB55,x`/`lda $BB56,x` at $BA21/$BA26, `lda $BB6D`/`lda $BB6E` at $B8BB/$B8C0, `lda $BB97`/`lda $BB98` at $B95C/$B961 | | `$C000-$C000` | 1 B | `-` | unreferenced data - a single $88 byte; CDL: 1/1 bytes read as data | not referenced by any instruction | | `$C09E-$C1FD` | 352 B | `EnemySpawnParamTable` | 176 two-byte records (enemy-slot count, index of the first slot) | `lda $C09E,x`/`lda $C09F,x` at $C040/$C045, `lda $C0FE,x`/`lda $C0FF,x` at $C04B/$C050, `and $C1EF,x` at $D643 | | `$C28F-$C304` | 118 B | `EnemySlotOffsetTable` | per-enemy-slot one-byte offsets; the table really runs $C28F-$C30E (the tracer split it at $C305) | `lda $C28F,y` at $C259 | | `$C30E-$C30E` | 1 B | `-` | the last byte of the 128-entry offset table at $C28F | `lda $C28F,y` at $C259 with y = $7F | | `$C440-$C444` | 5 B | `ObjHandlerJumpTable` | 16-bit handler addresses; only the first two entries lie inside the block, the rest of the 32-entry table overlaps what the tracer split as code | `lda $C441,y` at $C437, `lda $C440,y` at $C43B | | `$C478-$C47C` | 5 B | `-` | code the tracer could not reach - five bytes that decode as `jsr $C6B4` plus a truncated `lda`; CDL: none of the 5 bytes was touched by the capture | not referenced by any instruction | | `$C482-$C499` | 24 B | `-` | code the tracer could not reach - decodes as ten consecutive instructions; CDL: none of the 24 bytes was touched by the capture | not referenced by any instruction | | `$C4AE-$C4D1` | 36 B | `-` | code the tracer could not reach - decodes as fifteen consecutive instructions; CDL: none of the 36 bytes was touched by the capture | not referenced by any instruction | | `$C4F2-$C4F3` | 2 B | `-` | code the tracer could not reach - two bytes (`sta $0C`); CDL: none of the 2 bytes was touched by the capture | not referenced by any instruction | | `$C4FD-$C4FE` | 2 B | `-` | code the tracer could not reach - two bytes (`sta $00`); CDL: none of the 2 bytes was touched by the capture | not referenced by any instruction | | `$C526-$C53A` | 21 B | `-` | code the tracer could not reach - decodes as eight consecutive instructions; CDL: none of the 21 bytes was touched by the capture | not referenced by any instruction | | `$C553-$C567` | 21 B | `-` | code the tracer could not reach - decodes as nine consecutive instructions; CDL: none of the 21 bytes was touched by the capture | not referenced by any instruction | | `$C5A3-$C625` | 131 B | `-` | code the tracer could not reach - decodes as 54 consecutive instructions; CDL: none of the 131 bytes was touched by the capture | not referenced by any instruction | | `$C64F-$C657` | 9 B | `-` | code the tracer could not reach - decodes as four consecutive instructions; CDL: none of the 9 bytes was touched by the capture | not referenced by any instruction | | `$C65F-$C698` | 58 B | `-` | code the tracer could not reach - decodes as 24 consecutive instructions; CDL: none of the 58 bytes was touched by the capture | not referenced by any instruction | | `$C6D3-$C6D3` | 1 B | `-` | unreferenced data - a single $A9 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$C741-$C79F` | 95 B | `EnemySpriteTileTable` | six one-byte tile indices ($01, $01, $02, $02, $0A, $BD), then code | `lda $C741,y` at $C72F | | `$C83A-$C8B3` | 122 B | `ObjDataPtrTable` | 61 x 16-bit pointers into the per-object data area $C86x-$C9xx | `lda $C83A,y` at $C7F8, `lda $C83B,y` at $C7FD | | `$C8BB-$C8BD` | 3 B | `-` | unreferenced data - three bytes; CDL: none of the 3 bytes was touched by the capture | not referenced by any instruction | | `$C8C5-$C8D1` | 13 B | `-` | unreferenced data - thirteen bytes; CDL: none of the 13 bytes was touched by the capture | not referenced by any instruction | | `$C8DA-$C90E` | 53 B | `-` | code the tracer could not reach - 53 bytes of code the tracer split out of the routine at $C8B4; CDL: none of the 53 bytes was touched by the capture | not referenced by any instruction | | `$C916-$C91F` | 10 B | `-` | code the tracer could not reach - ten bytes of code; CDL: none of the 10 bytes was touched by the capture | not referenced by any instruction | | `$C927-$C9BB` | 149 B | `ObjYPosTable` | code, then the 16-bit Y positions at $C93C | `lda $C93C,y` at $C7C8, `lda $C93D,y` at $C7CD | | `$CA0A-$CA61` | 88 B | `BytecodeOpDispatchTable` | 44 x 16-bit handler addresses for the script VM's opcode dispatch | `lda $CA0A,x` at $C9F7, `lda $CA0B,x` at $C9FC | | `$CD37-$CD44` | 14 B | `ObjTypeCodeTable` | fourteen one-byte object-type codes | `lda $CD37,x` at $CC96 and $CCEA | | `$CD4C-$CD4C` | 1 B | `CharCodeTable` | the first byte of an ASCII character table (`abcdefghijklmno...`) | `lda $CD4C,x` at $CBB8, $CBBF, $CC2A and $CC31 | | `$CD4D-$CD80` | 52 B | `-` | unreferenced data - the rest of the ASCII character table started at $CD4C; CDL: 11/52 bytes read as data | not referenced by any instruction | | `$CD89-$CE02` | 122 B | `-` | code the tracer could not reach - 122 bytes of code the tracer split out of the routine at $CD81; CDL: none of the 122 bytes was touched by the capture | not referenced by any instruction | | `$CEC3-$CECE` | 12 B | `-` | code the tracer could not reach - decodes as five consecutive instructions; CDL: none of the 12 bytes was touched by the capture | not referenced by any instruction | | `$D014-$D017` | 4 B | `-` | unreferenced data - four bytes; CDL: none of the 4 bytes was touched by the capture | not referenced by any instruction | | `$D215-$D249` | 53 B | `ObjTypeJumpTable` | 16-bit code addresses indexed by the object's type byte; 26 entries fit in the block, the table continues into the code the tracer split at $D24A | `lda $D216,y` at $D20C, `lda $D215,y` at $D210 | | `$D24A-$D24A` | 1 B | `-` | unreferenced data - a single $D9 byte; CDL: 1/1 bytes read as data | not referenced by any instruction | | `$D252-$D2C3` | 114 B | `-` | code the tracer could not reach - 114 bytes of code; CDL: none of the 114 bytes was touched by the capture | not referenced by any instruction | | `$D2CA-$D2CA` | 1 B | `-` | unreferenced data - a single $15 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$D33B-$D342` | 8 B | `-` | code the tracer could not reach - decodes as four consecutive instructions; CDL: none of the 8 bytes was touched by the capture | not referenced by any instruction | | `$D445-$D445` | 1 B | `-` | unreferenced data - a single $A9 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$D628-$D628` | 1 B | `-` | unreferenced data - a single $F4 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$D633-$D63D` | 11 B | `-` | unreferenced data - eleven bytes of the region the tracer split as the routine `Sub_D63E`; CDL: none of the 11 bytes was touched by the capture | not referenced by any instruction - the `and $EF3D` at $D63E is the mis-decode of this data | | `$D654-$D6F8` | 165 B | `ObjMoveCodeBlock, ObjMoveDeltaTable` | CDL-silent bytes that decode as instructions (BIT/STA/STY/CPX), then the ten movement deltas at $D6C7 | `adc $D6C7,y` and `lda $D6C7,y` at $D4B0, $D4BC, $D4C7, $D4CD, $D4D5, $D4EC, $D4F9, $D505, $D50B, $D553 and $D561 | | `$D702-$D71F` | 30 B | `-` | code the tracer could not reach - decodes as fourteen consecutive instructions; CDL: none of the 30 bytes was touched by the capture | not referenced by any instruction | | `$D721-$D793` | 115 B | `-` | code the tracer could not reach - decodes as 51 consecutive instructions; CDL: none of the 115 bytes was touched by the capture | not referenced by any instruction | | `$D7C3-$D7D9` | 23 B | `-` | unreferenced data - five 16-bit pointers to the sprite-layout groups at $D83B plus the first two sprite records; CDL: none of the 23 bytes was touched by the capture | not referenced by any instruction | | `$D833-$D83A` | 8 B | `ObjSpriteLayoutPtrTable` | 4 x 16-bit pointers to the sprite-layout groups at $D840, $D84A, $D864 and $D882 | `lda $D833,y` at $D7E3, `lda $D834,y` at $D7E8 | | `$D83B-$D8DF` | 165 B | `ObjSpriteLayoutData` | sprite-layout groups: a count byte followed by that many 4-byte records (Y offset, tile, attribute, X offset) | not referenced by any instruction - reached through the pointer table at $D833 | | `$D92C-$D986` | 91 B | `-` | code the tracer could not reach - decodes as 45 consecutive instructions; CDL: none of the 91 bytes was touched by the capture | not referenced by any instruction | | `$D9A7-$D9C2` | 28 B | `-` | code the tracer could not reach - decodes as five consecutive instructions; CDL: none of the 28 bytes was touched by the capture | not referenced by any instruction | | `$DA73-$DA90` | 30 B | `ObjSpriteTileTable` | six one-byte sprite tile indices ($D2, $3F, $3F, $3F, $3F, $D2) stored into the tile field of the $0700 sprite record, then code | `lda $DA73,y` at $DA16 | | `$DADE-$DB19` | 60 B | `-` | code the tracer could not reach - decodes as 25 consecutive instructions; CDL: none of the 60 bytes was touched by the capture | not referenced by any instruction | | `$DB7D-$DB8B` | 15 B | `-` | code the tracer could not reach - decodes as six consecutive instructions; CDL: none of the 15 bytes was touched by the capture | not referenced by any instruction | | `$DBCD-$DBDB` | 15 B | `-` | code the tracer could not reach - decodes as six consecutive instructions; CDL: none of the 15 bytes was touched by the capture | not referenced by any instruction | | `$DC5E-$DC5E` | 1 B | `-` | unreferenced data - a single $60 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$DC71-$DC75` | 5 B | `-` | unreferenced data - five bytes; CDL: none of the 5 bytes was touched by the capture | not referenced by any instruction | | `$DDAA-$DEDF` | 310 B | `-` | code the tracer could not reach - decodes as 142 consecutive instructions; CDL: none of the 310 bytes was touched by the capture | not referenced by any instruction | | `$DF0E-$DF0F` | 2 B | `ObjInitRoutinePtr` | the 16-bit code address $DF14 | `lda $DF0E` at $DEEA, `lda $DF0F` at $DEF0 | | `$DF78-$DFA1` | 42 B | `ObjRoutinePtrTable` | 21 x 16-bit code addresses | `lda ObjRoutinePtrTable,y` at $DF41 | | `$DFA7-$DFA8` | 2 B | `-` | code the tracer could not reach - two bytes (`lda #$01`); CDL: none of the 2 bytes was touched by the capture | not referenced by any instruction | | `$E089-$E08A` | 2 B | `-` | unreferenced data - two bytes; CDL: none of the 2 bytes was touched by the capture | not referenced by any instruction | | `$E146-$E150` | 11 B | `-` | code the tracer could not reach - decodes as five consecutive instructions; CDL: none of the 11 bytes was touched by the capture | not referenced by any instruction | | `$E1DB-$E23F` | 101 B | `-` | code the tracer could not reach - decodes as 40 consecutive instructions; CDL: none of the 101 bytes was touched by the capture | not referenced by any instruction | | `$E256-$E25A` | 5 B | `-` | unreferenced data - five bytes; CDL: none of the 5 bytes was touched by the capture | not referenced by any instruction | | `$E288-$E2CE` | 71 B | `-` | code the tracer could not reach - decodes as 28 consecutive instructions; CDL: none of the 71 bytes was touched by the capture | not referenced by any instruction | | `$E409-$E409` | 1 B | `-` | unreferenced data - a single $D0 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$E420-$E44B` | 44 B | `-` | code the tracer could not reach - decodes as 19 consecutive instructions; CDL: none of the 44 bytes was touched by the capture | not referenced by any instruction | | `$E482-$E4E3` | 98 B | `-` | code the tracer could not reach - decodes as 42 consecutive instructions; CDL: none of the 98 bytes was touched by the capture | not referenced by any instruction | | `$E501-$E51F` | 31 B | `-` | code the tracer could not reach - decodes as 12 consecutive instructions; CDL: none of the 31 bytes was touched by the capture | not referenced by any instruction | | `$E553-$E599` | 71 B | `-` | code the tracer could not reach - decodes as 28 consecutive instructions; CDL: none of the 71 bytes was touched by the capture | not referenced by any instruction | | `$E5AF-$E63B` | 141 B | `-` | code the tracer could not reach - decodes as 56 consecutive instructions; CDL: none of the 141 bytes was touched by the capture | not referenced by any instruction | | `$E668-$E6B8` | 81 B | `EnemySpriteFacingTiles` | code, then the nine enemy tile indices at $E680 | `lda $E680,y` at $E86D | | `$E852-$E852` | 1 B | `-` | unreferenced data - a single $4C byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$E8A0-$E8A8` | 9 B | `EnemySpriteTileTableFlip` | nine one-byte enemy tile indices - the left/right facing counterpart of the table at $E680 | `lda $E8A0,y` at $E873 | | `$E8D7-$E982` | 172 B | `-` | code the tracer could not reach - decodes as 77 consecutive instructions; CDL: none of the 172 bytes was touched by the capture | not referenced by any instruction | | `$E9ED-$E9ED` | 1 B | `-` | unreferenced data - a single $B0 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$EA93-$EA9E` | 12 B | `-` | unreferenced data - twelve bytes; CDL: none of the 12 bytes was touched by the capture | not referenced by any instruction | | `$EAB1-$EAE2` | 50 B | `-` | unreferenced data - 50 bytes; CDL: none of the 50 bytes was touched by the capture | not referenced by any instruction | | `$EC95-$EC95` | 1 B | `-` | unreferenced data - a single $A9 byte; CDL: none of the 1 bytes was touched by the capture | not referenced by any instruction | | `$ED7C-$EE27` | 172 B | `EnemySpawnYTable, EnemyMovePtrTable` | eight 16-bit Y positions, then 78 x 16-bit enemy-movement code addresses at $ED8C | `lda $ED7D,y`/`lda $ED7C,y` at $ED60/$ED69, `lda $ED8C,y`/`lda $ED8D,y` at $EBEA/$EBEF | | `$EE2F-$EE3B` | 13 B | `-` | code the tracer could not reach - decodes as eight consecutive instructions; CDL: none of the 13 bytes was touched by the capture | not referenced by any instruction | | `$EE43-$EE4F` | 13 B | `-` | code the tracer could not reach - decodes as eight consecutive instructions; CDL: none of the 13 bytes was touched by the capture | not referenced by any instruction | | `$EE57-$EE6B` | 21 B | `-` | code the tracer could not reach - decodes as 14 consecutive instructions; CDL: none of the 21 bytes was touched by the capture | not referenced by any instruction | | `$EE78-$EE7B` | 4 B | `-` | unreferenced data - four bytes; CDL: none of the 4 bytes was touched by the capture | not referenced by any instruction | | `$EE83-$EE8C` | 10 B | `-` | unreferenced data - ten bytes; CDL: none of the 10 bytes was touched by the capture | not referenced by any instruction | | `$EE94-$EE9D` | 10 B | `-` | unreferenced data - ten bytes; CDL: none of the 10 bytes was touched by the capture | not referenced by any instruction | | `$EEA5-$EED0` | 44 B | `-` | unreferenced data - 44 bytes; CDL: none of the 44 bytes was touched by the capture | not referenced by any instruction | | `$EED8-$EF08` | 49 B | `-` | unreferenced data - 49 bytes; CDL: none of the 49 bytes was touched by the capture | not referenced by any instruction | | `$EF10-$EF2A` | 27 B | `-` | unreferenced data - 27 bytes; CDL: none of the 27 bytes was touched by the capture | not referenced by any instruction | | `$EF32-$EF34` | 3 B | `-` | unreferenced data - three bytes; CDL: none of the 3 bytes was touched by the capture | not referenced by any instruction | | `$EF3B-$EFC5` | 139 B | `SpriteLayoutBlocks` | a run of sprite-layout blocks (count byte + 4-byte records of Y offset, tile, attribute, X offset) | not referenced by any instruction - the `and $EF3D` at $D63E is inside a region the tracer mis-split as code | | `$EFC6-$EFCC` | 7 B | `-` | unreferenced data - data the tracer mis-split as code: the bytes decode as five instructions, but the CDL records the CPU reading them as data; CDL: 7/7 bytes read as data | not referenced by any instruction | | `$EFCD-$EFFD` | 49 B | `-` | unreferenced data - 49 bytes; CDL: 26/49 bytes read as data | not referenced by any instruction | | `$F005-$F017` | 19 B | `-` | unreferenced data - 19 bytes; CDL: none of the 19 bytes was touched by the capture | not referenced by any instruction | | `$F01A-$F01F` | 6 B | `-` | unreferenced data - six bytes; CDL: 6/6 bytes read as data | not referenced by any instruction | | `$F020-$F029` | 10 B | `-` | unreferenced data - ten bytes; CDL: 10/10 bytes read as data | not referenced by any instruction | | `$F02A-$F034` | 11 B | `-` | unreferenced data - data the tracer mis-split as code: the bytes decode as six instructions, but the CDL records the CPU reading them as data; CDL: 11/11 bytes read as data | not referenced by any instruction | | `$F035-$F039` | 5 B | `-` | unreferenced data - five bytes; CDL: 5/5 bytes read as data | not referenced by any instruction | | `$F03A-$F049` | 16 B | `-` | unreferenced data - data the tracer mis-split as code: the bytes decode as nine instructions, but the CDL records the CPU reading them as data; CDL: 16/16 bytes read as data | not referenced by any instruction | | `$F04A-$F053` | 10 B | `-` | unreferenced data - ten bytes; CDL: 10/10 bytes read as data | not referenced by any instruction | | `$F054-$F058` | 5 B | `-` | unreferenced data - five small values ($00-$38); CDL: 5/5 bytes read as data | not referenced by any instruction | | `$F05F-$F0E1` | 131 B | `-` | unreferenced data - 131 bytes; CDL: none of the 131 bytes was touched by the capture | not referenced by any instruction | | `$F0E8-$F1D9` | 242 B | `EnemySpawnTable, EnemyFlightPathTable, EnemyPhaseJumpTable` | enemy spawn records in the same 4-byte stride as the flight-path table, the sine-wave flight path at $F136 and the phase jump table at $F1B6 | `lda $F136,y`/`$F137,y`/`$F138,y`/`$F139,y` at $D129-$D146 and $ED00-$ED1D, `lda $F1B7,x`/`lda $F1B6,x` at $F205/$F209 | | `$F1E1-$F1ED` | 13 B | `-` | code the tracer could not reach - decodes as seven consecutive instructions; CDL: none of the 13 bytes was touched by the capture | not referenced by any instruction | | `$F53C-$F55B` | 32 B | `AttributeTableAddrTable` | 16 x 16-bit PPU addresses - the attribute tables of the two on-screen nametables ($23C0-$23F8 and $2BC0-$2BF8) | `lda $F53D,x` at $F33E, `lda $F53C,x` at $F345 | | `$F5D8-$F61C` | 69 B | `MessageTextTable` | seven message offsets and the message pool (screen position + font tile indices, $FE/$FF end markers) | `lda $F5D8,y` at $F595, `lda $F5DF,y` at $F599, $F59F and $F5A5 | | `$F89E-$F8BD` | 32 B | `HandlerJumpTable` | 16 x 16-bit values used by the computed jump at $F895/$F899 | `lda $F89F,y` at $F895, `lda $F89E,y` at $F899 | | `$F8F5-$F8F9` | 5 B | `-` | unreferenced data - five bytes; CDL: none of the 5 bytes was touched by the capture | not referenced by any instruction | | `$F911-$F915` | 5 B | `-` | unreferenced data - five bytes; CDL: none of the 5 bytes was touched by the capture | not referenced by any instruction | | `$F957-$F976` | 32 B | `SpriteYPosTable` | one-byte Y positions for the player and radar sprites; the table really starts at $F956 | `lda $F956,y` at $F7CC, `sbc $F976,y` at $F7C5 | | `$F977-$F996` | 32 B | `SpriteYDeltaTable` | one-byte Y increments; the table really starts at $F976 | `sbc $F976,y` at $F7C5 (the block is one byte late) | | `$F997-$F9BC` | 38 B | `SpriteLayoutBlockPtrTable` | 19 x 16-bit pointers to the sprite-layout blocks at $F9BD | `lda $F997,y` at $F920, `lda $F998,y` at $F925 | | `$F9BD-$FAF5` | 313 B | `SpriteLayoutBlockData` | sprite-layout blocks: a count byte followed by that many 4-byte records (Y offset, tile, attribute, X offset) | not referenced by any instruction - reached through the pointer table at $F997 | | `$FC19-$FC4D` | 53 B | `ResetVarTable, InitRamSignature` | reset default values ($FC19-$FC44) and the nine-byte RAM signature at $FC45 | `lda $FC19,x` at $FC03, `lda $FC1D,x` at $FC08, `lda $FC21,x` at $FBF7, `lda $FC25,x`-`lda $FC28,x` at $FBDE-$FBED, `lda $FC45,x` at $FBC6, `cmp $FC45,x` at $FB99 | | `$FE02-$FE09` | 8 B | `GameSubModeIndexTable` | eight one-byte values | `lda $FE02,x` at $FD49 | | `$FEE6-$FF05` | 32 B | `PaletteData` | 32 bytes of NES palette data (four sprite palettes of eight bytes) | not referenced by any instruction - copied by `lda $FEE6,y` at $FB76 | | `$FF06-$FF1C` | 23 B | `TitleSpriteAttrList` | 23 OAM attribute bytes for the title screen, $00 terminated | `lda $FF06,y` at $FCAD and $FCC2 | | `$FF1E-$FFFF` | 226 B | `-` | unreferenced data - the second copy of the Namco copyright string, then the IRQ handler and the CPU vectors at $FFFA-$FFFF; CDL: 2/226 bytes read as data | not referenced by any instruction | ### What the interpretation established - **The CHR is two pattern tables.** The sprite table is at $0000 and the background table at $1000; each holds 256 tiles. Rendering the CHR shows what they contain: in the sprite table $00-$09 are the digits, $0A-$23 the letters, $24 the space, $2C-$2F the little alien creatures, $40+ the enemy sprites, $6E the solid fill tile and $6F-$72 the Xevious ground creatures; in the background table $00/$0C/$0D are the sky gradients, $2C is solid rock and $6E-$72 are the terrain shapes. - **$8000-$9FFF is the level's background tilemap.** 8192 bytes = 32 columns x 256 rows of background tile indices: the first and the last rows are a jagged run of $6F-$72 (the terrain shapes), long runs of $0C/$0D/$CD are the sky, and the sparse values in between are the terrain features. The game copies the map into the nametable as the screen scrolls and reads it back at $F447 to turn the creature tiles into sprites. No instruction names it with an absolute operand; it is reached through a computed pointer. - **The game runs a bytecode VM.** The 44-entry table at $CA0A is the opcode dispatch: the VM at $C9E3 fetches an opcode from the script pointer ($2A), compares it with $28 and jumps through the table with `jmp ($0004)` at $CA07. The 16 scripts at $ACFB-$B8AA (each prefixed with its length byte) are the stage scripts that VM executes. - **The sprite record is four bytes: Y, tile, attribute, X.** This is proven by the message routine at $F5B7 (which stores the Y base, the character, a zero attribute and the X base into $0700) and by the sprite-layout reader at $F930 (which stores Y offset, tile, attribute and X offset). $0700-$07FF is the 64-sprite buffer; the routine at $FEA3 swaps it with the copy at $0780. - **The $F136 table is a sine wave.** 32 four-byte records of two signed 16-bit deltas whose X values run 0, 50, 98, 142, 180, 212, 236, 250, 256 and back while Y runs the same series in reverse - the flight path of a sine-wave enemy, read at $D129-$D146 and $ED00-$ED1D. - **Three tables were split one byte late or early by the tracer** and are documented rather than rewritten: the 128-entry offset table at $C28F really ends at $C30E (the tracer split it at $C305), the Y-position table read by `lda $F956,y` at $F7CC really starts at $F956 (the `rts` there was decoded as code), and the Y-delta table subtracted by `sbc $F976,y` at $F7C5 really starts at $F976. - **Two jump tables overlap what the tracer split as code** - the 32-entry handler table whose first two entries are at $C440 and the type-indexed jump table at $D215. Both are documented as such rather than "fixed". - **The copyright string exists twice** - at $BEC9 inside the sprite attribute block and again at $FF1E next to the CPU vectors. ### Pass 1 notes - The committed Pass 1 split was produced by a static trace and never used the Mesen CDL in this folder. `_tools/cdl_reclass.py` was run against `xevious_mesen.cdl` on 2026-10-21: 1,158 bytes reclassified data→code, 48 code→data, 42 labels emitted, and 3 branch targets resolved to new labels. The recovery is what makes the $A74B–$B8AA and $F9xx tables readable: before it, $A6D7 (a VRAM copy loop) and $F8BD–$F915 (handler entries) sat inside `.byte` blocks. - The pointer table at $D833 is 4 entries and starts at the byte the tracer had decoded as `rti` at $D833; `lda $D833,y` / `lda $D834,y` at $D7E3/$D7E8 read it high/low. The former `ObjCodePtrTable` label at $D834 was one byte late and has been replaced by `ObjDataPtrTable` at $D833. - Two computed-dispatch mechanisms were recovered via declared jump tables: - `jmp ($fe)` at $BA88 indexes a 16-entry table at $BA8B (targets in $BAAB–$BB20 range) - `jmp ($4)` at $CA07 indexes a 44-entry table at $CA0A (targets mostly in $CA–$CB and $C0–$C3 ranges); the VM at $C9E3 only reaches opcodes below $28, so the last four entries are unused - One branch at $E40A targets $E3B5, which falls inside the operand of `jsr $CF2F` at $E3B3. Emitted as `.byte` with an explanatory comment since the target cannot be a label. ### Pass 1 residue (CDL-silent, left as found) The CDL has no opinion about these addresses (they were never fetched), so the re-split could not settle them. They are the only remaining inconsistencies and are documented rather than guessed at. - Six raw `$XXXX` call operands have no instruction boundary at the target: `jsr $08A9` at $C62D (`Sub_C626`), `jsr $01D7` at $D24B, `jsr $F230` at $D61E (`Sub_D61B`), `jmp $CE04` at $DF63 ($CE04 is two bytes into `bit $00A2` at $CE03), `jsr $21FF` at $EAA9 and `jsr $E0FF` at $EAAD (both in `Sub_EA9F`). - `Sub_C626`, `Sub_D61B`, `Sub_D63E`, `Sub_EA9F` and `$D24B` decode as code but their bytes form tables (4-byte records, pointer-table tails). They are the source of five of the six raw operands above. - `$D617–$D628` and `$EA9F–$EAC0` are therefore still emitted as instructions; their bytes read as data tables. - Six addresses contain undocumented/illegal opcodes not decoded by the tracer: $9848, $A2C3, $CD89, $E0FF, $E3B5, $F230. ## 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 `$FAF6` (`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 | |---------|---------| | `$FB00` | `WaitVblank` (falls through) | | `$FB07` | `CopyResetVars` (falls through) | | `$FB30` | `ClearVramByte` (falls through) | | `$FB32` | `ClearVramLoop` (falls through) | **NMI** is at `$FC4E` (`NmiHandler`). It is the per-frame handler; what it calls: | Address | Routine | |---------|---------| | `$FE0A` | `NmiOamDmaCopy` | | `$FE37` | `ReadJoypad` | | `$FD0E` | `NmiClearOam` | **IRQ** is at `$FF1D` (`IrqHandler`) - a different address from RESET. ## 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 | $FC4E | | RESET vector | $FAF6 | | IRQ vector | $FF1D | | ROM file | `Xevious (U).nes` | | SHA-256 | `1915fb1c30251de0c8f7913720a27b25d3ccef871851722a504d95fbb9d0ca7c` | ### Header notes - none ## Open work - **Pass 1** - complete, and re-split from the Mesen CDL on 2026-10-21 (see Pass 1 notes and residue above). - **Pass 2** - complete. All `Label_XXXX` names are replaced and every raw `jsr`/`jmp` operand that lands on an instruction boundary uses a label. Six CDL-silent operands remain raw (listed above). - **Pass 3** - complete. 143 routine entry points have semantic names; 624 internal labels remain as `Sub_XXXX` address-based names; 46 data tables are named and every one of the 129 data blocks is interpreted in the **Pass 3 data-table inventory** above. - **Data tables** - every block is accounted for, but three questions are still open and are recorded rather than guessed at: - The four 247-byte overlay tables at $A000, $A0F7, $A1EE and $A2E5 are read as a pair and written to the $0208 buffer, indexed by a tile byte read from the nametable. Which of the two bytes of the pair is the Y position and which the tile is not established. - The 41 blocks recorded as "code the tracer could not reach" are CDL-silent. They decode cleanly as instructions, but the capture never executed them, so they are left as they were found. - The `pha/pha/rts` computed jumps at $C437, $D210, $DF41, $F205 and $F895 push the two address bytes of a target and a return address on the stack. Which byte is which is inferred, not proven. - **Promotion** - done: promoted to `NROM/Xevious (U)` in commit `df11857`. ## Files | File | Purpose | |--------|---------| | `prg.s` | Pass 3 disassembly (semantic entry-point names + Sub_XXXX branch labels) | | `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 (semantic names applied at Pass 2/3) | | `Makefile` | build and byte-identity check | | `xevious_mesen.cdl` | Mesen Code Data Logger capture (CDLv2) used to correct the split | --- ## Naming residue — address-derived entry points Every `jsr`/`jmp` target in this project now carries a semantic name except **2**, which keep the honest address-derived `Sub_XXXX` form: | Label | Address | Why the dump does not settle the name | |--------|---------|-------------------------------------| | `Sub_C022` | `$C022` | The tail of a sprite-movement calculation: it loads the byte at `$8F`, adds `$FE` and saturates the result at zero on carry. The routine it belongs to computes a screen-edge wrap, but the dump does not identify which sprite field `$8F` holds. | | `Sub_DFA9` | `$DFA9` | An object-update handler: it stores into `$038B,x`, calls the script VM's compare and store opcodes, then writes `$038A,x` and continues with `$10`. The opcode dispatch makes the role of the handler's own fields hard to pin down from the instructions alone. | The other 13 entry points are named: `CopyEdgeSpritesToOam`, `CopyStageSpritesToOam`, `SelectSpriteLayoutByTile`, `WriteVramDescriptorFromTable`, `WriteVramBlock`, `WriteVramBlockAt2083`, `WriteVramBlockAt208C`, `WriteVramBlockAt2095`, `SetObjectSpriteXPositions`, `ClearObjUpdateCounters`, `SetStageScriptFlag`, `ClampFrameCounterLow` and `ClampFrameCounterHigh`. The three `WriteVramBlockAt...` names say which VRAM block each of the three descriptor entries writes; the dump does not name the pictures themselves.