Files
disasm/NROM/Donkey Kong Jr. Math (U)/sites.tsv
T
tmerrittandClaude Opus 4.8 49e117bfcc Fix Pass 3 symbol application and add promotion criteria to PROMPTS.md
- Apply symbols.inc hardware register names to Defender 2 (U) (51 operands)
- Apply symbols.inc hardware register names to Donkey Kong 3 (JUE) (36 operands)
- Add APU register symbols (-) to Defender 2 (U) and Donkey Kong 3 (JUE) symbols.inc
- Apply symbols to Donkey Kong Jr. Math (U) (80 operands: 11 single + 69 hardware)
- Apply symbols to Excitebike (JU) (786 operands: 785 single + 1 hardware)
- Add promotion criteria to PROMPTS.md: symbol/local substitution,
  ROM-specific semantic naming, and verification checklist

Add branch/jump target naming requirement to PROMPTS.md

All branches and jumps must target symbolic labels with descriptive names
derived from program flow role (e.g., _Loop, _Next, _Done, _Store, _Return),
never raw address literals. Adds criterion 8 to verification checklist.

Rename all OVERVIEW.md to README.md; add root README content to top-level

- Rename all OVERVIEW.md files to README.md throughout the repo (47 files)
- Prepend README.md content to top-level OVERVIEW.md before rename
- Fix apply_symbols.py NAME_RE regex to handle spaced assignments
- Apply symbols.inc to Defender 2 (U) (51 hardware operands)
- Apply symbols.inc to Donkey Kong 3 (JUE) (36 hardware operands)
- Apply symbols.inc to Donkey Kong Jr. Math (U) (80 operands: 11 single + 69 hardware)
- Apply symbols.inc to Excitebike (JU) (786 operands: 785 single + 1 hardware)
- Add missing Zp18/FrameCounter aliases to Excitebike prg.s
- Build all 27 top-level projects: byte-identical

Promote Donkey Kong Jr. Math back to _wip tier

Moves code from `copilot` folder and verifies each builds after

Add pre-commit hook for byte-identical verification

Add .git/hooks/pre-commit that runs 'make' then 'make clean' in each
project directory before committing. This ensures every project builds
byte-identical before any commit is accepted.

Also includes all file moves from the Donkey Kong Jr. Math (U) demotion
and other file restructuring from the session.

moves code out of copilot folder, its all AI generated.
Moves NROM games into NROM folder

removes copilot folder from Lunar Pool
Adds makefile to build all projects recursively

Updates docs to reflect changes in layout

Repromotes Donkey Kong Jr Math
Repromotes Excitebike
Promotes Popeye (JU) (PRG 1)
Updates Makefile to provide summary of build failure/success

Promote Raid on Bungeling Bay (U): Pass 2/3 partial, whole-ROM byte-identical

Move _wip/NROM/Raid on Bungeling Bay (U) to NROM/ and switch the build
from a PRG-only compare to a whole-ROM one:

  - header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
  - linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
    areas ahead of PRG ($C000, $4000)
  - rom.nes symlink to the space-containing original ROM name
  - Makefile builds header.o/prg.o/chr.o into reconstructed.nes and
    compares it against rom.nes ('Byte-identical ROM verified.')
  - one leftover neutral indirect operand jmp (Zp01) at $E2EC becomes
    jmp (IndDispatch01); apply_symbols.py reports 0 substitutions pending

README.md / TODO.md / AGENTS.md updated: 29 promoted, 7 in _wip/.

Pac-Man (U): Pass 2 complete (label renaming) + Pass 3 partial (ZP aliases, table names)

Pass 2 — fresh map derived from the committed split, not from any drafted
map (the drafted maps in other projects were audited and found not
applicable):

  - all 194 address-derived Label_XXXX definitions renamed to semantic
    routine-entry names plus <Routine>_<Role>_<addr> internal branch
    targets; zero Label_ remains
  - all 49 jsr/jmp call sites resolved from raw $XXXX to labels; zero
    raw $XXXX call operands remain
  - routinemap.tsv / derived_names.tsv record the derivation

Pass 3 (partial):

  - 15 proven semantic zero-page aliases added to locals.inc
    (GameState, NmiFlag, ScrollX/Y, PpuCtrlShadow, OamDmaPage,
    CocktailModeFlag, ActivePlayerFlag, GameplaySuspended, FrameCounter,
    StateTimer, Player1/2Input, ActiveInput, CopyrightVerified)
  - 112 operands substituted into prg.s (11 single + 101 hardware)
  - key data tables named: ProgrammerSig ($C0EB), GameStateDispatchTable
    ($C253), TitleScreenData ($C2FD), EntityPtrTable ($D912),
    AudioCommandTable ($EFDD)

Also corrects the README's claim that the RESET vector points at padding:
$FF00 holds real boot code (sei/cld, PPU off, double vblank wait, then
jmp ColdStart at $C042).

