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

Devlog

Notes on the Chrono Trigger matching decompilation project, one post per working day. Written in plain English — if you don't know 65816 assembly, check the Glossary first.

16 October 2026: the credits, and a future that refused to change

The fifth and sixth batches of the packed $C3 module take it from half to 70%. The module is a block of code the game keeps compressed in the ROM and unpacks into RAM at $7E:3000 when it needs it; the jet-bike race was its first part to be matched. This batch is three of its smaller programs, each a scene of its own.

Continue reading →

15 October 2026: how the sound driver reads a score

The third batch of the SPC700 sound driver is the part that plays the music: the pass that walks through every voice's track many times a second. With it the driver stood at two thirds of its 6,543 code bytes. The fourth batch, later the same day, took it the rest of the way: the whole driver is now built from source, and every one of its 177 routines and tables is verified.

Continue reading →

14 October 2026: how much of the ROM is code? And bank $C1 is done

Every progress figure on this site divides the code matched so far by the amount of code in the game. Until today that second number, 358,356 bytes, came from a one-off survey done at the start. Now that whole banks are matched, it could be checked, and it was wrong by a third.

Continue reading →

9 October 2026: event commands, battle effects, the dial and the menu threads

Two more batches went through review overnight: the second half of the field's event-script commands in $C0, and the part of the battle engine that resolves an action's targets and runs its effects in $C1. Together 10,245 bytes in 143 routines, all independently verified.

Continue reading →

8 October 2026: who can you hit? The target modes

The code that answers "who does this action hit?" for the battle menu is matched: a 33-entry table of target modes and the eighteen small routines behind it, plus the routine that puts a character into the ready queue. 1,033 bytes in 26 functions (session 43).

Continue reading →

24 September 2026: the cursor that draws itself

One big routine: BattleMenu_UpdateCursorOverlay, 828 bytes, the last stub in the command-menu neighborhood. Every frame, after input is processed, it decides what the pointing hand (or hands) on screen should look like, and where.

Continue reading →

22 September 2026: the tech and item lists, and the command menu is closed

The input handling for the tech list and the item list is matched, the last two submenus still holding stubs. Every input handler in the battle command menu is now matched code. 637 bytes in 15 routines, the last two increments of session 41.

Continue reading →

19 September 2026: the battle command menu, from dirty flag to committed action

The biggest single day so far: 1,478 bytes in 22 routines, all in bank $C1's battle command menu. It now runs as matched code from the gate that decides whether to redraw the menu, through controller input and confirm, to the 8-byte action record the battle engine executes. This is the first stretch of session 41, worked in eight increments.

Continue reading →

14 August 2026: opening bank C1, from the math helpers to the battle windows

Bank $C1, the battle engine, is open. In one day it went from an empty file to 4,085 matched bytes: math and number formatting, the battle status bar and all its callees, the item and tech list renderers, and the per-frame window upkeep. 33 functions over sessions 34 to 40, plus a root-cause fix in the disassembler.

Continue reading →

12 August 2026: the sprite-init system closes, and a first look at bank C1

The triple-slot routines, the dispatcher layer above the sprite-slot cluster and the animation queue that drives it are all matched, so the sprite system from $C98A to $E129 is one continuous run of matched code. Then a scouting pass over bank $C1, the battle engine. 3,509 new bytes in 10 functions (sessions 31 to 33).

Continue reading →

11 August 2026: the sprite-slot cluster takes shape, and an honest progress number

Five body routines of the sprite-slot init cluster are matched, then the triple-slot dispatch. In between, the progress number gets a real denominator: matched code against the game's code, not against the whole 4 MB ROM. 2,377 new bytes in 7 functions (sessions 29 and 30).

Continue reading →

10 August 2026: the animation-frame gate

One routine today, Sub_CB3A (162 bytes), the gate at the start of every sprite-slot init routine. Scoping around it corrected yesterday's picture of the call chain and mapped a new cluster at $CB3A–$D800.

Continue reading →

9 August 2026: the Sub_E12A cluster closes, and the slot allocators

All six callees of Sub_E12A are matched in one pass, which completes the sprite init arc. Then the three sprite-slot allocators that sit just before it: 1,169 new bytes in 9 functions (sessions 26 and 27).

Continue reading →

7 August 2026: the last mode handler, screen transitions, and the sprite init pass

The $0C76 mode dispatch is closed with the default handler. Then the whole screen-transition path, from fade-out through scene save and restore to fade-in, is matched, two early labels are corrected, and the 1,034-byte sprite init pass Sub_E12A goes in: 2,568 new bytes in 15 functions over sessions 21 to 25.

Continue reading →

6 August 2026: the engine spine, the whole sprite system, and the mode handlers

The longest day so far, seventeen sessions (4 to 20) in bank $C0. The game loop and its per-frame reset are matched, then the complete sprite system, from the VBlank handler down to every renderer and init helper, then the head of the per-frame state machine and all five of its named mode handlers: 9,542 new bytes in 32 functions.

Continue reading →

31 July 2026: MainInit, the hardware setup

MainInit at $FD:C000 is matched: the 215 bytes the SNES runs right after the reset stub to put the hardware into a known state. The project now stands at 471 matched bytes.

Continue reading →

25 July 2026: a disassembler and the first bank sweeps

No new matches today. Instead the project got the tools it needs to scale: a recursive-descent disassembler, sweeps of banks $00, $01 and $02, CI, a pre-commit hook, progress tracking and a hardware register include file.

Continue reading →

20 July 2026: setting up, and the last page of bank $00

The project starts. I set up the build, found the reset vector, and matched the whole last page of bank $00: 256 bytes of boot stubs, tables, ROM header and vectors.

Continue reading →