Files
disasm/_wip/Pac-Man (U)/OVERVIEW.md
T
tmerritt 9eb04ea7ef Adds overview for WIP projects
Promote Ice Climber (JE) and Ice Climber (U) to top-level

- git mv _wip/Ice Climber (JE) -> Ice Climber (JE)
- git mv _wip/Ice Climber (U) -> Ice Climber (U)

- Added header.s / chr.s (one-line .incbin each)
- Added HEADER/PRG/CHR linker.cfg with proper memory layout
- Added copilot/rom.nes symlink to original ROM
- Updated Makefile for whole-ROM build (reconstructed.nes vs rom.nes)
- Updated _tools paths from ../../../_tools/ to ../../_tools/

Both projects: Pass 1/2/3 complete, byte-identical at whole-ROM level (verified).

Root OVERVIEW.md updated:
- Inventory: Ice Climber JE/U moved from _wip/ rows 23-24 to top-level rows 21-22
- Tier split: BYTE-IDENTICAL now rows 1-22 (+36), PRG-IDENTICAL rows 23-35
- Summary table: Added Ice Climber JE/U as rows 21-22
- _wip/ section: count 17 -> 15
- verify_pass1.py scope: 19 -> 22 top-level projects

All 22 top-level projects verified byte-identical.

Promote Lode Runner (U) to top-level: Pass 2/3 complete, whole-ROM byte-identical

- git mv _wip/Lode Runner (U) -> Lode Runner (U)

- Added header.s / chr.s (one-line .incbin each)
- Added HEADER/PRG/CHR linker.cfg with proper memory layout
- Added copilot/rom.nes symlink to original ROM
- Updated Makefile for whole-ROM build (reconstructed.nes vs rom.nes)

Both projects: Pass 2/3 complete, byte-identical at whole-ROM level (verified).

Root OVERVIEW.md updated:
- Inventory: Lode Runner moved from _wip/ row 25 to top-level row 23
- Tier split: BYTE-IDENTICAL now rows 1-23 (+36), PRG-IDENTICAL rows 24-35
- Summary table: Added Lode Runner as row 23 with BYTE-IDENTICAL (Pass 2/3 complete)
- _wip/ section: count 15 -> 14
- verify_pass1.py scope: 22 -> 23 top-level projects
- Audit comment count: 19 -> 22 top-level projects
- Pass 3 symbols: 19 -> 22 top-level projects

All 23 top-level projects verified byte-identical.

TODO.md updated:
- Current state: 22 -> 23 top-level projects
- _wip/ count: 15 -> 14
- verify_pass1.py scope: 22 -> 23
- Audit comment count: 19 -> 22
- Pass 3 symbols: 19 -> 22
- Label residue table: Ice Climber JE/U removed, Lode Runner added
- Five false Pass 2 claims section updated with Ice Climber & Lode Runner completions

Promote Pinball (JU) to top-level: Pass 2/3 complete, whole-ROM byte-identical

- git mv _wip/Pinball (JU) -> Pinball (JU)

- Added header.s / chr.s (one-line .incbin each)
- Added HEADER/PRG/CHR linker.cfg with proper memory layout
- Added copilot/rom.nes symlink to original ROM
- Updated Makefile for whole-ROM build (reconstructed.nes vs rom.nes)

Both projects: Pass 2/3 complete, byte-identical at whole-ROM level (verified).

Root OVERVIEW.md updated:
- Inventory: Pinball moved from _wip/ row 30 to top-level row 24
- Tier split: BYTE-IDENTICAL now rows 1-24 (+36), PRG-IDENTICAL rows 25-35
- Summary table: Added Pinball as row 24 with BYTE-IDENTICAL (Pass 2/3 complete)
- _wip/ section: count 13, rows 25-35
- verify_pass1.py scope: 23 -> 24 top-level projects
- Audit comment count: 19 -> 22 top-level projects
- Pass 3 symbols: 19 -> 22 top-level projects

All 24 top-level projects verified byte-identical.

TODO.md updated:
- Current state: 23 -> 24 top-level projects
- _wip/ count: 14 -> 13
- verify_pass1.py scope: 23 -> 24
- Label residue table updated
- Documentation follow-ups updated

Promote Millipede (U) and Popeye (JU) (PRG 0) to top-level

Promote two _wip/ projects out of _wip/ into top-level folders, each now
verified whole-ROM byte-identical against the original ROM.

- Millipede (U): moves all copilot files up, adds header.s, chr.s,
  linker.cfg with PRG+HEADER+CHR areas, rom.nes copy, and switches the
  Makefile from PRG-only cmp to whole-ROM cmp. Makefile _tools depth
  adjusted (../../../../_tools/ -> ../../_tools/).
- Popeye (JU) (PRG 0): same promotion treatment.
- AGENTS.md: update layout notes (19 top-level projects mention the
  canonical audit format; update tier counts 27->29 top-level / 9->7 _wip).
