Promote Xevious (U) and Zanac (U) from _wip/ to NROM/

- Xevious (U): Promoted from _wip/NROM/Xevious (U)/ to NROM/Xevious (U)/
  - Pass 3 complete: 34.5% code coverage, 143 semantic entry points,
    4 named data tables, ~20 semantic ZP aliases
  - NROM mapper 0, 32 KB PRG, 8 KB CHR, horizontal mirroring

- Zanac (U): Promoted from _wip/UNROM/Zanac (U)/ to NROM/Zanac (U)/
  - Pass 3 complete: 34.5% code coverage (bank 7 only), 133 semantic
    entry points, 26 named data tables, 14 semantic ZP aliases
  - UNROM mapper 2, 128 KB PRG (8 banks), no CHR
  - Bank 7 fixed at CPU -; banks 0-6 switchable at 000-
  - Bank 7 assembled separately as prg.07.s with .org

Both projects build byte-identical. Updated root README.md inventory,
per-project details, and WIP.md accordingly.

Move Zanac (U) to UNROM/ mapper directory

Zanac (U) is a UNROM (mapper 2) game, not NROM (mapper 0). Move it to
the correct mapper directory and update README.md and WIP.md references
accordingly. Update project counts in WIP.md (857->856 total, UNROM
98->97 projects).

Promote Mermaids of Atlantis (U) from _wip/ to MAPPER8/

Additional cleanup of Mermaids of Atlantis
This commit is contained in:
tmerritt committed 2026-10-21 07:20:59 -04:00
1 parent 49e117bfcc
commit df11857075
58 files changed
+39615 -263

No files matched your search

