Files
disasm/AGENTS.md
T
tmerritt 3877214637 update of Circus WIP
start of Pyramid wip
2026-10-16 16:17:08 -04:00

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/symlink rom.nes) and a per-project OVERVIEW.md at the folder root (power-on flow analysis).
  • Root OVERVIEW.md is 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.md is the workflow contract. default_project.tar.gz is the empty-project skeleton (prg.s, symbols.inc, linker.cfg, Makefile, locals.inc). _ROMS/ is the master ROM store; _tools/ has splitnes.py and chr2gif.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 BB comment 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/ .byte or .incbin blocks 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 neutral ZpXX names 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 bne as bpl; fixes use bne *-$XX to 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 = $E4 beside RandomState0 = $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 DeferredTaskHandlerTable entry 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 through jmp ($0002) built from RAM — trace via its two queue tables ($C3A6, $CCD5), and do NOT fall-through-seed gaps that follow rts/jmp/brk (that misclassifies data as code).
  • ROM filenames contain spaces; builds incbin a space-free rom.nes inside copilot/. Keep that copy/symlink working and don't rename it.
  • .gitignore contains ROMS/* but the actual directory is _ROMS — the pattern matches nothing, so ROM binaries stay tracked. Check before committing large blobs.