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

Last updated: October 16, 2026

Kajar

Chrono Trigger

A byte-exact decompilation of the 1995 classic, one matched routine at a time

But… the future refused to change.

Game Over screen
249,251code bytes matched
100.00%of reachable 65C816 code in ROM
23,638data bytes matched
3,736functions matched
3,736functions readable
3,736functions verified
249,251bytes of 65C816 code (SPC700 and the packed $C3 module apart)
100.00%of the SPC700 sound driver verified (6,543 of 6,543 bytes)
70.17%of the packed $C3 module's code found so far verified (14,750 of 21,020 bytes)
2026-08-06: 10,013 bytes matched, 60 matched2026-08-07: 12,583 bytes matched, 76 matched2026-08-09: 13,752 bytes matched, 85 matched2026-08-10: 13,914 bytes matched, 86 matched2026-08-11: 16,291 bytes matched, 94 matched2026-08-12: 19,800 bytes matched, 104 matched2026-08-14: 23,885 bytes matched, 164 matched2026-09-19: 25,363 bytes matched, 186 matched2026-09-22: 26,000 bytes matched, 206 matched2026-09-24: 26,828 bytes matched, 207 matched2026-10-08: 128,218 bytes matched, 1,715 matched, 1,715 readable, 1,715 verified2026-10-09: 154,931 code bytes matched, 10,444 data bytes, 2,184 matched, 2,184 readable, 2,184 verified2026-08-06 · 10,013 B2026-10-09 · 154,931 B
Matched code bytes by working day, from the code repo's history (days before the code/data split count every matched byte).

Every number above is generated; see Progress.

Welcome to ChronoRET, a byte-exact matching decompilation of Chrono Trigger (SNES, US 1.0).

The goal is hand-labeled 65816 assembly that assembles back to a ROM that is bit-for-bit identical to the original 1995 cartridge. A routine only reaches the main branch once it is matched byte for byte, written to the project's readability standard, and approved by an independent review.

This project is not affiliated with or endorsed by Square or Square Enix in any way.


Project at a glance

Bank What is matched there
$C0 The field engine: game loop, frame wait and NMI handler, location loading, map scrolling, object motion, the event script opcodes, the sprite system, and the reset code, header and vectors at the top of the bank
$C1 The battle engine: BattleSys_Main and its turn lists, the enemy behaviour scripts, the PC command runner, action scripts, the battle menu, targeting and status bar
$C2 The scene mode (tasks, scripts, sprite list, scene loading) and the text window decoder
$FD MainInit, the battle helpers bank $C1 calls with JSL, the field HDMA set-up and the location animation set-up
$CC, $CF, $FF Copies of matched code kept in other banks: the 8×8 multiply ($CC), a scaled sine and a four-digit number formatter ($CF), the wave tables ($FF)

What the 100% covers, and what is left

The 100% is the game's 65C816 code: every byte of it that can run is matched, readable and verified. It is not the whole project. Still to do:

  • The packed $C3 module (the jet-bike race), about 34 KB once unpacked, held compressed in the ROM. It is built from source and packed back to the exact bytes, and about 70% of its code is matched so far (the race, its display and several smaller scenes); the rest is still the ROM's bytes.
  • The game's data: graphics, music, maps, text, scripts and tables, about 3.9 MB. Every byte of it is mapped and placed by the source, and the compressed blocks are rebuilt by the project's own packer, but the contents still come from files extracted from the player's own ROM. The game's text, 101 tables and palettes, and the location event scripts are now in readable form, rebuilt to the exact bytes; turning the rest into readable form (battle and scene scripts, graphics, maps, music) is the long part that remains; see DATA_PLAN.md in the code repository.

The build no longer starts from a copy of the original: it assembles everything onto a blank image, and needs the player's own ROM only to extract the data files. No game data is stored in the project.

How much of each bank is matched, and at which level, is generated on the ROM Map and Progress pages.


Start here


Reference

Matched regions

What is matched, bank by bank, is on the ROM Map, generated from the code repository on every update, so it is never out of date. The figures by level, bank and day are on Progress, and every routine of a system is listed on its page under Systems.

The 4 MB ROM is mostly graphics and music data; only about 240 KB is executable 65816 code.

Key documents

Document What it covers
Architecture How the banks fit together: boot, the field frame, bank $C2, the battle
Systems One page per game system, with its routines
Glossary 65816 and SNES terms explained
asar Quirks Assembler gotchas that affect byte-exactness
Contributing Toolchain setup, match workflow, commit rules

Methodology

A routine goes through these steps before it reaches the main branch:

  1. Draft — make draft ADDR=C1:3714 (tools/draft.py) disassembles the routine from its address, tracking the M/X flags, DP and DB, and writes asar source that already uses every name the project has for its operands. It checks that the draft assembles to the original bytes.
  2. Make it readable — the matcher names what the draft could not (RAM, constants, calls, the routine itself) and writes the header: what the routine is for, its CPU state on entry and exit, and anything a reader would not guess. Unknown meanings stay hedged ("probably", Unk names).
  3. Gate — make gate runs the byte-for-byte diff (make diff), proves that every byte the source claims is really emitted by it (make verify), and runs the readability lint (tools/lint_readability.py). The ; Callers block of each header is generated by tools/callers.py, never written by hand.
  4. Review — someone who did not write the routine checks that its names and comments tell the truth. The verdict is a row in a review round file (symbols/reviews/rNNN.csv) that carries the routine's source hash, so any later edit sends it back for review.

Each level includes the one before: matched → readable → verified. The figures are computed by tools/progress.py from the source and the review log; generated files are not committed, and no number is typed by hand.


Tools and source only — no ROM data, no extracted assets. To contribute or verify matches you need your own legally obtained copy of Chrono Trigger (SNES, US 1.0).

ROM SHA-256:

06d1c2b06b716052c5596aaa0c2e5632a027fee1a9a28439e509f813c30829a9