.gitignore: ignore reconstructed_prg.bin (build artifact of the _wip
Makefiles; '**/reconstructed.*' does not match the underscore form).

Promote Pac-Man (U): Pass 2/3 complete, whole-ROM byte-identical

Move _wip/NROM/Pac-Man (U) to NROM/ and switch the build from a PRG-only
compare to a whole-ROM one:

  - header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
  - linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
    areas ahead of PRG ($C000, $4000)
  - rom.nes symlink to 'Pac-Man (U) [!].nes' (the original ROM name
    contains a space and brackets)
  - Makefile builds header.o/prg.o/chr.o into reconstructed.nes and
    compares it against rom.nes
  - reconstructed.nes is 24,592 bytes, MD5 a69d310f8cae9397fbd39f204672b5c7
    - equal to the original ROM; the header/prg/chr splits were checked
    against the original before promotion and are byte-exact

Pass 3 residue closed.  The last 7 multi-alias zero-page operands are
resolved per site through a new sites.tsv, each proven from context
rather than guessed:

  - jmp ($0010) at $C250/$D3CA/$D90F/$D9B6 -> (DispatchPtrLo); each
    is immediately preceded by sta DispatchPtrLo/sta DispatchPtrHi
  - jmp ($00FE) at $EFDA -> (AudioHandlerPtrLo); preceded by
    sta AudioHandlerPtrLo/sta AudioHandlerPtrHi
  - sta a:$0000,y at $C048/$C089 -> a:Zp00,y; the literal zero-page
    base in the two ZP clear loops, so the neutral name is used rather
    than the semantic WorkPtrLo.  The 'a:' prefix survives the
    substitution, so the bytes stay 99 00 00 (sta abs,Y)

apply_symbols.py now reports 119 operands substituted (101 hardware,
11 single-name, 7 site) and 0 residue.

New tool _tools/align_audit_comments.py: re-aligns the audit comment to
column 35 after a substitution lengthens an operand (nesdis.py pads each
instruction to 31 characters).  Whitespace-only, so the byte identity
cannot change.  405 lines re-aligned in this project; all 2,387 audit
comments still match prg.bin at the stated PRG offset, 0 mismatches.

Docs: root README.md / TODO.md / AGENTS.md updated - 30 promoted, 6 in
_wip/; a per-project detail entry for Pac-Man (U) added; the stale
'Donkey Kong 3 (JUE) has no README.md' claim corrected (it has a
318-line one).

Promote Raid on Bungeling Bay (U) [a2]: Pass 3 complete, whole-ROM byte-identical

Move _wip/NROM/Raid on Bungeling Bay (U) [a2] to NROM/ and switch the build
from a PRG-only compare to a whole-ROM one:

  - header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
  - linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
    areas ahead of PRG ($C000, $4000)
  - rom.nes symlink to 'Raid on Bungeling Bay (U) [a2].nes' (the original
    ROM name contains spaces and brackets)
  - reconstructed.nes is 24,592 bytes, MD5 659d340a1e9d420eee28df13319b0094
    - equal to the original ROM; the header/prg/chr splits were checked
    against the original before promotion and are byte-exact

Pass 3 - 15 semantic zero-page aliases, each applied only at the sites
where its role is proven:

  - PpuCtrlShadow ($C2), 15 sites: the reset entry primes it right after
    'sta PPUCTRL', and every other use is an ora/and/eor followed by
    'sta PPUCTRL'
  - NmiPathSelector ($C4), 5 sites: written 1 at $C3E9 and 0 at $C962
  - GameState ($D6), 6 sites: 'cmp #$02' and used as an index at $C4C7
  - FrameSubCounter ($55), 6 sites: set to $0A at $C520, decremented per
    NMI at $C07B
  - PrngPeriodCounter ($EA) / PrngSeedB ($EB) / PrngState ($EC), 13 sites:
    the PRNG state
  - PtrLo ($00) / PtrHi ($01), 8 sites: the 16-bit pair $1C13 and $1610
    compared at $E785/$E791
  - IndDispatch01 ($01) / IndDispatch02 ($02), 3 sites: the computed
    dispatch at $E2EC
  - IndDispatch1B ($1B) / IndDispatch1C ($1C), 6 sites: the dispatch at
    $E7A3
  - IndDispatch17 ($17) / IndDispatch19 ($19): the dispatches at $E79D
    and $E7A0

Addresses that carry two names keep the neutral ZpXX name where the other
role applies - $01 is PtrHi at the 16-bit compare and IndDispatch01 at the
dispatch; $17 is IndDispatch17 at the dispatch and Zp17 for the absolute
RAM $0017 store in the copy loop at $E895/$E8D0.

