Kajar notes of ChronoRET, rebuilding Chrono Trigger one matched routine at a time

Last updated: October 9, 2026

Contributing

The code repo's own CONTRIBUTING.md, STYLE.md and REVIEW.md are the rules; this page is a summary of how the work goes.

Ways to help

  • Bank mapping: identifying what lives where in ROM, even roughly, before anything is matched.
  • Function matching: draft, make readable, gate, review (below).
  • Review: checking routines someone else matched, so they reach verified.
  • Tooling: diffing, cross-references, progress tracking, CI.
  • Data and graphics cataloguing: identifying compressed blobs, tile data and their formats (separate from code matching, but needed eventually).

Ground rules

  • No ROM data, headers or extracted assets in commits. Ever. Tools and source only.
  • Matched, readable and reviewed, or not on main. A literal transcription of the disassembly is fine on a work branch, never on main.
  • Byte-exact means byte-exact. A routine that "looks equivalent" but doesn't reassemble identically isn't matched.
  • Say how you know. A name or meaning that is inferred says so, and from what ("inferred: only written by the revive path"); an unknown one stays an Unk name or is hedged ("probably"). Community documents and other disassemblies are leads, not evidence.
  • Keep the original's quirks. Dead code, a redundant instruction, an apparent bug: kept, named and documented, never "fixed".
  • No generated numbers in docs. Counts and percentages come from tools/progress.py; never type one by hand, and never commit symbols/functions.csv or symbols/progress.json.
  • One pull request per logical unit: a cluster of routines, a tooling change. Bring a branch up to date by merging main, never by rebasing.

The workflow

  1. Pick the next target from the code repo's NEXT.md.
  2. Draft it: make draft ADDR=C1:3714 (tools/draft.py) disassembles the routine, tracking M/X, DP and DB, and writes asar source with a header skeleton and every operand the project already has a name for, then checks it assembles to the original bytes. make xref ADDR=... (tools/xref.py) lists every call or jump to an address.
  3. Make it readable (STYLE.md): named RAM (asm/include/ram_*.inc), structs, calls and constants; explicit .b/.w/.l widths (see asar Quirks); no hand-encoded opcodes; a header with what the routine is for and its CPU state on entry and exit (M, X, DP, DB). Calls into unmatched code go through label-only stubs in asm/include/unmatched*.asm.
  4. Generate the Callers blocks: python3 tools/callers.py --update rewrites the ; Callers block of every header from tools/xref.py's confirmed call sites. The block is generated, not reviewed, and left out of the source hash; run it after matching code and after merging main. Hand-written remarks about callers go on a ; Callers note: line.
  5. Gate: make gate runs make diff (byte-exact), make verify (every byte the source claims is really emitted by it) and make lint (tools/lint_readability.py, including the header rules HEADER, CALLERS, SIZE, UNMATCHED and DPDB).
  6. Review: someone who did not write the routine checks a whole cluster against the ROM: every claim true, the CPU state right, names that don't mislead, unknowns hedged. The verdict is one row per routine in a new round file, symbols/reviews/rNNN.csv (address,name,date,reviewer,verdict,source_hash,notes), with the routine's source_hash from symbols/functions.csv. Any later edit to the routine changes its hash and sends it back for review. tools/progress.py --update then marks it verified.
  7. Session end: tools/end_session.sh.

A change to STYLE.md or to the lint's rules is its own commit, approved by the maintainer and logged under "Decisions" in STATUS.md, so no routine is judged by a rule its own author just wrote.

Getting started

  1. python3 tools/check_env.py to confirm your toolchain (asar 1.91, Python 3.10+, make).
  2. Drop your own legally dumped ROM in roms/chrono_trigger.sfc (never committed; see Target ROM).
  3. make diff should report a 100% match.
  4. Read STATUS.md for where things stand and NEXT.md for the queue.