Pass 3 for NES PowerPad Test Card (U): name all data tables and VramWrite streams
- Decoded the VramWrite ($E1CC) stream format: <addr hi> <addr lo> <count> <bytes>, $00 terminator - Named all 9 payload streams ($E4CC-$E7C2, no gaps/overlaps) plus VramWriteSourcePointerTable at $F000 - Split PadBitTableLives into Player1TileTable ($E4B4) and Player2TileTable ($E4C0), 12 entries each (Y=0..11) - Decoded CHR font (digits $30-$39, letters $3A-$52, space $5F; 'W' missing from the A-Z run) and recovered on-screen text including 'PRESS A TO TEST SIDE-A' / 'SIDE-B' - Documented that the 16 KiB PRG is two byte-identical 8 KiB halves; $C000 copy is dead - Documented 7 unreached subroutines inside the live code region (kept as .byte per Pass-1 policy) - Fixed a stray duplicate sentence and stale _wip paths in root OVERVIEW.md Byte-identical ROM verified.
This commit is contained in:
1 parent
3ef16a6f99
commit
4c644d2a20
23 files changed
+17290
-507
No files matched your search
@@ -40,7 +40,7 @@ This document describes the execution flow of the disassembled NES PowerPad Test
|
||||
|------|--------|-------------|
|
||||
| Pass 1 | Complete | Code/data split — entire PRG bank classified as traced code (~7.2%) or explicit `.byte` data (~92.8%) with `; CPU:$xxxx PRG:$xxxx` annotations |
|
||||
| Pass 2 | Complete | Routine headers added for all labeled positions; key routines semantically named (`Reset`, `NmiHandler`, `VramWrite`, `ReadPad`, `ProcessPads`, etc.); zero-page aliases in `locals.inc` |
|
||||
| Pass 3 | Complete | Data tables/structures identified and named (`PaletteData` at $E121, `PadBitTableLives` at $E4B4); remaining `Label_Exxxx` references are internal branch targets within routines |
|
||||
| Pass 3 | Complete | All data tables named: `VramWriteSourcePointerTable` ($F000, 9 streams), `Player1TileTable`/`Player2TileTable` ($E4B4/$E4C0), `PaletteData` ($E121), and all nine VramWrite payload streams (`PowerPadSideAButtonGraphics`, `PanelFrameTiles`, `StatusMessageText`, `SideATestPromptText`, …). Screen text decoded from CHR. Remaining 46 `Label_Exxxx` are internal loop/branch targets. |
|
||||
|
||||
---
|
||||
|
||||
@@ -155,33 +155,67 @@ Full list in `copilot/locals.inc`.
|
||||
|
||||
## 8. Data Tables
|
||||
|
||||
| Table | Address | Description |
|
||||
|-------|---------|-------------|
|
||||
| `PaletteData` | $E121 | 32-byte palette data loaded into PPU palette RAM |
|
||||
| `PadBitTableLives` | $E4B4 | 70-byte pad bit lookup table; `DrawScore` reads from offset $0C ($E4C0) |
|
||||
| Pattern pointers | $F000–$F013 | Pointer pairs loaded by `LoadPatternTable1`–`5` routines |
|
||||
### 8.1 Direct tables
|
||||
|
||||
| Table | Address | Size | Description |
|
||||
|-------|---------|------|-------------|
|
||||
| `PaletteData` | $E121 | 32 | Palette loaded into PPU $3F00-$3F1F by `LoadPalette` |
|
||||
| `Player1TileTable` | $E4B4 | 12 | PPUADDR low bytes for player 1, indexed Y=0..11 |
|
||||
| `Player2TileTable` | $E4C0 | 12 | Same for player 2; `$00` = "skip this button" |
|
||||
| `VramWriteSourcePointerTable` | $F000 | 18 | 9 little-endian stream pointers, one per `LoadPatternTable*` / draw call site |
|
||||
|
||||
### 8.2 VramWrite payload streams
|
||||
|
||||
`VramWrite` ($E1CC) reads records of `<addr hi> <addr lo> <count> <count bytes>`, terminated by a `$00` at a record boundary. All nine streams tile `$E4CC-$E7C2` with no gaps and no overlaps:
|
||||
|
||||
| Slot | Ptr | Stream label | Address | Records | Writes to |
|
||||
|------|-----|--------------|---------|---------|-----------|
|
||||
| 0 | $F000 | `PowerPadSideAButtonGraphics` | $E54F | 2 | $2083, $20A3 — 52 tile graphics in pattern table 0 |
|
||||
| 1 | $F002 | `PowerPadButtonLabelTiles` | $E58A | 4 | $2136, $2156, $2236, $2256 — button captions |
|
||||
| 2 | $F004 | `PanelFrameTiles` | $E5B3 | 8 | $2124…$22C4 — panel borders for six indicator boxes |
|
||||
| 3 | $F006 | `SideAPressedButtonRow` | $E64C | 6 | $2184…$22A4 — side-A button caps |
|
||||
| 4 | $F008 | `SideAPanelButtonRow` | $E6BF | 6 | same rows, alternate layout |
|
||||
| 5 | $F00A | `StatusMessageText` | $E732 | 3 | $2121, $2163, $2183 — status messages |
|
||||
| 6 | $F00C | `Player1ButtonIconStream` | $E4CC | 2 | $2196, $21B6 |
|
||||
| 7 | $F00E | `Player2ButtonIconStream` | $E4E3 | 2 | $2296, $22B6 |
|
||||
| 8 | $F010 | `SideATestPromptText` | $E790 | 2 | $2304, $2344 — the prompt rows |
|
||||
|
||||
### 8.3 Screen text (decoded from CHR)
|
||||
|
||||
Font mapping read directly out of `chr.bin` pattern table 1: digits `$30-$39` = `'0'-'9'`, letters `$3A-$52` = `'A'-'Z'` (note **`W` is absent** from the `A-Z` run), `$57` = `-`, `$58` = `/`, `$59` = `\`, `$5F` = space.
|
||||
|
||||
| Address | Text |
|
||||
|---------|------|
|
||||
| $2121 | `CONNECT POWER PAD <$5D> CONTROLLER` |
|
||||
| $2163 | `<$60>IF POWER PAD IS CONNECTED<$62>` |
|
||||
| $2183 | `<$61> IC MAY BE BAD <$53> <$63>` |
|
||||
| $2304 | `PRESS A TO TEST SIDE-A` |
|
||||
| $2344 | `PRESS B TO TEST SIDE-B` |
|
||||
|
||||
Tiles `$53-$5E` are truncated glyph fragments in CHR ROM — including the `W` of `POWER`, which sits at `$5E` and renders incomplete. The original cartridge therefore displays partial marks at those positions; this is a ROM authoring artifact, reproduced faithfully.
|
||||
|
||||
---
|
||||
|
||||
## 9. Build
|
||||
|
||||
```bash
|
||||
cd "_wip/NES PowerPad Test Card (U)/copilot"
|
||||
make # → ca65 + ld65 + cmp reconstructed_prg.bin prg.bin → "BYTE-IDENTICAL"
|
||||
cd "NES PowerPad Test Card (U)/copilot"
|
||||
make # → ca65 + ld65 + cmp reconstructed.nes rom.nes → "Byte-identical ROM verified."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Notes
|
||||
|
||||
- The PRG is approximately 7% code / 93% data. Most of the PRG bank ($C000–$DFFF, $E54F–$FFFF) is $FF-filled test pattern data.
|
||||
- The NMI handler drives per-frame updates; the main loop (`Reset` at $E058) spins waiting for vblank and frame counter changes.
|
||||
- `PadBitTableLives` at $E4B4 is a shared lookup table — `DrawLives` reads from base $E4B4, `DrawScore` reads from offset $0C ($E4C0).
|
||||
- IRQ vector points to $E000 (Reset) and is effectively unused.
|
||||
- **The 16 KiB PRG is two byte-identical 8 KiB halves.** `prg[0x0000:0x2000] == prg[0x2000:0x4000]` is exactly true. Both halves hold the same program, pointer table, and vector set. The vectors point at `$E06E`/`$E000`/`$E000`, so the CPU always enters the `$E000` copy; nothing references `$C000-$DFFF`, so the first copy is dead and is kept as classified `.byte` data rather than disassembled.
|
||||
- Unreached gaps inside the live code region decode as valid subroutines (PPUMASK show/hide background, PPUCTRL NMI-disable, frame-counter digit tiles, `ldx #$80 / txs`). Per Pass-1 policy they stay `.byte` data; each is decoded in the `prg.s` header comment block.
|
||||
- The PRG is approximately 7.2% code / 92.8% data. Most data is `$FF` padding from `$E7C3-$EFFF` and `$F012-$FFF9`.
|
||||
- The NMI handler drives per-frame updates; the main loop spins waiting for vblank and frame-counter changes.
|
||||
- IRQ vector points to $E000 (`Reset`) and is effectively unused.
|
||||
|
||||
---
|
||||
|
||||
## 11. Next Steps
|
||||
|
||||
- **Promotion** — move to a top-level `NES PowerPad Test Card (U)/` folder, add `header.s` / `chr.s` + full-ROM `make` target (as e.g. `Burger Time (U)`), then join the root `OVERVIEW.md` numbered inventory.
|
||||
- **Optional deeper Pass 3 work** — extract the pattern pointer data at $F000+ into labeled `.byte` blocks; refine zero-page aliases with more specific roles.
|
||||
- Optional: refine the `Zp05`–`Zp0F` aliases now that `ProcessPads`/`DrawScore`/`DrawLives` semantics are known (pad-state bytes vs. shift counters).
|
||||
- Optional: `$E4CC-$E4F9` holds two near-identical icon streams differing only in two bytes; could be collapsed to a parameterized table in a future reconstruction, but the byte form is preserved as-is.
|
||||
Reference in new issue
Block a user