+4
View File
@@ -101,6 +101,10 @@ ZpFF = $FF ; 8 refs; reads=3 writes=5; used at $EE9B, EF7B, E
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; ---------------------------------------------------------------------------
; Semantic zero-page aliases (Pass 3)
;
+25
View File
@@ -0,0 +1,25 @@
CA65 ?= ca65
LD65 ?= ld65
all: reconstructed.nes verify
prg.o: prg.s symbols.inc locals.inc prg.bin
$(CA65) -g -o $@ $<
header.o: header.s header.bin
$(CA65) -g -o $@ $<
chr.o: chr.s chr.bin
$(CA65) -g -o $@ $<
reconstructed.nes: header.o prg.o chr.o linker.cfg
$(LD65) -C linker.cfg -m reconstructed.map -Ln reconstructed.lbl -o $@ header.o prg.o chr.o
verify: reconstructed.nes rom.nes
cmp reconstructed.nes rom.nes
@echo "Byte-identical ROM verified."
clean:
rm -f *.o reconstructed.nes reconstructed_prg.bin reconstructed.map reconstructed.lbl
.PHONY: all verify clean
+103
View File
@@ -0,0 +1,103 @@
# Xevious (U)
## Status
**Pass 3 complete.** All routine entry points (jsr/jmp targets) have semantic
names, and all raw `$XXXX` call operands in `jsr`/`jmp` instructions have been
replaced with label references (except 7 targets outside code range, kept as
raw addresses). Major data tables and zero-page aliases have been named. The
project builds and verifies byte-identical to the original ROM.
`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 | 11321 bytes (34.5%) |
| Data | 21447 bytes (65.5%) |
| Instructions | 5513 |
| Routines/labels | 795 |
| Zero-page aliases | 156 (in `locals.inc`) |
| Indirect dispatches | `jmp ($fe)` at $BA88 (table $BA8B, 16 entries), `jmp ($4)` at $CA07 (table $CA0A, 64 entries) |
### Pass 2 results
| Metric | Value |
|--------|-------|
| `Label_XXXX` names replaced | 781 labels → unique names |
| Raw `$XXXX` jsr/jmp operands replaced | 466 → label references |
| Remaining raw `$XXXX` jsr/jmp | 7 (targets outside code range) |
| 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 | ~574 (`Sub_XXXX` address-based, local to routines) |
| Named data tables | PatternData, SpriteAttrTable, JumpTable4, ResetVarTable |
| Semantic zero-page aliases | ~20 (PPUCTRLShadow, ObjectX, ObjectY, ObjPtr, GameMode, Joypad1Cur, etc.) |
### Pass 1 notes
- 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 64-entry table at $CA0A (targets mostly in $CA–$CB and $C0–$C3 ranges)
- 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.
- Six addresses contain undocumented/illegal opcodes not decoded by the tracer: $9848, $A2C3, $CD89, $E0FF, $E3B5, $F230.
## 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. Code/data split produced; build verifies byte-identical.
- **Pass 2** - complete. All `Label_XXXX` names replaced with unique names; all
raw `$XXXX` jsr/jmp operands replaced with label references (7 remain outside code range).
- **Pass 3** - complete. All 143 routine entry points have semantic names;
~574 internal branch labels remain as `Sub_XXXX` address-based names;
~20 zero-page aliases have semantic names; 4 data tables named.
- **Promotion** to `NROM/<name>/` once ready, as `git mv`.
## 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 |
Binary file not shown.
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
.segment "CHR"
.incbin "chr.bin"
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
.segment "HEADER"
.incbin "header.bin"
+10
View File
@@ -0,0 +1,10 @@
MEMORY {
HEADER: start = $0000, size = $0010, fill = yes;
PRG: start = $8000, size = $8000, fill = yes;
CHR: start = $0000, size = $2000, fill = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
PRG: load = PRG, type = ro;
CHR: load = CHR, type = ro;
}
+159
View File
@@ -0,0 +1,159 @@
; Xevious (U) application-specific RAM aliases - Pass 2
; Semantic names derived from observed usage in reachable code.
PPUCTRLShadow = $00 ; 24 refs; PPUCTRL mirror written each NMI
PPUMASKShadow = $01 ; 23 refs; PPUMASK mirror written each NMI
ScrollX = $02 ; 3 refs; horizontal scroll written to PPUSCROLL
ScrollY = $03 ; 18 refs; vertical scroll written to PPUSCROLL
VramPtrLo = $04 ; 53 refs; indirect pointer low byte for (Zp04),y
VramCopyCount = $05 ; 14 refs; copy/page counter (init to 7 in reset)
Joypad1Cur = $06 ; 4 refs; joypad 1 current state
Joypad1Prev = $07 ; 5 refs; joypad 1 previous state
Joypad2Cur = $08 ; 2 refs; joypad 2 current state
Joypad1Press = $09 ; 6 refs; joypad 1 newly-pressed buttons
Joypad2Cur2 = $0A ; 6 refs; joypad 2 current state (2nd copy)
Joypad2Prev = $0B ; 3 refs; joypad 2 previous state
UnusedZp0C = $0C ; 1 refs; read only at $FE73
NmiFrameFlag = $0D ; 5 refs; NMI frame flag
ObjUpdateFlag = $0E ; 51 refs; object update / sprite flag (heavily used)
NmiToggle = $0F ; 4 refs; NMI toggle flag (eor'd each frame)
GameMode = $10 ; 10 refs; game mode (0=title,1=game,2=demo?)
Zp12 = $12 ; 4 refs; reads=2 writes=2
ObjPtr = $13 ; 65 refs; object/entity pointer (heavily used)
Zp14 = $14 ; 10 refs
Zp15 = $15 ; 8 refs
Zp16 = $16 ; 1 refs
ObjectX = $18 ; 12 refs; object X coordinate
ObjectY = $19 ; 9 refs; object Y coordinate
Joypad1Press2 = $1A ; 10 refs; joypad press / frame counter
GameSubMode = $1B ; 24 refs; game sub-mode (read 22x, written 2x)
Zp1C = $1C ; 4 refs
Zp1D = $1D ; 3 refs
Zp1E = $1E ; 3 refs
Zp20 = $20 ; 4 refs; read only
FrameToggle = $22 ; 7 refs; toggle flag (r or'ed each NMI)
Zp23 = $23 ; 24 refs; read 23x, written 1x
Zp24 = $24 ; 18 refs; read 17x, written 1x
Zp25 = $25 ; 19 refs
Zp26 = $26 ; 2 refs
Zp27 = $27 ; 9 refs
Zp28 = $28 ; 2 refs; init to $F8 in reset
Zp29 = $29 ; 5 refs
Zp2A = $2A ; 36 refs; read 33x, written 3x
Zp2B = $2B ; 5 refs
Zp2C = $2C ; 13 refs
ObjectDeltaX = $2D ; 28 refs; object delta X (read 11x, written 17x)
Zp2E = $2E ; 6 refs
Zp2F = $2F ; 5 refs
Zp30 = $30 ; 9 refs
Zp31 = $31 ; 3 refs
Zp32 = $32 ; 5 refs
Zp33 = $33 ; 2 refs
Zp34 = $34 ; 3 refs
ObjectYLo = $35 ; 27 refs; object Y coordinate low
ObjectYHi = $36 ; 17 refs; object Y coordinate high
ObjectXLo = $37 ; 34 refs; object X coordinate low
ObjectXHi = $38 ; 37 refs; object X coordinate high
Zp39 = $39 ; 11 refs
Zp3A = $3A ; 2 refs
Zp3B = $3B ; 24 refs
ResetHi = $3C ; 10 refs; high byte from reset table
Zp3D = $3D ; 6 refs
Zp3E = $3E ; 6 refs
Zp3F = $3F ; 6 refs
Zp40 = $40 ; 3 refs
Zp41 = $41 ; 4 refs
Zp42 = $42 ; 4 refs; init to 4 in reset
Zp43 = $43 ; 1 refs; init to $FE in reset
Zp44 = $44 ; 4 refs
Zp45 = $45 ; 8 refs
Zp46 = $46 ; 9 refs
Zp48 = $48 ; 4 refs
Zp49 = $49 ; 2 refs
Zp4B = $4B ; 2 refs; copied from $0110 in reset
Zp4E = $4E ; 1 refs; init to 2 in reset
Zp52 = $52 ; 2 refs
Zp53 = $53 ; 2 refs; from reset table $FC25
Zp54 = $54 ; 1 refs; from reset table $FC26
Zp55 = $55 ; 1 refs; from reset table $FC27
Zp56 = $56 ; 1 refs; from reset table $FC28
Zp57 = $57 ; 4 refs
Zp58 = $58 ; 3 refs
Zp59 = $59 ; 9 refs
Zp5A = $5A ; 8 refs
Zp5B = $5B ; 3 refs
Zp5D = $5D ; 1 refs; from reset table $FC21
Zp5E = $5E ; 6 refs; copied from $0140 in reset
Zp5F = $5F ; 2 refs; from reset table $FC21
Zp60 = $60 ; 9 refs; read only (checked in NMI)
Zp61 = $61 ; 10 refs
Zp62 = $62 ; 3 refs
ObjIndex = $63 ; 6 refs; object/index slot (from reset $0141)
Zp65 = $65 ; 2 refs
Zp66 = $66 ; 2 refs; from reset table $FC1D
Zp69 = $69 ; 1 refs
Zp6C = $6C ; 2 refs
Zp6E = $6E ; 3 refs
Zp77 = $77 ; 1 refs
Zp7B = $7B ; 1 refs
Zp7F = $7F ; 2 refs
Zp80 = $80 ; 14 refs; copied from $0120 in reset
Zp81 = $81 ; 3 refs
Zp82 = $82 ; 1 refs
Zp83 = $83 ; 1 refs
Zp84 = $84 ; 1 refs
Zp85 = $85 ; 1 refs
Zp87 = $87 ; 4 refs
Zp88 = $88 ; 10 refs
Zp8A = $8A ; 1 refs
Zp8B = $8B ; 1 refs
Zp8C = $8C ; 2 refs
Zp8D = $8D ; 6 refs
Zp8E = $8E ; 4 refs
Zp8F = $8F ; 10 refs
Zp90 = $90 ; 8 refs
Zp91 = $91 ; 5 refs
Zp92 = $92 ; 5 refs
Zp93 = $93 ; 1 refs
Zp94 = $94 ; 2 refs
Zp95 = $95 ; 3 refs
Zp96 = $96 ; 2 refs
Zp97 = $97 ; 1 refs
Zp98 = $98 ; 3 refs
Zp99 = $99 ; 15 refs
Zp9A = $9A ; 4 refs; copied from $0130 in reset
ZpA2 = $A2 ; 1 refs
ZpA4 = $A4 ; 1 refs
ZpA7 = $A7 ; 3 refs
ZpA9 = $A9 ; 6 refs
ZpAA = $AA ; 1 refs
ZpAD = $AD ; 1 refs
ZpB3 = $B3 ; 1 refs
ZpC1 = $C1 ; 4 refs
ZpC3 = $C3 ; 2 refs
ZpC6 = $C6 ; 2 refs
ZpD7 = $D7 ; 3 refs
ZpD8 = $D8 ; 9 refs
ZpDE = $DE ; 2 refs
ZpE6 = $E6 ; 2 refs
SpriteAttr = $E8 ; 5 refs; sprite attribute byte (set in NMI)
ZpEA = $EA ; 2 refs
ZpEB = $EB ; 1 refs
NmiCounter = $ED ; 4 refs; NMI counter (inc'd each frame)
ZpEE = $EE ; 2 refs; bit 7 of Zp63 (sprite flag?)
ZpF0 = $F0 ; 8 refs
ZpF1 = $F1 ; 1 refs
ZpF2 = $F2 ; 43 refs; heavily used general-purpose
ZpF3 = $F3 ; 1 refs
ZpF4 = $F4 ; 3 refs
ZpF5 = $F5 ; 1 refs
ZpF6 = $F6 ; 4 refs
ZpF7 = $F7 ; 1 refs
ZpF8 = $F8 ; 2 refs
ZpF9 = $F9 ; 1 refs
ZpFA = $FA ; 1 refs
ZpFB = $FB ; 1 refs
ZpFC = $FC ; 10 refs
ZpFD = $FD ; 30 refs; heavily used general-purpose
ZpFE = $FE ; 15 refs; indirect jump lo (jmp ($fe) dispatch)
ZpFF = $FF ; 9 refs; indirect jump hi (jmp ($fe) dispatch)
Binary file not shown.
+14981
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+108
View File
@@ -0,0 +1,108 @@
; =============================================================================
; Nintendo Entertainment System hardware symbols
; =============================================================================
; -----------------------------------------------------------------------------
; PPU registers
; -----------------------------------------------------------------------------
PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
OAMADDR = $2003
OAMDATA = $2004
PPUSCROLL = $2005
PPUADDR = $2006
PPUDATA = $2007
OAMDMA = $4014
; -----------------------------------------------------------------------------
; Controller ports
;
; $4016:
; Write: controller strobe
; Read: controller port 1
;
; $4017:
; Read: controller port 2
; Write: APU frame counter
; -----------------------------------------------------------------------------
JOY1 = $4016
JOY2 = $4017
; -----------------------------------------------------------------------------
; APU pulse channel 1
; -----------------------------------------------------------------------------
APUPULSE1CTRL = $4000
APUPULSE1SWEEP = $4001
APUPULSE1TIMERLO = $4002
APUPULSE1TIMERHI = $4003
; -----------------------------------------------------------------------------
; APU pulse channel 2
; -----------------------------------------------------------------------------
APUPULSE2CTRL = $4004
APUPULSE2SWEEP = $4005
APUPULSE2TIMERLO = $4006
APUPULSE2TIMERHI = $4007
; -----------------------------------------------------------------------------
; APU triangle channel
; -----------------------------------------------------------------------------
APUTRIANGLECTRL = $4008
APUTRIANGLETIMERLO = $400A
APUTRIANGLETIMERHI = $400B
; -----------------------------------------------------------------------------
; APU noise channel
; -----------------------------------------------------------------------------
APUNOISECTRL = $400C
APUNOISEPERIOD = $400E
APUNOISELENGTH = $400F
; -----------------------------------------------------------------------------
; APU DMC channel
; -----------------------------------------------------------------------------
APUDMCCTRL = $4010
APUDMCDIRECT = $4011
APUDMCADDR = $4012
APUDMCLENGTH = $4013
; -----------------------------------------------------------------------------
; APU status and frame counter
;
; $4015:
; Write: enable or disable the five APU channels
; Read: channel and interrupt status
;
; $4017:
; Write: APU frame-counter mode and IRQ inhibit
; Read: controller port 2
; -----------------------------------------------------------------------------
APUSTATUS = $4015
APUFRAMECOUNTER = $4017
; -----------------------------------------------------------------------------
; Controller masks
; -----------------------------------------------------------------------------
PAD_RIGHT = $01
PAD_LEFT = $02
PAD_DOWN = $04
PAD_UP = $08
PAD_START = $10
PAD_SELECT = $20
PAD_B = $40
PAD_A = $80
PAD_HORIZONTAL = PAD_LEFT | PAD_RIGHT
PAD_VERTICAL = PAD_UP | PAD_DOWN
PAD_DPAD = PAD_HORIZONTAL | PAD_VERTICAL