- OVERVIEW.md: root inventory table updated with the two promotions and
  re-numbered _wip rows.
- TODO.md: handoff updates.
- Remaining _wip projects: assorted pass 2/3 edits (prg.s, locals.inc,
  reconstructed.lbl, reconstructed_prg.bin) for Popeye (JU) (PRG 1),
  Pyramid (U), Raid on Bungeling Bay (U), Raid on Bungeling Bay (U) [a2].
2026-10-19 19:58:41 -04:00

181 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pac-Man (U) — Game Flow from Power-On
This document describes the execution flow of the disassembled Pac-Man (U) PRG bank (16 KB, mapped at CPU **$C000–$FFFF**), starting from power-on. It is based entirely on `copilot/prg.s` in the repository. The rebuild is verified **byte-identical** to the original `prg.bin` at the PRG level.
**Variant note:** `Pac-Man (Tengen) (U)` is an unrelated dump (different PRG). Both use horizontal mirroring.
**Unusual RESET vector:** The RESET vector points to **$FF00** (inside the vector page padding), not into the PRG code at $C000+. The PRG at $FF00 is all `$FF` bytes (invalid opcode). The actual initialization code begins at **$C042** (`Label_C042`), reached via an unknown mechanism — possibly the dump has a corrupted vector, or the game uses a hardware reset quirk. The disassembly traces from $C042 as the effective reset entry.
---
## 1. Effective Reset Entry — $C042 (`Label_C042`)
**`Label_C042`** ($C042–$C0A0)
The code at $C042 performs cold-start hardware initialization:
| Step | Code | Purpose |
|------|------|---------|
| 1–2 | `ldx #$FF` / `txs` | Initialize stack pointer to $01FF |
| 3–4 | `lda #$00` / `tay` | A=0, Y=0 |
| 5–9 | `Label_C048`: `sta $0000,y` / `iny` / `cpy #$3E` / `bne` | Clear $0000–$003D (62 bytes) |
| 10–17 | `ldx #$08` / `ldy #$87` / `Label_C054`: `sta (Zp00),y` / `iny` / `bne` / `inc Zp01` / `cpx Zp01` / `bne` | Clear 9 pages from $8700 ($8700–$8F00) via Zp00/Zp01 |
| 18–19 | `lda #$06` / `sta $2001` | PPUMASK = $06 (show BG, hide sprites) |
| 20–23 | `lda #$00` / `sta $2005` ×2 | PPUSCROLL = 0,0 |
| 24–25 | `sta Zp41` / `sta Zp42` | Zp41=Zp42=0 (scroll shadows) |
| 26–27 | `sta $2000` / `sta $2001` | PPUCTRL=0, PPUMASK=0 |
| 28 | `tay` | Y=0 |
| 29–37 | `Label_C077`: `lda $C0EB,y` / `cmp $0052,y` / `bne Label_C086` / `iny` / `cpy #$0F` / `bne` / `beq Label_C0A0` | Compare 15-byte copyright string at $C0EB with RAM at $0052; if match, jump to $C0A0 |
| 38–41 | `Label_C086`: `lda #$00` / `tay` / `Label_C089`: `sta $0000,y` / `iny` / `bne` / `ldy #$00` | If mismatch: clear $0000–$00FF, Y=0 |
**Copyright check:** 15-byte string "COPYRIGHT 1984 NAMCO LTD. ALL RIGHTS RESERVED" at $C0EB compared against RAM at $0052. On cold start, RAM is garbage so check fails, clearing $0000–$00FF. On warm reset, if signature persists, skips extra clear.
**Note:** The code from $C042 onward is **identical** to `Pac-Man (Tengen) (U)` from its `Label_C03D` ($C03D) onward. The only difference is the entry point ($C033 vs $C042) and the initial `sei`/`cld`/`PPU off` which are missing here (possibly executed before jumping to $C042).
---
## 2. Interrupt Vectors — CPU $FFFA–$FFFF
Located at PRG offset $3FFA (end of 16 KB bank):
| Vector | Address | Handler |
|--------|---------|---------|
| NMI | $C0FA | `NmiHandler` |
| RESET | $FF00 | **Points into vector padding ($FF bytes)** — likely corrupted dump |
| IRQ | $C16A | `IrqHandler` (single `rti` — unused placeholder) |
**Actual reset entry:** $C042 (`Label_C042`), traced as effective cold start.
---
## 3. NMI / Frame Heartbeat — `NmiHandler` ($C0FA)
Identical to `Pac-Man (Tengen) (U)` — see that document for full details. Summary:
```
NmiHandler ($C0FA):
pha / txa / pha / tya / pha
lda #$1E / sta $2001
lda #$00 / sta $2003 / sta Zp40
lda Zp45 / sta $4014 (OAMDMA)
jsr $DE3D (sprites) / jsr $E261 (game logic) / jsr $C16B (palette)
lda Zp41/Zp42 → $2005 (scroll)
lda Zp47/Zp46/Zp43 → $2000 (PPUCTRL)
Controller strobe + 8-bit read ($4016/$4017) → Zp4D/Zp4E
Select active input → Zp4F
inc Zp4B (frame counter)
Zp48=0 → jsr $EE8F (attract)
pla / tay / pla / tax / pla / rti
```
---
## 4. Key Subroutines
Identical to `Pac-Man (Tengen) (U)`:
- `$DE3D` — Sprite/OAM update
- `$E261` — Main game logic
- `$C16B` — Palette/PPU update (uploads 16 bytes from $0299 when $0299=$0F)
- `$EE8F` — Attract mode logic
- Controller reading: 8-bit shift from $4016/$4017 → Zp4D/Zp4E → Zp4F
---
## 5. Indirect Dispatch
Same as Tengen variant:
- `jmp ($0010)` at $C250, $D90F, $D9B6, $D3CA
- `jmp ($00FE)` at $EFDA
Not followed statically.
---
## 6. Memory Map (Key Zero Page / RAM)
| Address | Name | Use |
|---------|------|-----|
| $40 | `Zp40` | Cleared each NMI |
| $41–$42 | `Zp41`/`Zp42` | Scroll X/Y shadows |
| $43 | `Zp43` | PPUCTRL flag |
| $45 | `Zp45` | OAM DMA source page |
| $46–$47 | `Zp46`/`Zp47` | Game state flags |
| $48 | `Zp48` | Attract mode flag |
| $4B | `Zp4B` | Frame counter |
| $4D–$4E | `Zp4D`/`Zp4E` | Player 1/2 button shift registers |
| $4F | `Zp4F` | Active input |
| $0200 | OAM buffer | Sprite DMA source |
| $0299 | Palette buffer | 16 bytes for $3F00 upload |
| $0052 | Copyright check | 15-byte RAM signature |
---
## 7. Data Tables
| Table | Address | Description |
|-------|---------|-------------|
| Copyright string | $C0EB | 15 bytes "COPYRIGHT 1984 NAMCO LTD. ALL RIGHTS RESERVED" |
| Palette upload | $0299 | 16 bytes, uploaded when $0299=$0F |
---
## 8. Summary of Execution Flow
```
Power On / Reset
│
▼ (Vector points to $FF00 — $FF padding)
│
▼ (Unknown mechanism reaches $C042)
Label_C042 ($C042) ────► stack=$FF
│
├─ Clear $0000–$003D (62 bytes)
├─ Clear $8700–$8F00 (9 pages via Zp00/Zp01)
├─ PPUMASK=$06, PPUSCROLL=0,0
├─ Zp41=Zp42=0
├─ PPUCTRL=0, PPUMASK=0
├─ Copyright check: $C0EB vs $0052 (15 bytes)
│ ├─ Match: jump to Label_C0A0
│ └─ Mismatch: clear $0000–$00FF
│
▼
Main Initialization (Label_C0A0+)
│
▼
Main Loop (VBlank synchronized)
│
▼ (NMI fires once per frame)
NMI ($C0FA) [identical to Tengen variant]
├─ Preserve A,X,Y
├─ PPUMASK=$1E, OAMADDR=0, Zp40=0
├─ OAM DMA from Zp45 page
├─ jsr $DE3D (sprites), $E261 (game logic), $C16B (palette)
├─ Scroll from Zp41/Zp42
├─ PPUCTRL from Zp43/Zp46/Zp47
├─ Controller strobe + 8-bit read ($4016/$4017) → Zp4D/Zp4E
├─ Select active input → Zp4F
├─ inc Zp4B (frame counter)
├─ Zp48=0 → jsr $EE8F (attract)
└─ Restore, rti
```
---
## 9. Naming and Residue
**Pass 1 complete** — 4,506 lines, 194 `Label_` definitions, canonical audit comments, 19.6% code. 16 seeded routine entries from table references (same as Tengen variant).
**Pass 2 outstanding** — No semantic names applied; all 194 labels remain address-derived `Label_XXXX`.
**Pass 3 outstanding** — No semantic zero-page aliases; `locals.inc` holds neutral `ZpXX` names.
**Indirect dispatch** (not followed statically):
- `jmp ($0010)` at $C250, $D90F, $D9B6, $D3CA
- `jmp ($00FE)` at $EFDA
**Unusual RESET vector** — Points to $FF00 (vector page padding). The disassembly traces from $C042 as the effective entry. This may indicate a bad dump or a hardware quirk.
**Promotion outstanding** — Add `header.s`/`chr.s` + HEADER/PRG/CHR `linker.cfg`, switch `make` to whole-ROM `cmp`, move `_tools` paths from `../../../_tools/` to `../../_tools/`.
Build verification: `make` in `copilot/` produces `reconstructed_prg.bin`, compared against `prg.bin` (PRG byte-identical).