3.5 KiB
3.5 KiB
AGENTS.md
What this repo is
Eleven AI-generated disassemblies of NES ROMs. The contract (stated in PROMPTS.md and verified by make in every copilot/ folder) is byte-identical rebuilds: reconstructed.nes must match the original ROM exactly. Not for distribution (README.md).
Layout
- Each project owns a folder with a
copilot/build dir (prg.s,header.s,chr.s,linker.cfg,symbols.inc,locals.inc,Makefile, and a copy/symlinkrom.nes) and a per-projectOVERVIEW.mdat the folder root (power-on flow analysis). - Root
OVERVIEW.mdis the index: vectors, build fixes, and summary for all 11 projects. Keep it in sync when a project changes — its DK Jr. entries drifted badly before being corrected. PROMPTS.mdis the workflow contract.default_project.tar.gzis the empty-project skeleton (prg.s, symbols.inc, linker.cfg, Makefile, locals.inc)._ROMS/is the master ROM store;_tools/hassplitnes.pyandchr2gif.py.
Commands
cd "<Project>/copilot" && make # builds reconstructed.nes, then cmp vs rom.nes
make's default target includes the byte-identity cmp — a build that doesn't print "Byte-identical ROM verified." is a failure. Requires ca65/ld65 on PATH.
Irreversible conventions (do not "clean up" past these)
- Every instruction carries a trailing
; PRG:$xxxx AA BBcomment with PRG offset and exact emitted bytes. This is the byte-identity audit trail — preserve it even while renaming labels or restructuring files. - Unreached/unresolved bytes stay as data (
Label_/Data/.byteor.incbinblocks with ROM provenance), never deleted or reformatted. - Routine headers follow the template in
prg.s: global + local description, parameters, returns, clobbers. - Two separate symbol files:
symbols.inc= NES hardware constants only;locals.inc= zero-page and forward references. Unresolved zero-page bytes keep neutralZpXXnames rather than speculative names. - Pass discipline: Pass 1 = code/data split (stop for review), Pass 2 = label replacement, Pass 3 = semantic naming of data tables/structures. Do not skip straight to guessy rewrites.
Hard-won quirks (details in root OVERVIEW.md per-project "Build fix")
- The flat disassembler mislabels
bneasbpl; fixes usebne *-$XXto reproduce the original bytes (Clu Clu Land, Defender 2, Excitebike). - Zero pages are reused across modes; aliases may be required in
locals.inc(e.g.RandomStateAlt = $E4besideRandomState0 = $54). - Donkey Kong Jr. is architecturally different: reset entry is $C66E, the reset path idles forever in an LFSR loop, and the entire frame state machine runs inside NMI. Its
DeferredTaskHandlerTableentry 0 deliberately mirrors the IRQ vector word at $BFFE. - IRQ vectors often point at unused/data targets in these games — verify before assuming a handler is broken.
- Unlicensed titles break static-trace assumptions: Pyramid (U) pokes a mapper unlock at
$4100(beyond the register space) despite a mapper-0 header, and dispatches throughjmp ($0002)built from RAM — trace via its two queue tables ($C3A6,$CCD5), and do NOT fall-through-seed gaps that followrts/jmp/brk(that misclassifies data as code). - ROM filenames contain spaces; builds
incbina space-freerom.nesinsidecopilot/. Keep that copy/symlink working and don't rename it. .gitignorecontainsROMS/*but the actual directory is_ROMS— the pattern matches nothing, so ROM binaries stay tracked. Check before committing large blobs.