New tool _tools/apply_zp_aliases.py does the per-site substitution:
apply_symbols.py only rewrites *numeric* operands, so it cannot rename an
operand that is already written as a neutral ZpXX name.  The tool keeps the
ca65 'a:' prefix (dropping it would turn 'sta a:Zp17,y' into a zero-page
store and change the bytes) and rewrites only the operand token, so the
audit comment survives byte for byte.

Naming correction in the promoted sibling.  Finishing this dump showed that
$EA was misnamed 'VBlankWaitCounter': the routine at $C412 is the game's
pseudo-random generator (the classic eor/asl/php/lsr/plp/rol scrambler,
called from thirteen gameplay sites, twice in a row at $CDF4/$CDF9 with the
second result masked #$07), so $EA is the scrambler's phase counter.
Renamed PrngPeriodCounter in both dumps and named $EB/$EC PrngSeedB /
PrngState.  The sibling's two 'sta a:IndDispatch17,y' operands were also
wrong - they are absolute stores to RAM $0017, not the dispatch pointer -
and are now 'a:Zp17,y', matching the file's 'a:' = absolute convention.

Audit-comment alignment re-done with _tools/align_audit_comments.py (1,040
lines here, 1,080 in the sibling).  Both files still match prg.bin at every
stated PRG offset: 5,467 and 5,483 audit comments, 0 mismatches.

Docs: root README.md / TODO.md / AGENTS.md updated - 31 promoted, 5 in
_wip/; per-project detail entries added for both Raid dumps.

Promote Pac-Man (Tengen) (U): Pass 2/3 from scratch, whole-ROM byte-identical

Move _wip/NROM/Pac-Man (Tengen) (U) to NROM/ and switch the build from a
PRG-only compare to a whole-ROM one:

  - header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
  - linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
    areas ahead of PRG ($C000, $4000)
  - rom.nes symlink to 'Pac-Man (Tengen) (U) [!].nes'
  - reconstructed.nes is 24,592 bytes, MD5 d34e7a74d8d2c231b6cc601210e28ad0
    - equal to the original ROM; the header/prg/chr splits were checked
    against the original before promotion and are byte-exact

Disassembled from scratch.  No name, map or file was carried over from the
sibling 'Pac-Man (U)' dump; the map was derived from this dump's own
committed split and the two were only compared afterwards.

Pass 2 (new tool _tools/apply_pass2_map.py):
  - all 194 Label_XXXX definitions renamed to semantic routine entries plus
    <Routine>_<Role> branch targets; zero Label_ remains
  - all 48 raw $XXXX jsr/jmp operands resolved to labels; zero raw $XXXX
    call or branch operands remain
  - the map is in routinemap.tsv

Pass 3:
  - 30 semantic zero-page aliases, each applied only at the sites where its
    role is proven (per-site choice in sites.tsv; the addresses that carry
    two roles keep the neutral ZpXX name elsewhere).  _tools/
    derive_zp_aliases.py records how the set was derived, and locals.inc
    records the reason for every remaining neutral slot
  - 28 data tables named (new tool _tools/name_data_region.py), including
    CharacterDataTable ($C66A) and CharacterNameStrings ($C67E), where the
    ROM itself names Blinky, Pinky, Inky and Clyde - which is why the four
    indexed entities are called ghosts and not 'actors'
  - apply_symbols.py reports 0 substitutions pending and 0 residue
  - audit-comment alignment re-done with _tools/align_audit_comments.py;
    all 2,479 audit comments still match prg.bin at the stated PRG offset

Pass 1 correction - six command handlers recovered (new tool
_tools/recode_region.py).  ScriptCommandTable ($EFDD) is read by the traced
instruction at $EFCC, and six of its entries point at $F00A, $F022, $F03A,
$F052, $F062 and $F072 - all of which the tracer had left as data, and two
of which it had mis-split across the 'jmp $EF61' at $F01F and $F04F.
Those 120 bytes are code here, decoded straight from the ROM; the six
handlers tile $F00A-$F081 exactly.  The same gap exists in the promoted
'Pac-Man (U)' dump, which has not been corrected - recorded in both READMEs.

Residue (documented, not guessed): the unreached main game logic at
$C45A-$C55F is still .byte data.  It is code - the tracer's own decoder
walks it cleanly and the dispatch table at $C511 points into it - but
nothing reaches it, so it cannot be entered without a guess.  The same gap
exists in the promoted 'Pac-Man (U)' dump.  Re-deriving it is a Pass 1 job;
a Mesen Code Data Logger capture is the tool the repo uses for it.

Docs: root README.md / TODO.md / AGENTS.md updated - 32 promoted, 4 in
_wip/; a per-project detail entry added for the Tengen dump.

Promote Pyramid (U): Pass 1 corrected, Pass 2/3 complete, whole-ROM byte-identical

Move _wip/NROM/Pyramid (U) to NROM/ and switch the build from a PRG-only
compare to a whole-ROM one:

  - header.s/chr.s added (one-line .incbin of header.bin / chr.bin)
  - linker.cfg gains HEADER ($0000, $0010) and CHR ($0000, $2000)
    areas ahead of PRG ($C000, $4000)
  - rom.nes symlink to 'Pyramid (U) (Sachen).nes'
  - reconstructed.nes is 24,592 bytes, MD5 aa285ff17f25dd05da5996b7466c59e2
    - equal to the original ROM; the header/prg/chr splits were checked
    against the original before promotion and are byte-exact

Pass 1 correction - the committed split was a strict subset of the correct
one.  This game dispatches through 'jmp' trampoline tables that live
*inside* the data regions, and the tracer cannot follow a jmp there, so
828 bytes of code were still marked as data.  Four such tables were found
($C01E 3 entries, $C02A 6, $C042 2, $C054 5) plus ten more entries at
$C000-$C01B; all sixteen targets decode as valid instructions.  Seeding
them, the $C800 boot mainline and six further code starts recovers the
whole lot, plus a five-byte stub at $DF89 (lda $33 / jmp $DECB) that sat
in a hole between two routines.  The re-trace loses NO committed code byte
and takes the split from 34.5% to 39.6% (3,130 instructions / 6,493 code
bytes).  'make regen' reproduces it, so the split stays verifiable.

Pass 2 - a fresh map derived from this dump's own committed split:
  - 428 Label_XXXX definitions renamed; zero Label_ residue
  - 320 raw $XXXX jsr/jmp operands resolved; zero raw $XXXX branch
    operands remain
  - 431 routine entries and the 32 data blocks named from the code
  - the internal branch-target names are derived mechanically from the
    branch that reaches them by the new _tools/derive_branch_names.py
    (beq -> OnZero, bne -> OnNonzero, bcc/bcs -> the carry cases, a
    backwards branch -> Loop)
  - recorded in routinemap.tsv

Pass 3:
  - 24 semantic zero-page aliases, each applied only where its role is
    proven; the 57 slots that stay neutral are each listed with the reason
    in locals.inc (the neutral set lives in zp_aliases.inc so that
    'make regen' can rebuild locals.inc from prg.bin)
  - 32 data tables named - TaskVectorTable1/2, LevelScriptData,
    MusicPeriodTable, SoundEnvelopeTable, the actor tables - recorded in
    data_region_names.tsv
  - apply_symbols.py reports 0 substitutions pending and 0 residue; no
    hardware register is left as a raw literal
  - the audit comments are now canonical on every line, data included
    (the old file carried only 'PRG:$xxxx' on its 1,358 data lines);
    all 3,762 audit comments match prg.bin at their stated PRG offset

Kept as-is, not 'cleaned up':
  - sta $4100 stays a raw operand.  The iNES header claims mapper 0 but
    the boot code writes past the NES register space; the ROM does not
    explain it, so it is recorded rather than guessed
  - the 'A'/'V' check on RAM $0120/$0121 and its seed/clear routines
    are named for what they do, not for what they are for
  - the ninth entry of the $C3A6 task vector table ($D820) is a junk
    slot and stays data

Docs: root README.md / TODO.md / AGENTS.md updated - 33 promoted, 3 in
_wip/; a per-project detail entry added.

Hogan's Alley (JU): Pass 1 correction, Pass 2, Pass 3, promoted to NROM/

The light-gun game whose engine dispatches through *inline* tables:
`IndirectCall` at $C34D pops the return address of the `jsr` that called
it and reads a 16-bit handler pointer from the word that follows, so all
six handler tables ($C124 19 entries, $C219 4, $C89C 14, $CDD1 1, $D234 2,
$D3D6 14) live inside the code stream and the static tracer cannot follow
them.

Pass 1 correction.  The committed split was a strict subset of the correct
one -- 41.8% of the PRG was classified as code.  A fresh Mesen Code Data
Logger capture was merged with the four captures already in the folder
(hogans_merged.cdl, the OR of five per-byte flag arrays, 6,544 code bytes)
and _tools/cdl_reclass.py rewrote the split to match what the CPU actually
fetched: 1,216 bytes moved from data to code, five the other way, 59 labels
emitted.  The split is now 49.1% code (3,950 instructions, 8,041 bytes).
The four branch targets the reclassifier could not prove were turned into
labels by the new _tools/resolve_raw_branches.py.

Pass 2.  206 routine entries hand-named from this dump's own code and 413
internal branch targets derived mechanically by _tools/derive_branch_names.py:
630 Label_XXXX definitions gone, 484 raw $XXXX call operands resolved, 15
call targets the tracer had never labelled given a label.  Recorded in
routinemap.tsv.  No SubC<addr> residue was needed -- every entry the engine
reaches is named after what it does.

Pass 3.  60 semantic zero-page aliases, each applied only where its role is
proven (zp_aliases.inc, zp_alias_sites.tsv); the slots that stay neutral are
each listed with the reason.  All 34 data blocks named
(data_region_names.tsv).  apply_symbols.py reports 1 residue: `sta a:$00B4,y`
at $C203, the same address as Zp40/ActorPalette but forced to absolute
addressing, so it must stay numeric.

Promotion.  header.s, chr.s and a HEADER/PRG/CHR linker.cfg added, rom.nes
symlinked to the original ROM; the whole-ROM cmp passes on the first
promoted build.  There is deliberately no `make regen` target: the Pass 1
split here is the static trace corrected by a CDL capture, and the base the
correction was applied to is not what the current _tools/nesdis.py
produces, so prg.s is the maintained source of truth.

Tools changed:
  nesdis.py             --split/--note/--provenance options, so a data
                          region can carry its own name and explanation;
                          a forced-data address is no longer reported as a
                          recovered routine entry
  apply_pass2_map.py    can create the label for a call target the tracer
                          left unlabelled; no longer double-labels it
  apply_zp_aliases.py   --at-file, an address-based per-site list
  derive_branch_names.py keeps the map's own header instead of writing a
                          fixed one
  resolve_raw_branches.py  new: turns `bXX *+$NN` operands into labels
  build_hogans_map.py   new: the hand-written Pass 2 map builder

The existing regen pipelines (MUSCLE (U), Urban Champion (JU)) still
reproduce prg.s byte for byte.

Apply the symbols.inc register names at Pass 1; fix a dropped byte in cdl_reclass

nesdis.py now names the hardware registers as it renders the operands, so a
project's Pass 1 output already reads `lda PPUSTATUS` instead of `lda $2002`
and the Pass 3 apply_symbols.py step has nothing left to do for them.

  * nesdis.py --symbols FILE reads a symbols.inc-style file and substitutes
    the register names.  Only unambiguous entries in the $2000-$4017 window
    are used: $4017 is both JOY2 and APUFRAMECOUNTER, so it stays numeric
    and apply_symbols.py reports it as multi-alias residue, exactly as
    before.  The default is the symbols.inc next to --out, so a new project
    gets the names without asking; --no-symbols opts out.
  * The renderer records the operand's numeric value on the Insn, because
    operand_value() used to re-parse the operand text and could no longer
    read a name.
  * The controller bit masks in symbols.inc (PAD_A and friends) are
    constants, not addresses, and are still never substituted.

MUSCLE (U) and Urban Champion (JU) keep --no-symbols: their committed
prg.s was produced with the registers named by the Pass 3 apply_symbols.py
step, and the columns in those files reflect the in-place substitution.
Adding the missing apply_symbols.py step to both regen pipelines makes
them reproduce their committed prg.s byte for byte again - neither did
before this change (MUSCLE was 440 lines out, Urban Champion 772).

cdl_reclass.py had a bug that cost a byte: a region whose last source row
straddled the region's end was replaced by a regeneration of the region
only, so the tail of that row was dropped.  Mario Bros (JU) hit it at
$C595, where the rebuild came out one byte short and every label after it
shifted.  A region now covers the whole rows it replaces.

pass2.py reflow takes an optional column argument; the default is
unchanged (the ';' lands on the same column as before).

Mario Bros (JU): Pass 1 correction, Pass 2, Pass 3, promoted to NROM/

A two-player platformer whose handler tables are *inline*: the pointers sit
in the middle of the code stream, right after the `jsr` that reads them, so
the static tracer could never follow them.

Pass 1 correction.  The committed split was a strict subset of the correct
one -- only 72.0% of the PRG was classified as code.  A Mesen Code Data
Logger capture of this ROM (mario_mesen.cdl, 10,915 code bytes) showed
1,010 bytes the tracer had left as data were code; two branch targets the
capture never reached ($E4CB and $E639) were forced with --override for 57
more, so 1,067 bytes moved from data to code and 22 moved the other way.
The split is now 78.4% code (6,210 instructions, 12,847 bytes).  The three
branch targets the reclassifier could not prove were turned into labels by
_resolve_raw_branches.py, which now refuses to put a label on a `.byte` row.

Pass 2.  206 routine entries and 519 internal branch targets: 931
Label_XXXX definitions gone, 51 raw $XXXX call operands resolved and 12 call
targets the tracer had never labelled given a label.  Zero SubC residue --
the 185 entries a previous session had left as address-derived residue were
all named from this dump's own code.  Recorded in routinemap.tsv.

Pass 3.  25 semantic zero-page aliases, each applied only where its role is
proven (zp_aliases.inc); the slots that stay neutral are each listed with the
reason.  35 data tables named -- GameStateHandlerTable, EnemyBehaviourTable,
EnemyScriptTable, EnemyTypePointerTable, SoundRoutineTable,
NoteFrequencyTable and the rest -- and recorded in
data_region_names.tsv.  apply_symbols.py reports 0 residue.

Promotion.  header.s, chr.s and a HEADER/PRG/CHR linker.cfg added, rom.nes
symlinked to the original ROM; the whole-ROM cmp passes on the first
promoted build.  There is deliberately no `make regen` target: the Pass 1
split here is the static trace corrected by a CDL capture, and the base the
correction was applied to is not what the current _tools/nesdis.py
produces, so prg.s is the maintained source of truth.

Tools:
  apply_pass2_map.py     renames a label of any spelling -- SubC<addr> is
                          the honest residue form -- and its references
                          follow it; one combined pattern, so a 16,000-line
                          file does not need a substitution per label
  resolve_raw_branches.py refuses to label a data row
  build_mario_map.py      new: the hand-written Pass 2 map builder

Remove the old _wip/NROM/Mario Bros (JU) folder (promoted to NROM/)

Mario Bros (JU): add the promoted-tier header, CHR, rom.nes symlink and zero-page aliases

Moves _ROMS/<ROM> into _wip/<MAPPER>/<ROM>

Sync the docs and the skeleton tool with the 857-project _wip tier

The _wip/ tier now holds 857 projects across 30 mapper folders, all
building byte-identical for the whole ROM.  README.md, TODO.md and
AGENTS.md still described the old 39-project tier, so bring them in line
with WIP.md, which carries the tier's index.

The tier is no longer 39 projects of NROM-256 with a 16/32 KB PRG:
only two projects have a 16 KB PRG, 151 have 32 KB, 523 have 128 KB and
one has 1.5 MB, so most of it is a banked mapper whose image does not fit
the 6502's address space.  Those projects link their MEMORY areas at .nes
file offsets rather than CPU addresses, which is the only option and the
honest model; the 39 older projects keep the CPU-address layout because
their PRG really is one contiguous window.

make_skeleton.py gains the two layouts (--layout flat|cpu), the board
name for the mapper, and a fix for find_rom() mistaking the build
output reconstructed.nes for the source ROM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-20 16:44:06 -04:00

7.2 KiB

1128PtrHi
2130PtrLo
3142PtrLo
4145PtrHi
5176VBlankTimer
6236PtrLo
7238PtrHi
8252PtrLo
9254VBlankTimer
10262PtrLo
11264PtrHi
12373VBlankTimer
13377PtrLo
14391VBlankTimer
15438PtrLo
16440PtrHi
17627SprIndex
18633SprCount
19651SprCount
20664SprCount
21682SprCount
22690SprCount
23713SprCount
24737SprIndex
25752SprCount
26774SprIndex
27779SprCount
28801SprCount
29828SprCount
30841SprIndex
31854SprCount
32868SprCount
33921PtrLo
34923PtrHi
35937SprIndex
36944PtrLo
37946PtrHi
38995PtrLo
391000ObjIndex
401024SprIndex
411029SprIndex
421080SprIndex
431084GameState
441098SprIndex
451130GameState
461178Ptr2Lo
471213PtrLo
481215PtrHi
491217Ptr2Lo
501218ObjIndex
511225PtrLo
521237SprIndex
531253PtrLo
541255PtrHi
551257Ptr2Lo
561258ObjIndex
571265PtrLo
581358ObjIndex
591363ObjIndex
601386BtnState
611441BtnState
621491VBlankTimer
631494VBlankTimer
641524GameState
651556GameState
661563ObjIndex
671573BtnState
681585GameState
691603BtnState
701616GameState
711711SprIndex
721715PtrLo
731717PtrHi
741719Ptr2Lo
751732VBlankTimer
761734VBlankTimer
771830VBlankTimer
781832VBlankTimer
791837SprIndex
801841PtrLo
811843PtrHi
821845Ptr2Lo
831949BtnState
841952BtnState
851967ObjIndex
861998ObjIndex
872024Ptr2Lo
882049SprIndex
892061SprIndex
902075SprIndex
912123GameState
922207GameState
932234SprIndex
942242ObjIndex
952255GameState
962276SprCount
972279GameState
982292GameState
992307GameState
1002327ObjIndex
1012355SprIndex
1022397SprIndex
1032409SprIndex
1042431SprCount
1052446ObjIndex
1062463ObjIndex
1072489Ptr2Lo
1082492SprCount
1092508SprIndex
1102565FrameCounter
1112576ObjIndex
1122595FrameCounter
1132647ObjIndex
1142695Ptr2Lo
1152711ObjIndex
1162780ObjIndex
1172839PtrLo
1182857BtnState
1192861BtnState
1202886SprIndex
1212902GameState
1222909BtnState
1232984BtnState
1242990BtnState
1253110ObjIndex
1263185SprIndex
1273227ObjIndex
1283240ObjIndex
1293257ObjIndex
1303303FrameCounter
1313320FrameCounter
1323322ObjIndex
1333336PtrLo
1343340PtrHi
1353371Ptr2Lo
1363385PtrHi
1373386BtnState
1383414PtrLo
1393433Ptr2Lo
1403435PtrHi
1413580FrameCounter
1423597BtnState
1433637BtnState
1443652SprIndex
1453686PtrHi
1463712Ptr2Lo
1473714PtrLo
1483733FrameCounter
1493783FrameCounter
1503824BtnState
1513890SprCount
1523892BtnState
1533922BtnState
1543925SprCount
1553941BtnState
1563973SprCount
1573986BtnState
1584015BtnState
1594151BtnState
1604167BtnState
1614183FrameCounter
1624207PtrHi
1634209BtnState
1644230PtrLo
1654231BtnState
1664236PtrLo
1674250PtrLo
1684261PtrLo
1694263Ptr2Lo
1704278BtnState
1714327ObjIndex
1724422PtrLo
1734434Ptr2Lo
1744456PtrLo
1754470PtrLo
1764481SprIndex
1774484BtnState
1784533PtrHi
1794603GameState
1804623ObjIndex
1814626Ptr2Lo
1824666Ptr2Lo
1834671ObjIndex
1844698PtrHi
1854701PtrLo
1864703Ptr2Lo
1874709SprIndex
1884727FrameCounter
1894741PtrHi
1904744PtrLo
1914746Ptr2Lo
1924751ObjIndex
1934769PtrHi
1944771FrameCounter
1954773PtrLo
1964775Ptr2Lo
1974790FrameCounter
1984802SprIndex
1994808GameState
2004815PtrHi
2014817PtrLo
2024819Ptr2Lo
2034884FrameCounter
2044897PtrHi
2054899PtrLo
2064915Ptr2Lo
2074918SprCount
2084958ObjIndex
2094992PtrLo
2104996PtrHi
2114998Ptr2Lo
2125005BtnState
2135119PtrLo
2145123PtrHi
2155234Ptr2Lo
2165248SprIndex
2175301PtrLo
2185303PtrHi
2195305Ptr2Lo
2205359ScorePtrHi
2215362ScorePtrLo
2225371ScorePtrHi
2235373ScorePtrLo
2245376ScorePtrLo
2255379ScorePtrLo
2265523ObjIndex
2275601PtrLo
2285603PtrHi
2295605Ptr2Lo
2305655SprIndex
2315661Ptr2Lo
2325723SprIndex
2335729Ptr2Lo
2345773Ptr2Lo
2355775PtrHi
2365777PtrLo
2375794SprIndex
2385800Ptr2Lo
2395816BtnState
2405902PtrHi
2415904PtrHi
2425909PtrHi
2435911PtrHi
2445981PtrHi
2455983PtrLo
2466026PtrLo
2476028PtrHi
2486144PtrHi
2496146PtrLo
2506163Ptr2Lo
2516194Ptr2Lo
2526244PtrHi
2536264PtrLo
2546271PtrLo
2556317Ptr2Lo
2566361PtrHi
2576381PtrLo
2586384PtrLo
2596426PtrLo
2606427PtrHi
2616429Ptr2Lo
2626483ObjIndex
2636518ObjIndex
2646531ObjIndex
2656536BtnState
2666564PtrLo
2676566PtrHi
2686570ObjIndex
2696576PtrHi
2706614PtrLo
2716616PtrHi
2726632Ptr2Lo
2736664ObjIndex
2746687PtrLo
2756693PtrLo
2766706BtnState
2776759ObjIndex
2786778ObjIndex
2796814PtrHi
2806954PtrLo
2817036Ptr2Lo
2827041Ptr2Lo
2837044Ptr2Lo
2847047Ptr2Lo
2857128Ptr2Lo
2867130PtrLo
2877134Ptr2Lo
2887136PtrHi
2897458PtrLo
2907462PtrHi
2917566PtrLo
2927570PtrHi
2937734ScorePtrLo
2947736ScorePtrHi
2957789ScorePtrLo
2967821PtrLo
2977823PtrHi
2987825Ptr2Lo
2997885ScorePtrHi
3007887ScorePtrLo
3017919ScorePtrHi
3027921ScorePtrLo
3037970ScorePtrHi
3047972ScorePtrLo
3058208PtrLo
3068240PtrLo
3078244PtrLo
3088373PtrHi
3098375PtrLo
3108377Ptr2Lo
3118479PtrLo
3128481PtrHi
3138483Ptr2Lo
3148503PtrLo
3158604SprIndex
3168641SprIndex
3178680PtrLo
3188682PtrHi
3198694PtrLo
3208696PtrHi
3218711Ptr2Lo
3228747PtrLo
3238749PtrHi
3248900PtrLo
3258902PtrHi
3268916Ptr2Lo
3279016PtrLo
3289033PtrLo
3299125PtrLo
3309140PtrLo
3319146PtrLo
3329149PtrLo
3339264SprCount
3349271PtrLo
3359273PtrHi
3369275Ptr2Lo
3379350SprIndex
3389614PtrHi
3399643PtrHi
3409647PtrHi
3419686ObjIndex
3429698BtnState
3439775SndChannel
3449808SndChannel
3459983SndChannel
34610096PtrHi
34710103GameState
34810171PtrLo
34910186Ptr2Lo
35010395GameState
35110411SndChannel
35210479SndChannel
35310533SndChannel
35410619SndChannel
35510839SndChannel
35611005FrameCounter
35711009SndChannel
35811096SndChannel
35911208ObjIndex
36011239GameState
36111241ObjIndex
36211465GameState
36311566SndChannel
36411640GameState
36511670GameState
36611685SndChannel
36711687SndChannel
36811704GameState
36911721PtrHi
37011725PtrLo
37111727Ptr2Lo
37211732SndChannel
37311757PtrLo
37411761PtrLo
37511763PtrHi
37611765Ptr2Lo
37711974GameState
37812030GameState
37912055PtrLo
38012057PtrHi
38112077Ptr2Lo
38212130GameState
38312156FrameCounter
38412194GameState
38512208GameState
38612276GameState
38712296SndChannel
38812383GameState
38912501FrameCounter
39012512SndChannel
39112516ScorePtrHi
39212518ScorePtrLo
39312521SndChannel
39412567ScorePtrHi
39512569ScorePtrLo
39612585ScorePtrHi
39712587ScorePtrLo
39812603ScorePtrHi
39912605ScorePtrLo
40012626ScorePtrHi
40112645ScorePtrLo
40212658ScorePtrLo
40312672SndChannel
40412685SndChannel
40512808SndChannel
40612901SndChannel
40713018SndChannel
40813166PtrLo
40913168PtrHi
41013170Ptr2Lo
41113177PtrLo
41213179PtrHi
41313181Ptr2Lo
41413196SndChannel
41513242PtrLo
41613272Ptr2Lo
41713275PtrLo
41813297PtrLo
41913298Ptr2Lo
42013376SndChannel
42113438SndChannel
42213451SndChannel
42313457SndChannel
42413479SndChannel
42513485SndChannel
42613584SndChannel
42713661ScorePtrHi
42813665ScorePtrLo
42913667ScorePtrHi
43013704ScorePtrLo
43113705ScorePtrLo
43213730ScorePtrLo
43313731ScorePtrLo
43413746PtrLo
43513748PtrHi
43613761Ptr2Lo
43713764ScorePtrHi
43813765PtrHi
43913766ScorePtrLo
44013767PtrLo
44113849SndChannel
44213865SndChannel
44313880SndChannel
44413884SndChannel
44513975SndChannel
44613978SndChannel
44714045SndChannel
44814075SndChannel
44914081SndChannel
45014113SndChannel
45114117ScorePtrHi
45214119ScorePtrLo
45314162GameState
45414188GameState
45514206GameState
45614233SndChannel
45714251GameState
45814297GameState
45914300SndChannel
46014321GameState
46114337GameState
46214363GameState
46314423GameState
46414493SndChannel
46514506GameState
46614585Ptr2Lo
46714591PtrHi
46814616PtrLo
46914617Ptr2Lo
47014643PtrHi
47114684VBlankTimer
47214687VBlankTimer
47314701PtrHi
47414703Ptr2Lo
47514725Ptr2Lo
47614758PtrLo
47714761PtrLo
47814764VBlankTimer
47914779VBlankTimer
48014820PtrLo
48114826PtrLo
48214827PtrLo
48314829PtrHi
48414830PtrHi
48514843PtrLo
48614869PtrLo
48714881PtrLo
48814913Ptr2Lo
48914926PtrHi
49014929PtrHi
49114952PtrHi
49214963PtrHi
49314978Ptr2Lo
49415020Ptr2Lo
49515023Ptr2Lo
49615040PtrHi
49715043PtrLo
49815062Ptr2Lo
49915069PtrLo
50015070PtrLo
50115072PtrHi
50215073PtrHi
50315173PtrHi
50415187PtrLo
50515189PtrHi
50615339PtrHi
50715354Ptr2Lo
50815355Ptr2Lo
50915358Ptr2Lo
51015397PtrHi
51115398PtrHi
51215401PtrHi
51315402Ptr2Lo
51415404Ptr2Lo
51515418Ptr2Lo
51615432PtrHi
51715446PtrHi
51815449Ptr2Lo
51915520PtrLo
52015523PtrLo
52115592PtrLo
52215594PtrLo
52315600PtrLo
52415601PtrLo
52515602PtrLo
52615604PtrLo
52715608PtrLo
52815738FrameCounter
52915774PtrLo
53015779PtrLo
53115792PtrLo
53215905PtrLo
53315908PtrLo
53416237FrameCounter
53516241FrameCounter
53616245FrameCounter
53716249FrameCounter
53816253FrameCounter
53916257FrameCounter
54016261FrameCounter
54116265FrameCounter
54216269FrameCounter