# Gyromite (JUE) ## Status **Pass 1 + Pass 2 + Pass 3 (data tables).** 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. ``` ### The split | | | |---|---| | Data blocks | 52 | | Named data structures | 56 (in 25 of the blocks) | | Blocks read by no instruction | 28 (27 of them left unnamed) | The tracer could not reach a large part of this ROM, so most of the "data" is really code the tracer never got to. The inventory below says which is which: a block that decodes as a run of instructions is left unnamed and recorded as unreachable code, and a block that no instruction reads is recorded as unreferenced data with its ROM provenance. ## ROM | Property | Value | |----------|-------| | Format | iNES | | Mapper | 0 | | Board | NROM-256 | | Mirroring | Vertical | | 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 | $8079 | | RESET vector | $8000 | | IRQ vector | $8000 | | ROM file | `Gyromite (JUE).nes` | | SHA-256 | `bf1b323ba39c84b964f93127598b267ff3f16cbf99c533ae1e9b8332232b3e5b` | ### Header notes - none ## Open work - **The zero-page aliases** in `locals.inc` are the generated `ZpXX` names with no behavioural alias applied: the roles are not proven from the code alone. - **The routine names** are now semantic for 120 of the 187 `jsr`/`jmp` entry points; 67 keep the `SubC` form. The residue is listed under "Address-derived entry points" below. - **Twenty-eight of the 52 data blocks are read by no instruction**, and most of them decode as instructions the tracer never reached. They stay `.byte`. Seeding the tracer at the first byte of each would turn them back into routines. - **The record layout of `MothershipWaveLayout` and `EnemyWaveLayout`** is not established beyond the record size and count; which byte is which parameter could not be worked out from this dump. - **The tile identities behind the PPU tile numbers** in the nametable tables and the sprite-shape records are not decoded. The CHR would have to be rendered and compared against the running game (Mesen) the way `NROM/Chubby Cherub (U)` decoded its font codes. ## Address-derived entry points 120 of the 187 `jsr`/`jmp` entry points now carry a semantic name. **67 remain address-derived**, in five groups. In every case the dump itself does not reveal the routine's role, so the `SubC` form is kept rather than a name that would only guess. ### The craft that carries a mothership (20) `SubC9A5C`, `SubCA4C2`, `SubCA8DC`, `SubCA908`, `SubCA9CC`, `SubCAA22`, `SubCAA4E`, `SubCAA7B`, `SubCAA95`, `SubCAAC1`, `SubCAADB`, `SubCAB6F`, `SubCABA0`, `SubCAC23`, `SubCAC3F`, `SubCAC77`, `SubCACB0`, `SubCACC1`, `SubCACFC`, `SubCADFF`. These all work on the sixteen-byte slot at `$0600` - the slot whose state byte is `$0600`, whose sprite shape is `$0606` and whose X and Y are `$0608` and `$0609`. The slot is created with shape `$48` and takes shape `$49` when it meets a mothership slot (`CheckObjectHitsMothership` at `$AE01`), so the slot carries a mothership away from the top of the screen - but the dump never says which craft it is, and the direction bits of `$0602` are not resolvable to named controls. ### Scroll and sprite-position arithmetic (16) `SubC857B`, `SubC8859`, `SubC891A`, `SubC89BF`, `SubC8959`, `SubC8960`, `SubC8A5B`, `SubC8A72`, `SubC8A81`, `SubC8A8C`, `SubC8A9F`, `SubC8FE3`, `SubC9426`, `SubC8EFA`, `SubC8E21`, `SubC8E55`. These are the small helpers that split a screen position into a tile row and a column, add a scroll offset to the 16-bit scroll value in `Zp57`/`Zp58`, and turn a sprite shape into the X coordinate it is drawn at. They are arithmetic on values whose meaning is only known to the caller. ### Scene and mode condition tests (18) `SubC834D`, `SubC836C`, `SubC838C`, `SubC8DE5`, `SubC8E8F`, `SubC8E9C`, `SubC87BA`, `SubC87F1`, `SubC8825`, `SubC88D9`, `SubC88E7`, `SubC88F5`, `SubC8900`, `SubC890D`, `SubC980F`, `SubCA488`, `SubCA679`, `SubCA8D3`. Short tests on the scene id `Zp25`, the game mode byte `Zp4A` and the input byte `$07F5`. They raise a flag or start a sound, but which game event each test belongs to is not visible in the dump. ### The sound engine's voice set-up (4) `SubCF0A0`, `SubCF0A4`, `SubCF0A8`, `SubCF0AC`. Each one loads a mode byte (`$00`, `$08`, `$0C`, `$04`), saves the sequence pointer in `ZpFB`/`ZpFC` and the envelope value `$40` in `ZpFA`. Which APU channel each mode belongs to cannot be established from the dump, so they keep their address-derived names. ### The individual sound effects (6) `SubCF77D`, `SubCF794`, `SubCF7A6`, `SubCF7BF`, `SubCF7C8`. These start one of the game's sound effects on the first pulse voice. The effect is chosen by a request bit and its command list is an entry in the table at `$F7D1`; the dump does not say which game event each effect belongs to. `SubCF44F` is a jump into the middle of the sound engine's voice dispatcher and is left alone for the same reason. ### Other (3) `SubC8163` is inside the block the tracer could not decode (the undocumented `$B2` opcode) and its instructions are not trustworthy. `SubCB20A` masks the `PPUMASK` value but the effect of the three bits it clears is not visible. `SubCFFF7` is a one-instruction trampoline into `UpdateSoundEngine`. ## 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 | |---------|---------| | `$800A` | `SubC800A` (falls through) | | `$8017` | `SubC8017` (falls through) | | `$8017` | `SubC8017` | **NMI** is at `$8079` (`NmiHandler`). It is the per-frame handler; what it calls: | Address | Routine | |---------|---------| **IRQ** is at `$8000` (`Reset`) - the same address as RESET, so the IRQ vector reaches the reset path. ## Pass 3 data-table inventory Every `; ---- data $XXXX-$YYYY ----` region in `prg.s` is listed here. The tracer's data blocks are contiguous runs of bytes it never reached, so a block can hold a table, a table *and* unreached code, or code alone. Where a block holds several tables, each one has its own label and the row names them all. ### How the tables were read - `$0600-$06FF` is the game's object array: sixteen-byte slots at `$0600`, `$0610`, `$0620` ... Each slot has a state byte at `+0`, a type/shape byte at `+6`, X and Y at `+8`/`+9`, a sprite tile at `+10` and a direction mask at `+11`. - `$06E0-$06EF` is the player craft's state block: X at `$06E8`, Y at `$06E9`, a direction mask at `$06E2`/`$06E7` and the current sprite tile at `$06E6`. - `$0200-$02FF` is the OAM shadow that the NMI handler DMA's to the PPU. `$02E0-$02FF` is the four-slot strip the game writes the four sixteen-pixel-wide craft at the top of the screen into. ### Inventory | Address | Size | Name | Structure | Read by | |---------|------|------|-----------|---------| | `$80D9-$80DC` | 4 | `OamInitialSpriteData` | 4 bytes: the power-on contents of OAM sprite 0, stored back to front - `$80DC`→`$0200` (X = `$88`), `$80DB`→`$0201` (tile `$20`), `$80DA`→`$0202` (attributes `$FF`), `$80D9`→`$0203` (Y = `$2D`) | `lda $80D9,x` at `$8081` (stored with `sta $0200,x` at `$8084`; the shadow is DMA'd by `sta OAMDMA` at `$8091`) | | `$814E-$8162` | 21 | - | unreferenced; the tracer stopped at `$814E` because the first byte `$B2` is the undocumented `LDX #imm`, which `nesdis.py` does not decode. The bytes are instructions - `ldx #$5D`, `stx $1D`, `ldx $CB`, `stx $EF`, `stx $09`, `ldx #$52`, `stx $91,y`, `stx $27,y`, `ldx #$09` x3 - the tail of the routine that starts at `$8134` | not referenced by any instruction | | `$8175-$8330` | 444 | - | unreferenced; code the tracer could not decode (the undocumented `$B2` = `LDX #imm` appears 20 times). It continues the routine that begins at `$8163` | not referenced by any instruction | | `$839D-$857A` | 478 | - | unreferenced; decodes as 215 consecutive instructions - code the tracer could not reach, not data | not referenced by any instruction | | `$85B4-$87B9` | 518 | - | unreferenced; decodes as 238 consecutive instructions once the undocumented `$B2` opcode is allowed - code the tracer could not reach | not referenced by any instruction | | `$8A11-$8A5A` | 74 | `MothershipWaveLayout` (`$8A11`), `EnemyWaveLayout` (`$8A2A`) | one 74-byte stream of per-wave parameters read with two different strides. `$8A11-$8A29` = 5 records x 5 bytes, `$8A2A-$8A5A` = 7 records x 7 bytes. Each record is copied into a block of RAM slots 24 (`$18`) bytes apart: the 5-byte record at `$8A11 + 5*Zp54` supplies one byte to each of the five slots at `(Zp57)+$00/$18/$30/$48/$60`, the 7-byte record at `$8A2A + 7*Zp54` supplies one byte to each of seven such slots. The byte values are 8-bit parameters in `$00-$15`; which parameter sits in which slot is not established from this dump | `lda $8A11,x` at `$89E3`, `lda $8A2A,x` at `$8A07` | | `$8AB4-$8D03` | 592 | `NametableRow10Tiles` (`$8AB4`), `NametableRow14Tiles` (`$8B18`), `NametableRow10TilesMode3` (`$8BDC`), `NametableRow14TilesMode3` (`$8C40`) | four tables of PPU nametable tile indices: `$8AB4` = 5 x 20-byte rows, `$8B18` = 7 x 28-byte rows, `$8BDC` = 5 x 20-byte rows and `$8C40` = 7 x 28-byte rows (the last two are the set used in game mode 3). Each record is written to the PPU data port - the 20-byte rows to VRAM `$20A2`, the 28-byte rows to `$20E2`. The tile numbers used are `$30` (blank), `$3A-$3F` and `$44-$4B` in the first pair and `$86-$93` in the mode-3 pair; the ROM does not decode them further | `lda $8AB4,y` at `$8887`, `lda $8BDC,y` at `$8893`, `lda $8B18,y` at `$88C2`, `lda $8C40,y` at `$88CE` | | `$8F21-$8FA9` | 137 | - | unreferenced; decodes as 56 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$903B-$9095` | 91 | `EnemyWaveXPositions` (`$903B`), `EnemyWaveLaneIndices` (`$9041`), `EnemyWaveFlagOffsets` (`$9047`) | `$903B-$9040` = 6 x 8-bit X positions of the six enemy-wave slots, twenty pixels apart (`$88`..`$EC`); `$9041-$9046` = 6 x 8-bit lane indices (`$03,$00,$05,$01,$04,$02`); `$9047-$9049` = 3 x 8-bit RAM offsets (`$00,$10,$20`). `$904A-$9095` is code the tracer could not reach - the code/data boundary is one byte early, `$904A` being the opcode of `lda $0618` | `lda $903B,y` at `$8FB3`, `lda $9041,y` at `$8FB9`, `ldy $9047,x` at `$9031` | | `$9109-$911D` | 21 | - | unreferenced; decodes as 12 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$9168-$916D` | 6 | `EnemyShapeIdTable` | 6 x 8-bit sprite-shape ids for the six enemies of a wave (`$18,$0E,$18,$0F,$18,$10`); the id is doubled and added to `$24` to index `SpriteShapePointerTable` | `lda $9168,y` at `$90B0` (stored to the enemy's type byte `$0606`) | | `$9221-$9228` | 8 | `MothershipStartXPositions` (`$9221`), `MothershipStartTypeIds` (`$9225`) | two parallel 4-byte tables for the four mothership slots: the X position of each slot, sixteen pixels apart (`$04,$14,$24,$34`), and a per-slot type byte (`$01,$00,$02,$00`). The slots live in the `$0670`-block; their Y is the constant `$2A` | `lda $9221,y` at `$91B1`, `lda $9225,y` at `$91B7` | | `$92F7-$92FA` | 4 | `PlayerShipTileIds` | 4 x 8-bit PPU tile ids (`$39,$3A,$3B,$3C`) for the player craft's tile byte `$06E6` | `lda $92F7,y` at `$92AF` | | `$93ED-$93FC` | 16 | `BitMaskValueTable` (`$93ED`), `PlayerShipTileIdsAlt` (`$93F9`) | `$93ED-$93F8` = 12 x 8-bit values indexed by a one/two/four/eight bit mask - the code loads the table with the mask in Y, where Y is 1, 2, 4 or 8; `$93F9-$93FC` = 4 x 8-bit PPU tile ids (`$45,$45,$46,$47`) for the player craft's tile byte `$06E6` | `lda $93ED,y` at `$93CB`, `lda $93EF,y` at `$93A1` and `$93B4`, `lda $93F9,y` at `$9264` | | `$9466-$9468` | 3 | `EnemyCraftTileIds` | 3 x 8-bit PPU tile ids (`$44,$4C,$54`) for the enemy craft slot at `$06B0` | `lda $9466,y` at `$9406` | | `$9605-$9607` | 3 | `PlayerShipTileIdsAlt2` | 3 x 8-bit PPU tile ids (`$1F,$4F,$4F`) for the player craft's tile byte `$06E6` | `lda $9605,y` at `$95FB` | | `$9A44-$9A5B` | 24 | `PpuAttributeBytesMode0` (`$9A44`), `PpuAttributeBytesOtherModes` (`$9A4C`), `PpuAttributeBytesMode3` (`$9A54`) | three parallel 8-byte tables of PPU attribute bytes (palette and pattern-table bits: `$05`,`$06`,`$09`,`$0A`), one byte per attribute cell of the row being written. The game picks the set from the mode byte `Zp4A`: mode 0 uses `$9A44`, mode 3 uses `$9A54`, the other modes use `$9A4C` | `lda $9A44,x` at `$9A25`, `lda $9A54,x` at `$9A2C`, `lda $9A4C,x` at `$9A33` (all stored to `PPUDATA` at `$9A38`) | | `$9B16-$A07D` | 1384 | `SpriteShapeIndexTable` (`$9B16`), `SpriteShapePointerTable` (`$9B24`), `SpriteShapeRecordTable` (`$9BD8`) | `$9B16-$9B23` = 14 x 8-bit sprite-shape ids (`$48`, six x `$15`, four x `$1E`, three x `$1F`); `$9B24-$9BD7` = 90 x 16-bit little-endian pointers to the shape records, the pointer address computed as `$9B24 + 2 * shape id + $24`; `$9BD8-$A07D` = the shape records themselves - a 2-byte little-endian pointer to a tile list, one flags byte, then 5 or 6 PPU tile ids. The records are variable length (8 or 9 bytes) and the tile list ends in a byte whose top nibble is `$F` | `lda $9B16,y` at `$9A74` (the pointer address is computed at `$9A7C`-`$9A87`, the record is read at `$9A89`-`$9A9F`) | | `$A161-$A164` | 4 | `PlayerShipTileIdsAlt3` | 4 x 8-bit PPU tile ids (`$1E,$45,$46,$47`) for the player craft's tile byte `$06E6` | `lda $A161,y` at `$A157` | | `$A2F4-$A2FE` | 11 | - | unreferenced; decodes as 5 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$A310-$A317` | 8 | `PlayerShipTileIdsSet1` (`$A310`), `PlayerShipTileIdsSet2` (`$A313`), `PlayerShipTileIdsSet3` (`$A316`) | three small PPU tile-id lists written to the player craft's tile byte `$06E6`: 3 bytes (`$2A,$2B,$2C`), 3 bytes (`$27,$28,$29`) and 2 bytes (`$2D,$2E`) | `lda $A310,y` at `$A22E`, `lda $A313,y` at `$A290`, `lda $A316,x` at `$A2C8` and `$A2ED` | | `$A470-$A47D` | 14 | - | unreferenced; decodes as 6 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$A4E5-$A52D` | 73 | - | unreferenced; decodes as 36 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$A575-$A580` | 12 | `OamSpriteSlotOffsets` (`$A575`), `OamSpriteLeftXPositions` (`$A579`), `OamSpriteRightXPositions` (`$A57D`) | three parallel 4-byte tables for the four 16x8 craft drawn along the top of the screen: the OAM byte offset of each pair inside the `$02E0` strip (`$00,$08,$10,$18`) and the X positions of the two tiles of each pair (`$B8,$C8,$D8,$E8` and `$C0,$D0,$E0,$F0`, eight pixels apart). The Y is the constant `$1E` and the tiles are `$9E` and `$9F` | `ldy $A575,x` at `$A53D`, `lda $A579,x` at `$A552`, `lda $A57D,x` at `$A56B` | | `$A608-$A678` | 113 | - | unreferenced; the first byte is the undocumented `$B2` (`LDX #imm`) that `nesdis.py` cannot decode - code the tracer could not reach | not referenced by any instruction | | `$A6C1-$A763` | 163 | `HitCountTable` (`$A6FC`) | `$A6C1-$A6FB` is code the tracer could not reach (it starts with the undocumented `$B2`); `$A6FC-$A763` = a byte table of hit counts - `$03` and `$04` for the first 26 entries, then a run of `$00`, one `$40`, and more `$03`/`$04`. The code reads it with the index `0 or $0D + Zp49` (`Zp49` counts 0..`$0C`), so only the first 26 entries are reachable | `lda $A6FC,x` at `$A692` (stored to `Zp23`) | | `$AB6C-$AB6E` | 3 | `WaveConditionFlags` | 3 x 8-bit condition flags (`$80,$88,$92`); bit 7 is tested as the sign and bit 0 as the carry after `lsr a` | `lda $AB6C,y` at `$AB32` | | `$ACAA-$ACAF` | 6 | - | unreferenced; decodes as 3 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$ACCB-$ACEA` | 32 | `EnemyShapeIdTableA` (`$ACCB`), `EnemyShapeIdTableB` (`$ACD7`), `EnemyShapeIdTableC` (`$ACE3`), `EnemyShapeIdTableD` (`$ACE9`) | four lists of sprite-shape ids - the index into `SpriteShapePointerTable`: 12 bytes (`$01,$04,$03,$02,$04,$03,$2F,$32,$31,$30,$32,$31`), 12 bytes (`$06,$09,$08,$07,$09,$08,$33,$36,$35,$34,$36,$35`), 6 bytes (`$57,$55,$58,$57,$56,$58`) and 2 bytes (`$0B,$0C`). All of them are stored to the enemy's type byte `$0606` | `lda $ACCB,y` at `$AC36`, `lda $ACD7,y` at `$AB97`, `lda $ACE3,y` at `$AB86`, `lda $ACE9,x` at `$AC6B` and `$ACA3` | | `$AD6A-$ADFE` | 149 | - | unreferenced; decodes as 67 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$AEA8-$AF13` | 108 | `OamPrioritySpriteOffsets` (`$AEA8`) | `$AEA8-$AEAD` = 6 x 8-bit offsets into the `$0200` OAM shadow (`$00,$04,$08,$0C,$10,$14`); the code ORs bit 5 into the byte at `$025E + offset`, i.e. sets the sprite's priority flag. `$AEAE-$AF13` is code the tracer could not reach | `ldy $AEA8,x` at `$AE9B` | | `$B1CE-$B1D9` | 12 | - | unreferenced; decodes as 7 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B217-$B21F` | 9 | - | unreferenced; decodes as 4 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B227-$B22F` | 9 | - | unreferenced; decodes as 5 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B25C-$B28A` | 47 | - | unreferenced; decodes as 26 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B2BE-$B2C1` | 4 | - | unreferenced; decodes as 2 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B2F8-$B2FB` | 4 | - | unreferenced; decodes as 2 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$B34B-$B34B` | 1 | - | the first byte of a five-`ASL A` chain (`$B34B-$B34F` = `$0A` x5) that follows the `rts` at `$B34A`; the tracer's split put `$B34B` with the data and `$B34C-$B34F` with the code | not referenced by any instruction | | `$B351-$B351` | 1 | - | the first byte of a five-`INX` chain (`$B351-$B355` = `$E8` x5) between the `rts` at `$B350` and the `rts` at `$B356`; an instruction the tracer's split cut in the wrong place, not data | not referenced by any instruction | | `$B35E-$F09F` | 15682 | `PlayfieldColumnPointerTable` (`$B35E`), `PlayfieldSceneryRecords` (`$B374`), `ModeParameterTable` (`$BE8C`), `NametableTileData` (`$BF04`), `AttributePaletteBytes` (`$BF34`), `ModeParameterTableMode3` (`$DCB9`), `NametableTileDataMode3` (`$DD04`), `AttributePaletteBytesMode3` (`$DD34`), `MusicNotePeriodHighBytes` (`$F000`), `MusicNotePeriodLowBytes` (`$F001`), `MusicTrianglePeriodTable` (`$F060`), `MusicNoteLengthTable` (`$F076`) | the unused upper half of the 32 KB PRG, which holds the game's data tables. `$B35E-$B373` = 11 x 16-bit little-endian pointers, one per playfield column, into the scenery records at `$B374-$B4FE` (X/Y/tile triplets, one record per column, reached only through this pointer table). `$B374-$B4FE` = the per-column scenery records themselves. `$BE8C` = a run of 8-bit per-mode parameters, indexed by `Zp31[]` and read by the helper `GetModeParameter`; `$DCB9` = the mode-3 counterpart (0, 1, 2, 3 ...). `$BF04-$BF33` = 48 bytes of nametable tile indices for the narrow playfield strip (`$30` = blank), read four bytes at a time by the scroll copy loop at `$9700-$9753`, which writes two bytes to one row and two to the row below; `$DD04` = the same strip for the mode-3 screen. `$BF34` / `$DD34` = 8-bit values the attribute-write routine at `$98FD` reads at +6, +7 and +`$0C`, shifts right two and combines with the pattern-table bits of `PpuAttributeBytesMode0` before sending the byte to `PPUDATA` (the first twelve bytes of the first table are the palette values `$C0`/`$40`/`$80`/`$00`). `$F000` / `$F001` = the high and low bytes of the pulse-channel music note periods, interleaved; the period of note Y is `($F000[Y] \| $08) << 8 \| $F001[Y]`, a descending scale. `$F060-$F075` = 11 x 16-bit little-endian triangle-channel note periods (`$0069` ... `$003E`, with `$0389` as the first entry). `$F076-$F09F` = 42 x 8-bit note lengths for the music player (`$03,$06,$0C,$18,$30,...`). The rest of the block is unreferenced | `lda $B35E,y` at `$AF2A`, `ldx $B35F,y` at `$AF2D`; `lda $BE8C,x` at `$B0A3`, `lda $DCB9,x` at `$B0AA`; `lda $BF04,x` at `$9716`, `lda $BF05,x` at `$9725`, `lda $BF06,x` at `$9741`, `lda $BF07,x` at `$9750`; `lda $BF34,x` at `$991A`, `$993B`, `$9963`, `$9988`, `$99FD`, `$9A1C`; `lda $DD04,x` at `$970D`, `lda $DD05,x` at `$971C`, `lda $DD06,x` at `$9738`, `lda $DD07,x` at `$9747`; `lda $DD34,x` at `$9911`, `$9932`, `$995A`, `$997F`, `$99F4`, `$9A13`; `lda $F000,y` at `$F1B7` and `$F274`, `lda $F001,y` at `$F1AF` and `$F26C`; `lda $F076,y` at `$F189` | | `$F0F3-$F111` | 31 | `NoiseSfxRegisterData` (`$F100`) | `$F0F3-$F0FF` = 13 bytes of `$FF` filler, unreferenced. `$F100-$F111` = 6 x 3-byte noise-channel register sets, interleaved: the control byte, the period byte and the length-counter byte are read at `$F100+y`, `$F101+y` and `$F102+y` with the same index, so the three fields of one entry are one byte apart | `lda $F100,y` at `$F210` (→ `APUNOISECTRL`), `lda $F101,y` at `$F216` (→ `APUNOISEPERIOD`), `lda $F102,y` at `$F21C` (→ `APUNOISELENGTH`) | | `$F32F-$F336` | 8 | - | unreferenced; 2 x 4-byte APU pulse register sets (`$80,$7F,$80,$48` and `$80,$7F,$81,$48`) of the same shape as the noise table at `$F100` | not referenced by any instruction | | `$F34D-$F34E` | 2 | - | unreferenced; two bytes (`$A9,$DF`) between two instructions. They read as a 16-bit pointer (`$DFA9`) but nothing in this dump points there | not referenced by any instruction | | `$F384-$F38B` | 8 | - | unreferenced; 2 x 4-byte APU pulse register sets (`$0F,$7F,$0F,$08` and `$04,$7F,$0F,$08`) | not referenced by any instruction | | `$F3ED-$F43A` | 78 | `SfxPulse1SweepTable` (`$F3ED`), `SfxNoteDurationTable` (`$F3F4`) | `$F3ED-$F3F3` = 7 x 8-bit APU pulse-1 sweep/note bytes (`$83,$8B,$83,$8B,$83,$8B,$83`); `$F3F4-$F43A` = 71 x 8-bit note durations (`$03,$04,$03,$04,$03,$04,$00`, then further note data). Both are indexed by the same note counter `$05E0`, and a zero duration ends the sequence - the first sound effect is the seven notes at `$F3ED` with the seven durations at `$F3F4` | `lda $F3ED,y` at `$F49B` (→ `APUPULSE1SWEEP`), `lda $F3F4,y` at `$F4A1` (→ the delay counter `$05EA`) | | `$F580-$F597` | 24 | - | unreferenced; six 16-bit words, of which `$93D4`, `$93D5`, `$95B4`, `$929F`, `$9BD6` and `$9A1F` point into the shape-record area at `$9B16-$A07D` and the other six do not point anywhere in the PRG image. The layout could not be established | not referenced by any instruction | | `$F63F-$F65F` | 33 | `SfxPulseSweepTable` (`$F63F`) | `$F63F-$F653` = 21 x 8-bit APU sweep values for a sound effect - `$9C` and `$93` alternating ten times, then `$00` to end the sequence. `$F654-$F65F` is code the tracer could not reach | `lda $F63F,y` at `$F62C` (→ `APUPULSE1SWEEP` and `APUPULSE2SWEEP`) | | `$F67F-$F68F` | 17 | - | unreferenced; decodes as 7 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$F699-$F6B1` | 25 | - | unreferenced; decodes as 11 consecutive instructions - code the tracer could not reach | not referenced by any instruction | | `$F6C3-$F6CA` | 8 | - | unreferenced; the tail of the block overlaps the start of the instruction `lda $F2` at `$F6C9`. `$F6C5-$F6C8` has the shape of one 4-byte APU pulse register set (`$07,$7F,$43,$38`), like the tables at `$F32F` and `$F384` | not referenced by any instruction | | `$F7E4-$FFF6` | 2067 | `DeveloperCreditString` (`$FFD0`) | the tail of the fixed bank. `$FFD0-$FFDF` = 16 bytes of ASCII, `" HIROKAZU.TANAKA"` - the programmer credits; `$FFE0-$FFEF` = spaces and `$FFF0-$FFF6` = `$FF` filler. The rest of the block is unreferenced | not referenced by any instruction | | `$FFFA-$FFFF` | 6 | `InterruptVectorTable` | 3 x 16-bit little-endian CPU addresses: NMI `$8079`, RESET `$8000`, IRQ `$8000` | the CPU reads it, not an instruction in this dump | ### Notes on the blocks that are not tables - Twenty-eight of the fifty-two blocks are read by no instruction in this dump (twenty-seven of them are left unnamed; the twenty-eighth is the interrupt vector table, which the CPU reads rather than an instruction). Most of the unnamed ones decode as a run of instructions (or fail to decode only because of the undocumented `$B2` = `LDX #imm`), so they are code the tracer never reached rather than data. They are left unnamed here on purpose; seeding the tracer at the first byte of each would turn them back into routines. - The two one-byte regions at `$B34B` (`$0A` = `ASL A`) and `$B351` (`$E8` = `INX`) are the first bytes of `asl a` and `inx` chains that the tracer's split cut in the wrong place. They are instructions, not stray bytes. - `$F7E4-$FFF6` also holds the game's music data and the tail of the sound tables, but no instruction in this dump names an address inside those regions; they are reached through pointers this dump does not follow. - `$903B-$9095` is the one block where the tracer's code/data boundary is one byte early: `$904A` is the opcode of `lda $0618`, and the tracer put it with the data instead of with the code at `$904B`. ## 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 |