Sega Saturn decomp guide
Two SH-2 chips and young toolkits make Saturn ports possible now, but no full decomp exists yet.
What this system is like
The Saturn has two main chips and two video chips. That made it hard to program in 1994. It also makes it hard to rebuild today. Still, Saturn work moved fast in late 2026.
Path A, a game running on PC, is real now. Three shared toolkits turn the game's SH-2 code into C++. They each add a stand-in for the console, called a runtime. Seven games reach menus and early play this way. None claims a full playthrough yet. All of these toolkits are only weeks old.
Path B, a full decomp, is not done for any Saturn game yet. The furthest one reviewed here is the Saturn build of Symphony of the Night, at about 36% on decomp.dev. Daytona USA CCE rebuilds one race module from split assembly, byte for byte. Turning that into C that the old compiler rebuilds exactly is slow. The exact compiler is often lost.
Plan on WSL for Path B and for some Path A tools. Plan on Windows for playing, emulators and most Path A builds.
Two main chips share the work
The master SH-2 runs the game. The slave SH-2 often helps with 3D math. Both touch the same memory. A runtime must run both in a fixed order, or bugs come and go.
Two video chips, not one
VDP1 draws polygons as bent squares into a frame buffer. VDP2 draws the background layers and mixes them. Each chip has its own rules for color and order. Most visual bugs live where the two meet.
The CD drive sets the pace
Games stream data and movies from a slow 2x drive. Many wait loops expect the drive to take time. If your runtime answers too fast, games stall, drop sound or overwrite colors. Real seek times fixed this in several ports.
Two compiler families
Some games used Hitachi's SHC compiler. Others used Cygnus GCC. Their code looks different, and recompilers need patterns for both. For a matching decomp, the exact SHC version is often lost.
No standard splitter
On N64 and PS1, a tool named splat cuts the game file into pieces. It does not support Saturn. Saturn projects wrote their own splitters and boundary lists.
Two paths
Get it running on PC
You turn each SH-2 program on the disc into C++ with a shared toolkit. The toolkit's runtime stands in for the two SH-2s, both VDPs, the CD drive and sound. An SH-2 interpreter checks the C++ function by function. An emulator such as Beetle Saturn is the reference for pictures and sound. You then fix one runtime gap at a time.
Full decomp for porting
No Saturn game has a full decomp yet. The route that works so far has three tiers. First rebuild every program as assembly that matches byte for byte. Then turn code into C that the period compiler rebuilds exactly, one translation unit at a time. Code that will not match can be checked against an SH-2 oracle instead. Last, you swap the console parts for PC parts.
Path A: Get it running on PC
You turn each SH-2 program on the disc into C++ with a shared toolkit. The toolkit's runtime stands in for the two SH-2s, both VDPs, the CD drive and sound. An SH-2 interpreter checks the C++ function by function. An emulator such as Beetle Saturn is the reference for pictures and sound. You then fix one runtime gap at a time.
Method: static recompilation
Pick this first for any Saturn game. It gives a playable PC build in weeks, not years. It does not give readable source code.
Scope the game and pick a toolkit
Pin your exact disc by its product code and hash. Check if the game or its engine already has a port. Then pick one of the three toolkits. Write
SCOPE.mdso every session works toward the same goal.- Dump your own disc to
.cueand.bin. Keep it outside the repo, for exampleD:/saturn-discs/. - Run
certutil -hashfile "<DATA_TRACK>.bin" SHA256in PowerShell and write the hash inSCOPE.md. Hash each data track: the ones markedMODE1orMODE2in the.cue. - Read the product code with
python -m saturnkit.disc <DISC>.cue --infoafter step 2, or from the disc case. - Search GitHub for the game name plus
recompanddecomp. Fighters Megamix reused engine routines from Fighting Vipers. - Pick
saturnkitfor a Windows-first flow,saturn-recompfor itsgame.tomland learn loop, orsatrecompfor record-then-translate with a fallback. - If you pick
satrecomp, read itsdocs/NEXT_GAME.mdfirst. It lists what is still shaped by the one game it was built for. - Write
SCOPE.md: the goal, the disc hash, the toolkit and its pinned commit, the first milestone and its check.
Prompt for ClaudeGOAL: Draft SCOPE.md for a PC port of <GAME> (Saturn, product code <PRODUCT_CODE>) by static recompilation. READ FIRST: https://github.com/vs-sr-dev/saturnkit , https://github.com/callumjenkins/saturn-recomp , https://github.com/tmcleroy/satrecomp (READMEs only). FENCE: Edit only `SCOPE.md` and `notes/prior-work.md`. Do not install tools. Do not touch any disc file. CHECK: Done means SCOPE.md names the disc hash <DISC_SHA256>, one toolkit with a pinned commit, the first milestone (title screen in a headless run) and its check command, and a list of what is out of scope. notes/prior-work.md lists every repo you found for this game or engine with its URL. BUDGET: Stop after 45 minutes of searching. IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the SCOPE.md text. 3) Files changed. 4) Open questions for me. 5) New parking-lot items.
Done whengrep -c <DISC_SHA256> SCOPE.mdprints 1 or more,SCOPE.mdnames one toolkit commit and the first milestone, and you approved it.Proof this works: Shining Force III Recomp (exact data-track SHA-256 profiles), Baroque (SaturnRecomp) (setup rejects any disc that is not T-33901G), Fighters Megamix Recomp (shared engine with Fighting Vipers)
- Dump your own disc to
Set up the repo and the one check
Make a game repo with the toolkit as a pinned submodule. Install the compiler kit. Write one check script that builds and runs a short headless test. Write
CLAUDE.mdandPROGRESS.mdnow, not later.- Install MSYS2. In the MINGW64 shell run
pacman -S make mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-sdl3 mingw-w64-x86_64-python. Forsatrecomp, addmingw-w64-x86_64-gccandmingw-w64-x86_64-zlib. - For saturnkit:
git submodule add https://github.com/vs-sr-dev/saturnkit.git saturnkit. It needs no Python packages. - For saturn-recomp, in WSL:
git submodule add https://github.com/callumjenkins/saturn-recomp.git saturn-recomp, thenpip install -e saturn-recompinside a Python venv. The install must be editable. - For satrecomp: clone it, run
make checkwith no game, then copy itsexample/folder as your game repo. - Add
iso/,build/andwork/to.gitignore. No game bytes ever go in git. - Write
tools/check.sh. It builds, runsbuild/recomp-build/saturn --cue <DISC>.cue --headless --vblanks 600 --shot 600, and copies the picture tobuild/shots/600.png.
Prompt for ClaudeGOAL: Set up the <GAME> port repo on <TOOLKIT> with one check command. READ FIRST: SCOPE.md, the <TOOLKIT> README, `<TOOLKIT>/docs` if it exists. FENCE: Edit only `.gitignore`, `.gitmodules`, `tools/`, `CLAUDE.md`, `PROGRESS.md`, `notes/`. Never edit files inside the toolkit submodule. Do not add features. CHECK: Run `bash tools/check.sh <ABSOLUTE_PATH_TO_CUE>`. Done means it builds with no errors, writes one PNG to `build/shots/`, and `git status` shows no disc-derived file. BUDGET: Stop after 3 failed builds on the same error, or 90 minutes. IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: paste the last 20 lines of the check output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenbash tools/check.sh <ABSOLUTE_PATH_TO_CUE>exits 0 and writesbuild/shots/600.png, andgit status --porcelainlists nothing underiso/,build/orwork/.Proof this works: pc-virtualhydlide (saturnkit submodule, clang 22 in MSYS2 mingw64), PAL-Saturn-Recomp (pinned upstream commit 086c372), satrecomp README (
make checkneeds no game, read 2026-11-13)- Install MSYS2. In the MINGW64 shell run
Survey the disc
Learn what is on the disc before you translate anything. Find each program, where it loads, and which ones swap at the same address. Write it down. Wrong load addresses break every later step.
- Run
python -m saturnkit.disc <DISC>.cue --infoto readIP.BINand the first file to load. - Run
python -m saturnkit.disc <DISC>.cue --extract build/extractand--audio build/audiofor CD music. - For each program run
python -m saturnkit.sh2 <FILE>.BIN --find-baseto guess its load address. - Check each guess against the program's start code.
--find-basecan pick a wrong base for a small program that calls into a big one. - Write
notes/disc.md: every program file, its load address, its size, and its proof. - Mark overlay programs that load at one shared address. saturnkit tells them apart in memory by crc32.
Prompt for ClaudeGOAL: Write notes/disc.md: every SH-2 program on the <GAME> disc with its load address and proof. READ FIRST: SCOPE.md, the toolkit README section on `disc` and `sh2`. FENCE: Edit only `notes/disc.md` and `game.toml` (program list only). Read the disc only through the toolkit. Do not copy disc bytes into the repo. CHECK: Run `python -m saturnkit.sh2 <FILE> --base <ADDR> --at <ADDR> --count 32` for each program. Done means each listing starts with a sane function prologue, and each address in notes/disc.md names its proof (crt0, IP.BIN, --find-base or a loader call). BUDGET: Stop after 2 hours, or after 3 programs whose base you cannot prove. IF BLOCKED: Stop. Do not guess load addresses. List the programs you could not place. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the table of programs and bases. 3) Files changed. 4) Unproven programs. 5) New parking-lot items.
Done whennotes/disc.mdlists every program with a load address and a named proof.Proof this works: pc-dragonballlegend (IP.BIN, loader and seven programs surveyed first), pc-deepfear (
--find-base 06004000then discovery), pc-virtualhydlide (15 programs told apart by crc32)- Run
Map functions and library code
Run the toolkit's function finder on every program. Check its list against Ghidra. Mark SGL and SBL library code so nobody studies it by hand. Save the map as a ledger with a status column.
- Run
python -m saturnkit.recomp.discover <FILE>.BIN --base <ADDR> --reportfor each program. - Install Ghidra 12.0 with JDK 21. Add the
Ghidra-SegaSaturn-Loader12.0.0 release zip through File, Install Extensions. - Unzip a Mednafen save state with
gunzip, then load it in Ghidra with the loader. You see code as it sits in memory. - Copy
ApplySig.pyinto aghidra_scriptsfolder. Run it from the Script Manager with CyberWarriorX's Saturn library signatures to name SGL and SBL functions. - Export Ghidra's function list with a small script, as pc-deepfear does with its
ExportFuncs.java. Compare counts. Deep Fear matched 1,250 of 1,252. - Write
notes/functions.csvwith address, size, program, name, proof and status.
Prompt for ClaudeGOAL: Build notes/functions.csv for <PROGRAM> and explain every gap between the toolkit's discovery and Ghidra. READ FIRST: notes/disc.md, the discovery report at `build/<PROGRAM>.report.txt`, the Ghidra export at `build/ghidra/<PROGRAM>.funcs.txt`. FENCE: Edit only `notes/functions.csv`, `notes/discovery-gaps.md` and the seeds list in `game.toml`. Do not edit the toolkit. Do not edit generated C++. CHECK: Run `python -m saturnkit.recomp.discover <ABSOLUTE_PATH_TO_FILE> --base <ADDR> --report`. Done means every function Ghidra finds is either in the report or listed in notes/discovery-gaps.md with a reason (shared tail, data, library). BUDGET: Stop after 2 hours or 20 unexplained gaps. IF BLOCKED: Stop. Do not add seeds you cannot prove. List them. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both function counts and the gap count. 3) Files changed. 4) Open gaps. 5) New parking-lot items.
Done whennotes/functions.csvexists, and every Ghidra function is either found or explained.Proof this works: pc-deepfear (1,250 of 1,252 Ghidra functions matched), pc-virtualhydlide (571 of 576; the other 5 are shared tails), Daytona USA CCE (Ghidra with Saturn loader and SBL/SGL signatures)
- Run
First light: translate, self-test, boot
Turn every program into C++ and build it. Run the self-test against the SH-2 interpreter. Then boot the game with no window and take a picture. This is your first proof the chain works end to end.
- saturnkit:
python -m saturnkit.recomp --out build/recomp A=<FILE>.BIN@<ADDR>, then thecmakeandninjalines from its README. - saturn-recomp:
python -m saturnrecomp.build game.toml --recompile. - satrecomp:
make, thenmake record ARGS="--headless --frames 3000", thenmakeagain. - Self-test vectors:
python -m saturnkit.recomp.selftest --out build/vectors.txt --image A=<FILE>.BIN@<ADDR> --test A --auto. Add--optestto the recomp line for the instruction test. - Run them:
build/recomp-build/selftest build/recomp/selftest/optest.txt build/vectors.txt. Expect zero differences. - Boot headless:
build/recomp-build/saturn --cue <DISC>.cue --headless --vblanks 600 --shot 300,600.
Prompt for ClaudeGOAL: Recompile all programs of <GAME>, pass the self-test, and boot to the first screen headless. READ FIRST: SCOPE.md, notes/disc.md, notes/functions.csv, the toolkit README sections on recomp and selftest. FENCE: Edit only `game.toml`, `tools/` and `notes/`. Never edit generated C++ under `build/`. Never edit the toolkit. CHECK: Run `bash tools/check.sh <ABSOLUTE_PATH_TO_CUE>`. Done means the self-test prints 0 differences and `build/shots/600.png` shows a logo or title, not a black frame. BUDGET: Stop after 3 failed tries on one error, or 2 hours. IF BLOCKED: Stop. If the run stops on a call to a non-entry, report the address. Do not stub it. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: self-test summary line and the PNG path. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe self-test shows 0 differences and a headless run saves a picture of the first logo or title.Proof this works: pc-virtualhydlide (51,532 vectors, 0 differences), pc-dragonballlegend (30,261 of 30,261 vectors; boot to first battle), Fighters Megamix Recomp (record, translate,
make check)- saturnkit:
Build the reference runs
A reference run is the same input played in an emulator. You need it to say what right looks like. Record pad input as a text file. Replay it in your build and in Beetle Saturn. The emulator's frames drift from your VBlanks, so line pictures up by the game's own frame counter.
- Play in your build with
build/recomp-build/saturn --cue <DISC>.cue --record-input movies/intro.txt. - Replay headless:
build/recomp-build/saturn --cue <DISC>.cue --headless --input @movies/intro.txt --vblanks 9000 --shot 7760. - Make reference pictures:
python -m saturnrecomp.reference <CORE> --bios <BIOS_DIR> --cue <DISC>.cue --frames 3600 --input <PRESSES> --shot <FRAMES> --out refs/. - Build the Beetle Saturn core with
-D_LOW_ACCURACY_taken out of its Makefile. US and European discs need your ownmpr-17933.bin. Japanese discs needsega_101.bin. - Line up shots with
saturnrecomp.reference.play_synced. The real BIOS boots first and CD reads take time, so frame numbers alone do not match. - pc-deepfear does the same with its own
tools/oracle.py, which drives RetroArch with timed presses like--at 36:START,39:START,60:START,66:shot. - Store pictures in
refs/outside git, and their hashes inrefs/hashes.txtinside git. Movies may replay only on the machine that recorded them, so test each one twice there.
Prompt for ClaudeGOAL: Make three golden runs for <GAME>: boot to title, title to first control, first <N> minutes of play. READ FIRST: SCOPE.md, the toolkit README sections on --input, --record-input and the reference emulator. FENCE: Edit only `movies/`, `refs/hashes.txt`, `tools/golden.sh` and `notes/`. Do not change the runtime. Do not change game code. CHECK: Run `bash tools/golden.sh <ABSOLUTE_PATH_TO_CUE>`. Done means each run replays twice with the same picture hashes, and each run has emulator reference pictures taken at the same value of the game's own frame counter. BUDGET: Stop after 90 minutes or 3 runs that will not repeat. IF BLOCKED: Stop. Do not loosen the compare. Tell me which VBlank first differs. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the hash lines from both replays. 3) Files changed. 4) Runs still missing. 5) New parking-lot items.
Done whenThree recorded runs replay with the same hashes twice, and each has reference pictures.Proof this works: pc-dragonballlegend (scripted presses, CD-DA correlation 1.00 against Beetle Saturn), Fighting Vipers Recomp (input movies replay with the same per-frame hashes), saturn-recomp README (
saturnrecomp.referenceandplay_synced, read 2026-11-13)- Play in your build with
Grind: one runtime gap at a time
Now play forward until something breaks. Each break is one unit of work. Find the first wrong frame, then the first wrong memory write. Most Saturn breaks were runtime gaps, not game bugs.
- Find the first VBlank where your picture differs from the reference.
- Watch writes:
build/recomp-build/saturn --cue <DISC>.cue --headless --watch <START>:<END> --watch-vblanks <A>:<B>. - Check the known gaps first: DMA burst size, CD read speed and seeks, the division unit, VDP1 frame change timing. On
saturn-recomp, try--accurate-drivefor real drive timing. - Fix it in the runtime or as a numbered patch on the pinned toolkit, never in generated code.
- Add the run that showed the bug to
movies/. Write the cause innotes/findings.md.
Prompt for ClaudeGOAL: Find and fix the cause of <SYMPTOM> at VBlank <N> in movie <MOVIE>. READ FIRST: notes/findings.md (dead ends), PROGRESS.md, the two pictures `build/shots/<N>.png` and `refs/<N>.png`. FENCE: Edit only `<RUNTIME_PATH>`, `patches/` and `notes/`. Never edit generated C++. Never add per-game hacks to the runtime. No stubs and no faked events. CHECK: Run `bash tools/golden.sh <ABSOLUTE_PATH_TO_CUE>`. Done means the movie passes the frame where it failed, every other golden run still passes, and notes/findings.md names the proven cause. BUDGET: Stop after 3 failed fix ideas, or 2 hours with no new evidence. IF BLOCKED: Stop. Do not work around it. Report the first wrong write you found and what you need. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: golden.sh output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe failing movie passes the old failure point, and every older golden run still passes.Proof this works: pc-deepfear (DMAC 16-byte transfers, division unit shadow register, drive speed), PAL-Saturn-Recomp (black screen was a DMA burst bug, not VDP2), Baroque (SaturnRecomp) (CD block GetSectorInfo and DMA interrupt blockers)
Harden and package
Make sure old fixes stay fixed. Drive the interpreter fallback count down. Add saves, settings and a launcher. Check that no game data can leak into git or a release.
- Run all golden runs on a clean checkout:
git clone, thenbash tools/golden.sh <DISC>.cue. - Report coverage. satrecomp counts every fallback. saturn-recomp has
--coverage cov.txt. - Add an audit step like Fighters Megamix's
make auditthat fails on game data or personal paths. - Write saves outside the app folder, as Baroque does with
game/backup.bin. - On Windows, link statically, or a stray
libstdc++-6.dllcan stop the exe.
Prompt for ClaudeGOAL: Make the <GAME> port pass every golden run from a clean checkout and add an audit that blocks game data. READ FIRST: PROGRESS.md, `movies/`, `refs/hashes.txt`, notes/findings.md. FENCE: Edit only `tools/`, `.github/`, `docs/` and `PROGRESS.md`. Do not change the runtime or game.toml. Do not change any reference hash. CHECK: In a fresh clone at `<ABSOLUTE_TEMP_DIR>`, run `bash tools/golden.sh <ABSOLUTE_PATH_TO_CUE>` and `bash tools/audit.sh`. Done means both pass and the coverage report shows the fallback count. BUDGET: Stop after 2 hours. IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs and the fallback count. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenA clean clone passes every golden run and the audit, and the fallback count is written inPROGRESS.md.Proof this works: Fighters Megamix Recomp (
make audit, CI smoke start), Shining Force III Recomp (62 synthetic test files,check-source-package.py), PAL-Saturn-Recomp (static link fixes 0xC0000139)- Run all golden runs on a clean checkout:
Path B: Full decomp for porting
No Saturn game has a full decomp yet. The route that works so far has three tiers. First rebuild every program as assembly that matches byte for byte. Then turn code into C that the period compiler rebuilds exactly, one translation unit at a time. Code that will not match can be checked against an SH-2 oracle instead. Last, you swap the console parts for PC parts.
Method: matching decompilation
Pick this only after Path A, or for a game you love and will work on for years. Expect to be a pioneer. Budget months just to find the right compiler.
Scope: find the compiler family
You must know which compiler built the game. SHC and GCC leave different marks. Check what others found for the same engine. Write down how sure you are in
SCOPE.md.- Look for marks in the code. SHC games built with its
-picoption usebsrfandbrafcalls. GCC games show GCC switch tables. - Name library code first with
ApplySig.pyand CyberWarriorX's SGL and SBL signatures. - Read atolm's
docs/FINDING_THE_COMPILER.mdto see how one team fingerprinted SHC. - Check sotn-decomp and
saturn-splitterfor a GCC game built with the Cygnus DOS compiler. - Write
SCOPE.md: game hash, compiler family, the candidate compiler and flags, and the first target program.
Prompt for ClaudeGOAL: Decide which compiler family built <PROGRAM> of <GAME> and write it into SCOPE.md with evidence. READ FIRST: https://github.com/blythos/atolm (README and docs/FINDING_THE_COMPILER.md), https://github.com/sozud/saturn-splitter , notes/functions.csv. FENCE: Edit only `SCOPE.md` and `notes/compiler.md`. Do not install compilers. Do not touch disc files. CHECK: Done means notes/compiler.md lists at least five code addresses with the idiom each shows (SHC or GCC), and SCOPE.md names one family, one candidate compiler and its flags, and how sure you are. BUDGET: Stop after 2 hours. IF BLOCKED: Stop. If the signs disagree, say so. Do not pick one to look tidy. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the address table. 3) Files changed. 4) Open questions. 5) New parking-lot items.
Done whennotes/compiler.mdhas a table of five or more code addresses, each with its idiom, andgrep -E 'SHC|GCC' SCOPE.mdfinds the chosen family.Proof this works: atolm (Hitachi SHC 5.0 Release31 chosen by fingerprinting), pc-dragonballlegend (SHC
-piccode:bsrf,braf,mova), pc-deepfear (GCC switch tables and SGL handlers)- Look for marks in the code. SHC games built with its
Set up WSL, Docker and the byte check
Build a repo where one command rebuilds a program and compares its hash. The old compilers run in Docker inside WSL. Keep disc files and extracted programs in ignored folders. The byte check is your judge from now on.
- In WSL run
sudo apt install binutils-sh-elf make python3-yamland install Docker. - Fetch the period compiler only through a project script, such as atolm's
make setupor saturn-splitter'sscripts/get_gccsh.sh. - Write
make extractto pull programs from your disc intoextracted/. It must refuse a wrong dump. - Write
make checkto compare each rebuilt program withsha256sumagainst the extracted one. - Put expected hashes in
config/and block edits to them with a Claude Code hook.
Prompt for ClaudeGOAL: Set up the <GAME> decomp repo so `make check` rebuilds <PROGRAM> and compares its sha256. READ FIRST: SCOPE.md, notes/compiler.md, https://github.com/blythos/atolm (Makefile targets in the README). FENCE: Edit only `Makefile`, `toolchain/`, `tools/`, `config/`, `.gitignore`, `CLAUDE.md`, `.claude/settings.json`. Disc files stay in `ISOs/` and `extracted/`, both ignored. CHECK: In WSL run `make extract && make check`. Done means make check prints the hash of the extracted <PROGRAM>, and a deliberately broken rebuild makes it fail. BUDGET: Stop after 3 failed toolchain builds, or 3 hours. IF BLOCKED: Stop. Do not swap in a different compiler to get a green check. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the passing and the deliberately failing output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenmake checkpasses on the original and fails on a deliberately broken build.Proof this works: atolm (
make setup,make extract,make,make check), Daytona USA CCE (./setup.sh,make validate8 of 8 identical), Castlevania: Symphony of the Night Decompilation (make VERSION=saturn)- In WSL run
Split and rebuild as assembly
Cut each program into one file per function with a boundary list. Rebuild it from that assembly. It must match byte for byte. This gives you a full map and a safe base for C work.
- Keep a boundary database like Daytona's
config/race.bin.yamlwith 757 pieces and 100% coverage. - Write a splitter like Daytona's
tools/splitter.py.saturn-splitteris an example in Rust. - Turn raw
.bytelines into real SH-2 instructions so branches can move later. - Run
makethenmake checkafter each batch of boundaries. - Classify doubtful function starts five at a time in an append-only CSV.
Prompt for ClaudeGOAL: Rebuild <PROGRAM> from per-function assembly so it matches byte for byte. READ FIRST: SCOPE.md, notes/functions.csv, `config/<PROGRAM>.yaml`. FENCE: Edit only `config/<PROGRAM>.yaml`, `tools/splitter.py` and `notes/`. Never hand-edit the split output in `asm/`. Regenerate it. CHECK: In WSL run `make && make check`. Done means <PROGRAM> is byte-identical and the yaml covers 100% of its bytes. BUDGET: Stop after 3 hours or 5 failed rebuilds on one boundary. IF BLOCKED: Stop. List the addresses where the boundary is unclear. Do not guess. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: make check output and the coverage number. 3) Files changed. 4) Unclear boundaries. 5) New parking-lot items.
Done whenmake checkshows the program byte-identical, and the boundary file covers 100% of its bytes.Proof this works: Daytona USA CCE (757 subsegments at 100% coverage), Daytona USA CCE (eval-midentry skill, 5 addresses per run), saturn-splitter README (read 2026-11-13)
- Keep a boundary database like Daytona's
Prove the code can move
A byte match can hide hard-coded addresses. Build a copy with all code moved a few bytes. If it still boots, every pointer is real. Only then can you change code size safely.
- Add a build target that inserts 4 bytes at the start, like Daytona's
make 4shift. - Write the shifted program into a bootable disc image, as Daytona's
make discandtools/inject_disc.pydo. - Boot it headless in
mednafen-saturn-debugwith./mednafen --sound 0 --automation <IPC_DIR> <CUE>, and screenshot attract mode at 40 seconds. - Compare the shot with a golden picture, as Daytona's
tools/screenshot_test.pydoes. - Each failure is a missed pointer. Turn it into a label and rebuild.
Prompt for ClaudeGOAL: Make the +4 byte shifted build of <PROGRAM> boot to the same attract-mode picture as the original. READ FIRST: CLAUDE.md, `config/<PROGRAM>.yaml`, notes/shift-misses.md. FENCE: Edit only `asm/` label lines through the generator, `config/`, `tools/` and `notes/shift-misses.md`. Do not change the golden picture. CHECK: Run `make check && make 4shift && python3 tools/screenshot_test.py build/4shift.cue`. Done means make check passes and the screenshot matches the golden one. BUDGET: Stop after 10 missed pointers fixed, then report. IF BLOCKED: Stop. Report the address where the shifted build first goes wrong. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs. 3) Files changed. 4) Pointers still missing. 5) New parking-lot items.
Done whenThe shifted build boots and its screenshot matches the golden picture, whilemake checkstill passes.Proof this works: Daytona USA CCE (
make 4shift, screenshot test, 26 missed refs fixed in result2p), mednafen-saturn-debug README (--automationfile interface and screenshots, read 2026-11-13)- Add a build target that inserts 4 bytes at the start, like Daytona's
Mark libraries and group functions
Library code from SGL and SBL needs no new C. Name it and set it aside. Then group the rest into translation units. A translation unit is one original source file. On Saturn you usually match a whole unit, not one function.
- Apply SGL and SBL signatures in Ghidra and set those rows to
libraryinnotes/functions.csv. - Group functions that sit next to each other and either call each other with
bsror share a literal pool. Those must sit in one unit. - Write each group to
config/units.csvwith the signal that joined them. - Do not join two functions just because one calls the other through
jsr.
Prompt for ClaudeGOAL: Mark library code and group the rest of <PROGRAM> into translation units. READ FIRST: notes/functions.csv, `config/<PROGRAM>.yaml`, the Ghidra export `build/ghidra/<PROGRAM>.sigs.txt`. FENCE: Edit only `notes/functions.csv` and `config/units.csv`. Do not write C. Do not edit assembly. CHECK: Done means every function has a status, every unit names its joining signal (bsr link or shared pool), and `make check` still passes. BUDGET: Stop after 2 hours. IF BLOCKED: Stop. List the groups you are not sure of. Do not merge on a guess. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: counts per status and per unit. 3) Files changed. 4) Unsure groups. 5) New parking-lot items.
Done whenEvery function has a status and every unit names the signal that joined it.Proof this works: atolm (about 77.5% of sampled functions need their whole unit), Daytona USA CCE (tu-detection skill rules), atolm (15 exact SBL and CPK library placements)
- Apply SGL and SBL signatures in Ghidra and set those rows to
First match: one small unit
Match one small unit end to end with the period compiler. This proves the compiler, the flags and the build. Start with a leaf function that calls nothing. Write down every flag you used.
- Get a draft with
m2c --target sh2-gcc-c <FILE>.sfor GCC games. For SHC games, use it only as a hint. - Compile in the toolchain container with the flags in
SCOPE.md, for example atolm's-optimize=1 -speed. - Compare with
asm-differset up for SH2, orsh-elf-objdump -don both files. - Record the address, size, exact compile line and hash in
notes/matches.md.
Prompt for ClaudeGOAL: Match unit <UNIT> (functions <ADDRS>) of <PROGRAM> byte for byte with the period compiler. READ FIRST: SCOPE.md (compiler and flags), `asm/<UNIT>/`, notes/matches.md (one finished example), notes/findings.md (dead ends). FENCE: Edit only `src/<UNIT>.c` and `notes/`. No inline assembly, no embedded bytes, no new compiler flags without my approval. CHECK: In WSL run `make check`. Done means the unit is built from C and <PROGRAM> stays byte-identical. BUDGET: Stop after 8 attempts or 90 minutes. IF BLOCKED: Stop. Paste the smallest remaining diff and name its likely cause (register choice, scheduling, constant). OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: make check output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenmake checkpasses with that unit built from C.Proof this works: atolm (three leaf functions matched with SHC 5.0), m2c README (
sh2target, read 2026-11-13), asm-differ README (SH2 support, read 2026-11-13)- Get a draft with
Grind: unit loop with many workers
Now repeat the unit loop. A lead session hands out units, easy and small first. Each worker has its own worktree. Every merge must pass the full byte check.
- Sort
config/units.csvby size. Leaf units go first. - Give each worker one unit card, one finished example and the dead-end list.
- Run
make checkin the worker's worktree, and again on the main branch after merge. - Log near misses as
attemptedwith the remaining diff. Never count them as matched.
Prompt for ClaudeGOAL: Hand out the next <N> unattempted units of <PROGRAM> to workers and merge only proven matches. READ FIRST: config/units.csv, notes/matches.md, notes/findings.md, PROGRESS.md. FENCE: Edit only `PROGRESS.md` and merge commits. Workers edit only their own `src/<UNIT>.c`. Nobody edits hashes, asm or the Makefile. CHECK: After each merge run `make check` on the main branch. Done means every merged unit passes there, and PROGRESS.md shows matched, attempted and unattempted counts. BUDGET: Stop after <N> units or 4 hours. IF BLOCKED: Stop. Report which merge broke the check and revert it. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: make check output on main. 3) Files changed. 4) Units left. 5) New parking-lot items.
Done whenEvery merged unit passesmake checkon the main branch, andPROGRESS.mdshows the full status split.Proof this works: atolm (status table with eight states, CI-checked), Castlevania: Symphony of the Night Decompilation (asm-differ per version,
make diff_saturn)- Sort
Check code that will not match
Some units may never match, because the exact compiler is lost. For those, prove the C does the same thing. Run the original code in an SH-2 interpreter and diff it against your C. Keep these in a separate column.
- Build an oracle: run the original SH-2 code in an interpreter such as
python -m saturnkit.sh2emuor Sega Rally'stools/sh2.py. saturnkit's runs one function:--call <ADDR> --regs r4=<VALUE>. - Record inputs and outputs for each unit from real play.
- Run the C on the same inputs and compare memory after each call or each frame.
- Mark the unit
equivalence-verified. Never add it to the matched count.
Prompt for ClaudeGOAL: Prove unit <UNIT> behaves the same as the original, with an oracle diff. READ FIRST: notes/findings.md entry for <UNIT>, `src/<UNIT>.c`, the oracle docs in `docs/oracle.md`. FENCE: Edit only `tests/oracle/<UNIT>/`, `src/<UNIT>.c` and `notes/`. Do not change the oracle or the recorded traces. CHECK: Run `python3 tools/oracle_diff.py <UNIT> --traces <ABSOLUTE_TRACE_DIR>`. Done means 0 differing calls across all recorded traces. BUDGET: Stop after 3 fix ideas or 2 hours. IF BLOCKED: Stop. Paste the first differing call with both memory dumps. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: oracle_diff summary. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe oracle diff shows 0 differing calls on every recorded trace, and the unit sits in its own column.Proof this works: Sega Rally PSP (141 drive traces with 0 differing passes), atolm (equivalence-verified state, never summed into matched)
- Build an oracle: run the original SH-2 code in an interpreter such as
Port: swap the console parts
Put SH-2 hardware access behind small functions. Replace VDP1, VDP2, sound and CD with PC code. Fix big-endian data reads. Then run the same golden runs on the new system.
- Read game tables through helpers like Sega Rally's
g16andg32, since data is big-endian. - Replace drawing with a modern library, as Azel does with
bgfxand SDL. - Play Saturn sound data with a library like
aosdk, or keep a 68000 and SCSP model. - Run your golden runs on the port and compare against the emulator pictures.
Prompt for ClaudeGOAL: Move <SUBSYSTEM> of <GAME> from Saturn hardware calls to the port layer in `port/`. READ FIRST: PROGRESS.md, `src/<SUBSYSTEM>/`, notes/hardware-calls.md. FENCE: Edit only `port/` and the call sites listed in notes/hardware-calls.md. Do not change matched units except their hardware calls behind a define. CHECK: Run `make check` (Saturn build still byte-identical) and `bash tools/golden.sh --port <ABSOLUTE_PATH_TO_DATA>`. Done means both pass. BUDGET: Stop after 3 hours or 3 failed golden runs. IF BLOCKED: Stop. Report the first frame that differs and the call behind it. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe Saturn build still matches, and the port passes the same golden runs.Proof this works: Sega Rally PSP (g16 and g32 helpers, real PSP tests), Azel (bgfx, SDL, SoLoud and aosdk)
- Read game tables through helpers like Sega Rally's
Tools you need
| Tool | What it does | How to get it | How we know |
|---|---|---|---|
| saturnkit Required Windows | A Saturn toolkit in Python and C++. It reads discs, disassembles SH-2 code, finds functions, writes C++ and runs it on its own runtime. Its sh2emu interpreter can also run one original function alone.Path A Path B | git submodule add https://github.com/vs-sr-dev/saturnkit.git saturnkit | saturnkit README (read 2026-11-13); used by pc-virtualhydlide, pc-deepfear, pc-dragonballlegend |
| saturn-recomp Helpful both | A fork of saturnkit with a game.toml setup, a learn loop for missed code, and a reference runner for Beetle Saturn.Path A | git submodule add https://github.com/callumjenkins/saturn-recomp.git saturn-recomp && pip install -e saturn-recomp (or `uv add --editable ./saturn-recomp` if you use `uv`) | saturn-recomp README (read 2026-11-13): editable install required; disc builds, the agent and research tools are tested only on Linux; used by Shining Force III Recomp, PAL-Saturn-Recomp |
| satrecomp Helpful both | A toolkit that records which code runs, translates it to C++, and falls back to an interpreter for the rest. It counts every fallback. Path A | git clone https://github.com/tmcleroy/satrecomp && cd satrecomp && make check | satrecomp README (read 2026-11-13): make check needs no game; its Ymir reference patch is not published. Used by Fighters Megamix Recomp, Fighting Vipers Recomp |
| MSYS2 (MINGW64 clang, CMake, Ninja, SDL3) Required Windows | A Windows shell with Linux-style tools. It builds the C++ the toolkits write. Path A | Install from https://www.msys2.org/, then in MINGW64: pacman -S make mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-sdl3 mingw-w64-x86_64-python | packages.msys2.org pages for all six packages (read 2026-11-13); used by pc-virtualhydlide, Fighting Vipers Recomp |
| Ghidra Required both | A free disassembler and decompiler with SH-2 support. Use it to check function lists and read code. Path A Path B | Download a release zip from https://github.com/NationalSecurityAgency/ghidra/releases. Use 12.0 with JDK 21 if you want the Saturn loader release zip. The newest, 12.2, asks for JDK 25. | Ghidra README at tags Ghidra_12.0_build (JDK 21) and latest 12.2 (JDK 25), read 2026-11-13; used by Daytona USA CCE, Tomb Raider remix, Sega Rally PSP |
| Ghidra-SegaSaturn-Loader Helpful both | A Ghidra add-on that loads a Saturn disc's first program or an emulator save state at the right addresses. Path A Path B | Download the 12.0.0 release zip, then in Ghidra 12.0 use File, Install Extensions. For another Ghidra version, build it with `gradle -PGHIDRA_INSTALL_DIR=<GHIDRA_DIR>`. Add `ApplySig.py` to `ghidra_scripts` for library signatures. | loader README and release 12.0.0, built for Ghidra 12.0 (read 2026-11-13); used by Daytona USA CCE |
| Beetle Saturn (Mednafen) Required both | An accurate Saturn emulator. It is the reference for pictures and sound. It needs your own BIOS dump. Path A Path B | Mednafen from https://mednafen.github.io/, or the Beetle Saturn core in RetroArch. Put your own BIOS dumps in its system folder: `sega_101.bin` for Japan, `mpr-17933.bin` for the US and Europe. For `saturnrecomp.reference`, build the core without `-D_LOW_ACCURACY_`. | Mednafen ss docs and Beetle Saturn README (BIOS names, read 2026-11-13), saturn-recomp README; used by pc-deepfear, pc-dragonballlegend, Daytona USA CCE |
| Ymir Helpful both | A newer Saturn emulator with a debugger, save states and frame stepping. It needs your own BIOS dump. The satrecomp author compares against it, but that patch is not public. Path A | Download the latest release from https://github.com/ymir-emu/Ymir/releases (AVX2 or SSE2 build). On Windows, install the Visual C++ Redistributable. Put the BIOS in `roms\ipl` next to the program. | Ymir README, release v0.4.1 with Windows, Linux and macOS builds (read 2026-11-13); satrecomp README on the unpublished reference patch; used by Fighters Megamix Recomp, Fighting Vipers Recomp |
| sh-elf binutils Required WSL/Linux | The GNU assembler, linker and objdump for SH-2. Path B uses them to rebuild and compare programs.Path B | sudo apt install binutils-sh-elf | Ubuntu noble package page, 2.40+2 (read 2026-11-13); used by Castlevania: Symphony of the Night Decompilation, atolm |
| Docker (period compiler containers) Required WSL/Linux | Runs the old compilers in a box: Hitachi SHC under Wine, or Cygnus GCC under dosemu. Path B | Install Docker in WSL. Then let the project script build the container, such as atolm's `make setup`. | atolm README and CLAUDE.md (read 2026-11-13); saturn-splitter README; Castlevania: Symphony of the Night Decompilation Dockerfile (card) |
| asm-differ Required WSL/Linux | Shows your build's assembly next to the original, line by line. It supports SH2. Path B | In a Python venv: pip install 'asm-differ @ git+https://github.com/simonlindholm/asm-differ.git'. Then write a `diff_settings.py` for SH2, as sotn-decomp does. | asm-differ README (read 2026-11-13); used by Castlevania: Symphony of the Night Decompilation, atolm |
| m2c Helpful both | Turns assembly into a first draft of C. It has an sh2 target and knows GCC output.Path B | In a Python venv: pip install 'm2c @ git+https://github.com/matt-kempster/m2c.git'. Run it as `m2c --target sh2-gcc-c <FILE>.s`. | m2c README (read 2026-11-13); used by Castlevania: Symphony of the Night Decompilation |
| objdiff Helpful both | A diff tool for decomp projects with a window and a command line. It lists SuperH for Saturn. Path B | Download `objdiff-windows-x86_64.exe` or the CLI from https://github.com/encounter/objdiff/releases | objdiff README, release v3.8.3 (read 2026-11-13); no reviewed Saturn project used it |
| saturn-splitter Helpful WSL/Linux | A work-in-progress splitter for Saturn programs, like splat. It now targets one Symphony of the Night file, T_BAT.PRG. Its scripts run the Cygnus DOS compiler in Docker.Path B | Install Rust from https://rustup.rs first. Then: git clone https://github.com/sozud/saturn-splitter && cd saturn-splitter/rust-dis && cargo build --release | saturn-splitter README (read 2026-11-13); used by Castlevania: Symphony of the Night Decompilation |
| mednafen-saturn-debug Helpful WSL/Linux | A Mednafen fork that scripts can drive through two text files. It sets breakpoints, watches writes, traces calls and saves screenshots, with no window. Path B | In WSL: git clone https://github.com/AJBats/mednafen-saturn-debug && cd mednafen-saturn-debug && ./configure && make -j$(nproc) | mednafen-saturn-debug README (read 2026-11-13); used by Tomb Raider for the Sega Saturn (saturn-tr-remix) as a submodule |
Skills and add-ons
Read any skill before you install it. A skill is a set of instructions that Claude will follow. See Tools and Skills for the full list and safety notes.
verification-before-completion
Claude may not say done without fresh proof. Here that is a self-test with 0 differences, a golden run hash, or a make check pass.
npx skills add obra/superpowers --skill verification-before-completion -a claude-code
systematic-debugging
No fix until the cause is proven. Saturn ports lost time to wrong first guesses, like blaming VDP2 for a DMA bug.
npx skills add obra/superpowers --skill systematic-debugging -a claude-code
static-recomp-av-compare
Scores your port's pictures and sound against recordings you made. That fits the Beetle Saturn reference runs in Path A. It needs ffmpeg, and it was written for Codex, so its script paths need a fix.
npx skills add bgyss/switchrecomp --skill static-recomp-av-compare -a claude-code
matcher
A careful method for matching C, one idea per try. On Saturn, point it at a whole unit and at your make check. It expects the original compiler, and it calls five other lemiur skills, so install those too.
npx skills add lemiur/game-decompilation-skill-for-claude --skill matcher -a claude-code
decomp-matching-workflow
Sets a try limit per unit and gives workers a claim queue. That suits the Path B unit loop.
npx skills add madpai/game-decomp-compendium --skill decomp-matching-workflow -a claude-code
handoff
Writes a short note so a fresh session can carry on. Tell it to save into notes/, not a temp folder.
npx skills add mattpocock/skills --skill handoff -a claude-code
Mednafen debug MCP server (SaturnAutoRE)
Lets Claude set breakpoints, watch writes, trace calls and take screenshots in Mednafen. Daytona wired it in. The Tomb Raider remix wired its own server to the same Mednafen fork. GitHub shows no licence for the repo.
Run `git clone --recursive https://github.com/AJBats/SaturnAutoRE`. Build its `mednafen/` with `wsl bash build_with_gcc494.sh`. That needs a GCC 4.9.4 MinGW cross compiler at `/opt/gcc-4.9.4-mingw64/` in WSL. Then copy `templates/mcp.json` to your repo as `.mcp.json` and point it at `mednafen/mcp_server.py`.
GhidrAssistMCP
Lets Claude list functions, read decompiled code and rename things in Ghidra. Daytona used it for bulk decompiling.
Download the release zip built for your Ghidra version. For Ghidra 12.0 that is release 2.8.0; release 3.0.0 has zips for 12.1 and 12.2 only. In Ghidra use File, Install Extensions. Then run `claude mcp add --transport http ghidra http://127.0.0.1:8080/mcp`.
saturn-golden-run
Daytona's screenshot-test skill did this for one boot test. One skill keeps every session's check the same.
A `.claude/skills/saturn-golden-run/SKILL.md` that runs `tools/golden.sh <CUE>`, names each movie and VBlank that failed, and saves both pictures side by side. It must say: never change `refs/hashes.txt`.
saturn-boundary-batch
Daytona's eval-midentry sorted 487 doubtful starts this way. Small fixed batches keep the judgement steady.
A skill that takes the next 5 doubtful function starts, judges each as KEEP, MERGE or AMBIGUOUS with an address as proof, and appends rows to a CSV. No source edits and no builds.
Claude setup for this system
Cut Saturn work by program, by address and by recorded run. On Path A, one unit is one runtime gap seen in one golden run, or one discovery miss. On Path B, one unit is one translation unit, or a batch of five boundary checks. Every unit has one check: the self-test, a golden run hash, or make check. Pass disc paths as absolute paths.
Which model and effort for each job
The model and effort names come from one shared table, so they stay the same on every guide. See Claude Setup for the reasons.
| Job | What it means on this system | Max 20x (now called Ultra) | Max 5x (now called Max) |
|---|---|---|---|
| Plan the project | Pin the disc hash and product code. Find prior work for the game and engine. Pick a toolkit, or the compiler family for Path B. Write SCOPE.md. | Fable 5.2 effort highOne session. This choice shapes months of work. | Opus 5.5 effort highUse Fable 5.2 for this one session if you have weekly room. |
| Set up the project | Set up MSYS2 or WSL, the toolkit submodule, .gitignore, tools/check.sh and tools/golden.sh. For Path B, the Docker compiler and make check. | Opus 5.5 effort medium | Sonnet 5.5 effort medium |
| Study the game file | Survey the disc, find load bases and overlays, compare discovery with Ghidra, mark SGL and SBL code, and group translation units. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for function edges and data layouts. A mistake there spreads. |
| Bulk units | Discovery seeds with clear proof, batches of five boundary checks, and small leaf units to match. Each runs alone with its own check. | Sonnet 5.5 effort mediumHaiku 5.5 for the plainest units. | Sonnet 5.5 effort mediumFewer workers at once. Haiku 5.5 for the plainest units. |
| Hard units | Units that will not match after eight tries, SHC position-independent code, and computed jumps the recompiler cannot follow. | Fable 5.2 effort highGo to xhigh only after a failed try at high. | Opus 5.5 effort highSend only the last few that still fail to Fable 5.2. |
| Build the runtime | Fixes to the CD drive model, DMA, the SCU, VDP1 and VDP2 mixing, the 68000 and SCSP sound, and the slave SH-2 order. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for timing and graphics bugs. |
| Find a bug | Find the first wrong frame against Beetle Saturn, then the first wrong write with --watch. Prove the cause before any fix. | Opus 5.5 effort highAfter two failed tries with full evidence, move to Fable 5.2. | Opus 5.5 effort highOne bug at a time. |
| Check the work | A fresh session reruns the self-test, every golden run or make check. It hunts for stubs, edited hashes, generated-code edits and fallback hidden as recompiled. | Opus 5.5 effort mediumAlways a new session, never the one that did the work. | Sonnet 5.5 effort highAlways a new session, never the one that did the work. |
| Keep the records | Update PROGRESS.md, notes/functions.csv counts, notes/findings.md and the parking lot after each batch. | Haiku 5.5 effort medium | Haiku 5.5 effort medium |
How many sessions at once
Max 20x (now called Ultra)
Path A: 2 to 3 sessions, each in its own worktree on one bug in one golden run. Keep one writer per runtime file, since CD, DMA and VDP code is shared. Path B: 4 to 6 unit workers plus one lead, each with its own worktree and build folder. Merge one at a time and rerun make check on main.
Max 5x (now called Max)
Path A: 1 session, sometimes 2 when one only reads. Path B: 2 unit workers plus the lead. Send hard units one at a time. Batch the docs updates at the end of the day.
Lines for this project's CLAUDE.md
- Read `SCOPE.md`, `PROGRESS.md` and `notes/findings.md` at the start of every session. - Never edit generated C++ under `build/` or `work/`. Fix `game.toml`, a discovery seed or the runtime, then regenerate. - Never edit the toolkit copy in this repo. Toolkit fixes go upstream or into `patches/` as numbered patches on the pinned commit. - No stubs and no faked hardware events. If the game waits on hardware, find the missing behavior and report it. - The one check is `bash tools/check.sh <ABSOLUTE_PATH_TO_CUE>` (Path A) or `make check` in WSL (Path B). No pasted output means not done. - Do not edit `refs/hashes.txt`, `config/*.sha256`, golden pictures or check scripts. A change needs my approval in the same commit as its cause. - Disc images, BIOS files and anything extracted stay in `iso/`, `extracted/` and `build/`. Never commit or paste their bytes. - A unit is matched only when `make check` is byte-identical. Close or equivalent is reported as attempted or equivalence-verified, never matched. - Report the interpreter fallback count with every Path A result. Fallback is not recompiled code. - In a worktree, use absolute paths for the disc and the tools. From Git Bash, set `MSYS_NO_PATHCONV=1` before calling `wsl`. - Propose commits. Do not commit on your own. - Write side issues in `notes/parking-lot.md` and dead ends in `notes/findings.md`. Start every report with DONE, PARTIAL or BLOCKED.
Keep the context small
- Never read a generated C++ file whole. Search for the address, then read 30 lines.
- Give Claude the first differing VBlank and both pictures, not a whole trace log.
- Pass program names and addresses. Let Claude disassemble just that range with
saturnkit.sh2 --at --count. - Add
Readdeny rules foriso/**,extracted/**,build/**andwork/**. - Use a subagent to read a big discovery report and return only the gaps.
- Clear the chat after each unit. The ledgers carry the state.
More prompts for this system
Each step above has its own prompt. These extra prompts cover the rest of the work. Fill in the parts in <ANGLE_BRACKETS>.
Scope and feasibility
Before any work on a new Saturn game. It tells you which path is realistic and what exists.
GOAL: Tell me if <GAME> (Saturn, product code <PRODUCT_CODE>) can be ported to PC by static recompilation, and draft SCOPE.md. READ FIRST: https://github.com/vs-sr-dev/saturnkit , https://github.com/callumjenkins/saturn-recomp , https://github.com/tmcleroy/satrecomp , https://github.com/blythos/atolm (READMEs only). FENCE: Edit only `SCOPE.md` and `notes/prior-work.md`. Do not install anything. Do not open disc files. CHECK: Done means SCOPE.md names the toolkit, the first milestone and its check, and notes/prior-work.md lists every repo for this game or engine with a URL and its status. BUDGET: Stop after 1 hour. IF BLOCKED: Stop. Say plainly if a path is not realistic and why. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the repo list. 3) Files changed. 4) Risks you see. 5) New parking-lot items.
A good answer: A short SCOPE.md with one toolkit and one milestone. A list of real repos with links. A plain warning if Path B is out of reach.
Map one program
After the disc survey, for each SH-2 program you will translate.
GOAL: Map <PROGRAM> loaded at <ADDR>: functions, library code and gaps. READ FIRST: notes/disc.md, `build/<PROGRAM>.report.txt`, `build/ghidra/<PROGRAM>.funcs.txt`. FENCE: Edit only `notes/functions.csv` and `notes/discovery-gaps.md`. Do not edit game.toml, the toolkit or generated code. CHECK: Done means every function has address, size, name or `FUN_` placeholder, proof and status, and every Ghidra-only function has a reason in notes/discovery-gaps.md. BUDGET: Stop after 2 hours. IF BLOCKED: Stop. List addresses you cannot classify. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: counts by status. 3) Files changed. 4) Open gaps. 5) New parking-lot items.
A good answer: A CSV with one row per function and a count of library functions. A short gap list where each line has an address and a reason.
Unit loop, Path A: one runtime gap
Each time a golden run fails or the game hangs.
GOAL: Fix the hang at VBlank <N> in movie <MOVIE> of <GAME>. READ FIRST: notes/findings.md, the last 200 lines of `build/run.log`, `build/shots/<N>.png`, `refs/<N>.png`. FENCE: Edit only `<RUNTIME_FILE>` and `notes/`. No stubs, no skipped waits, no generated-code edits. CHECK: Run `bash tools/golden.sh <ABSOLUTE_PATH_TO_CUE>`. Done means this movie passes VBlank <N> and all others still pass. BUDGET: Stop after 3 fix ideas. IF BLOCKED: Stop. Show the loop the game waits in and the hardware register it reads. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: golden.sh output. 3) Files changed. 4) What is left. 5) New parking-lot items.
A good answer: DONE with the register or timing that was wrong, the one runtime change, and every golden run passing.
Unit loop, Path B: one translation unit
For each unit in the Path B grind.
GOAL: Match unit <UNIT> of <PROGRAM> byte for byte. READ FIRST: SCOPE.md, `asm/<UNIT>/`, one matched example `src/<EXAMPLE>.c`, notes/findings.md. FENCE: Edit only `src/<UNIT>.c`. No inline asm, no `.byte`, no new flags, no edits to hashes or the Makefile. CHECK: In WSL run `make check`. Done means the program is byte-identical with this unit built from C. BUDGET: Stop after 8 attempts. Save each attempt as `scratch/<UNIT>/try-<K>.c`. IF BLOCKED: Stop. Paste the smallest remaining diff and mark the unit attempted in notes/findings.md. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: make check output. 3) Files changed. 4) Remaining diff if any. 5) New parking-lot items.
A good answer: DONE with a clean make check, or BLOCKED with a small diff and a named cause such as register choice.
Batch dispatch
When you lead several workers at once.
GOAL: Pick the next <N> units and give each worker one task card. READ FIRST: PROGRESS.md, config/units.csv, notes/findings.md. FENCE: Edit only `PROGRESS.md` and `notes/assignments.md`. Do not write C. Each worker gets its own worktree at `<ABSOLUTE_WORKTREE_ROOT>/<UNIT>`. CHECK: Done means notes/assignments.md lists each unit, its worker, its worktree path and its card, and no unit is given twice. BUDGET: Stop after <N> units are assigned. IF BLOCKED: Stop. Say which units are not ready and why. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the assignment table. 3) Files changed. 4) Units left. 5) New parking-lot items.
A good answer: A table of units, sorted small first, each with a worktree path and a full task card ready to paste.
Debug with evidence
When a bug has resisted one fix, or two people disagree on the cause.
GOAL: Prove the cause of <SYMPTOM>. Do not fix it yet. READ FIRST: notes/findings.md, `movies/<MOVIE>.txt`, `build/shots/` and `refs/` around VBlank <N>. FENCE: Edit only `notes/debug-<SYMPTOM>.md`. Read-only everywhere else. Use `--watch`, `--peek` and `--trace` runs only. CHECK: Done means the note names the first wrong memory write, its address, the function that made it, and a second run that shows the same thing. BUDGET: Stop after 6 runs. IF BLOCKED: Stop. List what you ruled out and the next run you would make. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the watch output lines. 3) Files changed. 4) Proposed fix, not applied. 5) New parking-lot items.
A good answer: One proven first wrong write with the run that shows it twice, plus a fix proposal you can approve.
Verify and hunt for cheating
After every batch, in a brand new session.
GOAL: Check that the work in commits <FROM>..<TO> is real. READ FIRST: CLAUDE.md, PROGRESS.md, `git diff <FROM>..<TO> --stat`. FENCE: Read-only. Write only `notes/verify-<DATE>.md`. CHECK: Rerun `bash tools/check.sh <ABSOLUTE_PATH_TO_CUE>` and `bash tools/golden.sh <ABSOLUTE_PATH_TO_CUE>` (or `make check`). Done means you pasted the output and checked the diff for: edited hashes or refs, edits under build/ or the toolkit copy, stubs, skipped waits, inline asm or .byte in src/, and fallback counted as recompiled. BUDGET: Stop after 1 hour. IF BLOCKED: Stop. Report what you could not run. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) PASS or FAIL. 2) Proof: check output. 3) Each suspect change with file and line. 4) What to redo. 5) New parking-lot items.
A good answer: PASS with fresh check output, or FAIL with each suspect change named by file and line.
Status report
Once a week, or before you decide what comes next.
GOAL: Write a status report from the ledgers only. READ FIRST: PROGRESS.md, notes/functions.csv, config/units.csv, notes/findings.md, notes/parking-lot.md. FENCE: Edit only `notes/status-<DATE>.md`. Do not run builds. CHECK: Done means every number in the report comes from a ledger file, with the file named next to it. BUDGET: Stop after 20 minutes. IF BLOCKED: Stop. Say which ledger is missing or stale. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Golden runs passing, fallback count, units matched, attempted, equivalence-verified and unattempted. 3) Top 3 blockers. 4) Parking-lot items I must decide.
A good answer: A one-page report with numbers and file names, and no padding.
Session handoff
Before you stop for the day or your usage runs low.
GOAL: Save everything the next session needs into the repo. READ FIRST: PROGRESS.md, notes/findings.md, `git status`. FENCE: Edit only `PROGRESS.md`, `notes/findings.md` and `notes/next-session.md`. Do not change code. CHECK: Done means notes/next-session.md lists the current unit, the last check output, the next command to run, and open questions, and a fresh session could start from it alone. BUDGET: Stop after 15 minutes. IF BLOCKED: Stop. Say what you could not record. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the text of notes/next-session.md. 3) Files changed. 4) Uncommitted work. 5) New parking-lot items.
A good answer: A short note with the exact next command, so a fresh session can start without asking.
Blocked or cannot deliver
When a task keeps failing and you need a plain answer.
GOAL: Tell me plainly whether <TASK> can be done with what we have. READ FIRST: notes/findings.md entries for <TASK>, the last three reports on it. FENCE: Read-only. Write only `notes/blocked-<TASK>.md`. CHECK: Done means the note says YES, NO or NOT YET, the exact reason, the evidence, and two or three options with their cost. BUDGET: Stop after 30 minutes. IF BLOCKED: Stop. Say what evidence is missing. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) YES, NO or NOT YET. 2) Proof. 3) Options. 4) What you need from me.
A good answer: A clear NO or NOT YET with the reason, such as the exact SHC version being lost, and real options.
Scope change request
When Claude finds work outside the fence that seems needed.
GOAL: Ask me before leaving the fence for <CHANGE>. READ FIRST: SCOPE.md, CLAUDE.md. FENCE: Do not make the change. Write only `notes/scope-request-<CHANGE>.md`. CHECK: Done means the request says what change, which files, why the current task needs it, the risk, and how we would check it. BUDGET: Stop after 15 minutes. IF BLOCKED: Stop and ask. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) The request. 2) What happens if I say no. 3) Files that would change.
A good answer: A short request you can answer with yes or no, with no code changed yet.
Keep Claude on task
These are the detours Claude tends to take on this system, and the rule that stops each one. The full method is on Stay on Task.
| The detour | The rule to give Claude |
|---|---|
Claude edits generated C++ under build/ to get past a crash. | Never edit generated C++. Fix game.toml, a discovery seed or the runtime, then regenerate. |
| The game waits for the CD or DMA, and Claude fakes the done flag to move on. | No stubs and no faked hardware events. Find the missing hardware behavior and prove it with a watch run. |
| Claude patches the toolkit copy inside the game repo. | The toolkit copy is read-only. Put fixes upstream or in patches/ as numbered patches on the pinned commit. |
| Claude reports a scene as recompiled while it still runs in the interpreter. | Report the fallback count with every result. Fallback code is not recompiled code. |
| Claude blames the first plausible part, like VDP2 rotation, and builds on that guess. | No fix until the first wrong write is found and shown twice. Retract a diagnosis in notes/findings.md when evidence changes. |
| On Path B, Claude calls a 97% byte match a match, or adds inline assembly. | A unit is matched only when make check is byte-identical. Close work is logged as attempted. |
| On Path B, Claude starts extracting assets or writing a renderer. | Assets and new engine code are out of scope. Write the idea in notes/parking-lot.md. |
| Claude builds from frozen old folders or runs old tools that no longer fit. | Folders listed as frozen, like archive_src/, are read-only reference. Do not build from them. |
Problems other projects hit
SH-2 DMA moved only a quarter of the data in 16-byte mode but reported it done. Logos were cut and screens went black.
Fix: Model the DMA transfer size exactly. Check DMA before blaming the video chips.
Seen in: pc-deepfear, PAL-Saturn-Recomp
The CD drive answered faster than real hardware. Games timed out, lost sound or overwrote colors before VBlank.
Fix: Use real 2x read speed and seek times, as Mednafen times them.
Seen in: pc-deepfear, Fighters Megamix Recomp
A single .bin holding every track broke the CD model, because the audio flag was set per file.
Fix: Track the mode per track, and read a PREGAP as silence.
Seen in: PAL-Saturn-Recomp, pc-dragonballlegend
Function finding missed SHC position-independent calls and GCC switch tables. It also took strings for code.
Fix: Teach discovery each new pattern, cross-check with Ghidra, and add guards for data.
Seen in: pc-dragonballlegend, pc-deepfear
Ghidra invented function starts in the middle of functions. Daytona had 487 to sort.
Fix: Judge doubtful starts in small batches with proof, and write results to an append-only CSV.
Seen in: Daytona USA CCE (Saturn) AI Reverse Engineering Project
Git Bash rewrote /mnt/... paths when calling WSL, so commands failed.
Fix: Call WSL from PowerShell or cmd, or set MSYS_NO_PATHCONV=1 in Git Bash.
Seen in: Daytona USA CCE (Saturn) AI Reverse Engineering Project, Sega Rally PSP
On Windows, a stray libstdc++-6.dll from Git for Windows made the exe fail with 0xC0000139. CRLF line endings also broke hash checks.
Fix: Link statically, and set core.autocrlf false on the upstream checkout.
Seen in: PAL-Saturn-Recomp
Speed went wrong. A PAL game counted fields and ran 6/5 too fast at 60 Hz. A lower frame cap made the player walk five times too fast.
Fix: Keep game logic at its own rate. Draw extra frames between steps instead.
Seen in: pc-dragonballlegend, pc-virtualhydlide
Sound broke in quiet ways. One sound pitch bit was ignored, and fight sound stopped until the sound side got time.
Fix: Add sound regression tests, and give the 68000 and SCSP time inside rewritten code.
Seen in: PAL-Saturn-Recomp, Fighting Vipers Recomp
Saturn data is big-endian, but PC and PSP chips are little-endian. Tables read wrong.
Fix: Read every original table through helpers like g16 and g32.
Seen in: Sega Rally PSP
How long it takes
| Max 20x (now called Ultra) | Max 5x (now called Max) | One person, no AI | How sure | |
|---|---|---|---|---|
| Path A: running on PC | 2 to 8 weeks | 5 to 20 weeks | 4 to 18 months | medium confidence |
| Path B: full decomp | 9 months to 3 years | 1.5 to 6 years | 5 to 10 years or more | low confidence |
Read this first
These numbers assume one medium-sized game and one person giving 10 to 15 hours a week. Path A is medium confidence. Several dated projects on Saturn got real play in one to three weeks on an existing toolkit. But AI use is stated in only a few, repo dates can hide earlier work, and no project claims a full playthrough. The no-AI figure is a guess: no Saturn recomp says it was made without AI. Path B is low confidence. No Saturn game has a full decomp. These ranges come from the slow progress of Daytona, atolm and the Saturn part of sotn-decomp, and from N64 projects.
What makes it faster or slower
- Whether a toolkit already handles your game's compiler and libraries. SHC or GCC patterns new to the toolkit add days each.
- How the game uses the CD. Streaming movies and CD music need careful drive timing.
- How many overlay programs the disc has. Virtual Hydlide has 15. Each needs its own load address.
- For Path B, whether the exact compiler survives. Without it, some units may never match.
- Your review time. Each fix needs a look at its proof, and that is your 10 to 15 hours a week.
The facts behind these numbers
| Project | What happened | Link |
|---|---|---|
| Baroque (SaturnRecomp) | First commit and first release 2026-10-22. 3 contributors. README says it was built with Claude. Runs on an interpreter runtime. | source |
| pc-dragonballlegend | First commit 2026-10-06. Boot to the first battle by 2026-10-12, on the existing saturnkit. 1 contributor. No AI stated. | source |
| pc-deepfear | First commit 2026-09-26. Reached the first room by 2026-10-12. 1 contributor. No AI stated. | source |
| Shining Force III Recomp | First commit and first release 2026-10-19. 11 releases by 2026-11-09. 2 contributors. Codex branch names hint at AI use. | source |
| saturn-recomp | Repo created 2026-10-04. README says Claude Code wrote most changes since the fork from saturnkit. | source |
| Daytona USA CCE (Saturn) AI Reverse Engineering Project | First commit 2026-03-01. Race module split to 100% byte coverage on 2026-05-27; the other 7 modules still come from retail bytes in the build. C lifting still going at the last commit, 2026-08-24. Claude Code with skills and MCP. | source |
| atolm (Panzer Dragoon Saga) | Created 2026-07-15, 56 commits to 2026-08-01. CLAUDE.md says Claude Code in WSL. About 1 KB of code matched; most units still unattempted. | source |
| Azel | First commit 2017-02-24. 1 contributor, no AI stated. In 2026 the start of the game is still only semi playable. | source |
| Castlevania: Symphony of the Night Decompilation | First commit 2022-01-01. 55 contributors. On decomp.dev (read 2026-11-13) the PS1 version is 72.10% decompiled and the Saturn version 35.87% of 735 KB of code. | source |
Projects reviewed (13)
Fewer than 10 games on RecompLauncher: it lists only 2 Saturn games, and both were reviewed. 11 more projects came from outside it, one per game, for 13 games in all. Most are young and have 1 to 5 stars.
What each project teaches
Castlevania: Symphony of the Night Decompilation
Castlevania: Symphony of the Night
Started: 2022-01. First release: 2023-04. Code: C.
AI: policy: agents may help, but PR text must be written by a person
Lesson: One repo can host PS1, PSP and Saturn builds with a VERSION switch. Its Saturn build uses its own splitter and is the furthest Saturn matching decomp reviewed here, at about 36%.
Azel
Panzer Dragoon Saga
Started: 2017-02. First release: none. Code: C++.
AI: none stated
Lesson: Rewriting a big Saturn game by hand takes years. After nine years, only the start is semi playable.
Tomb Raider for the Sega Saturn (saturn-tr-remix)
Tomb Raider
Started: 2026-10. First release: 2026-11. Code: C++, C and Python.
AI: implied: .mcp.json for a Mednafen MCP server and nine parallel read-only audits Agent files: .mcp.json.
Lesson: Treat the retail code as the truth. Record each difference as a numbered issue with severity and fix size.
Shining Force III Recomp
Shining Force III
Started: 2026-10. First release: 2026-10. Code: Python and C++.
AI: implied: codex/ branch names and Codex mentions in docs; not stated directly
Lesson: Identify discs by an exact data-track hash, and carry your toolkit fixes as a patch on a pinned commit.
Baroque (SaturnRecomp)
Baroque
Started: 2026-10. First release: 2026-10. Code: PowerShell and C.
AI: yes: README says it was developed with AI assistance (Claude)
Lesson: Its runtime runs SH-2 code in an interpreter on the real BIOS, so it is not a recomp. Hangs came from missing hardware, like one CD command.
Sega Rally PSP
Sega Rally Championship
Started: 2026-10. First release: none. Code: C and Python.
AI: none stated
Lesson: Build an oracle first. Run the original SH-2 code in an interpreter and diff your C against its traces.
pc-virtualhydlide
Virtual Hydlide
Started: 2026-09. First release: none. Code: Python and C++.
AI: none stated
Lesson: Self-test the recompiler against an SH-2 interpreter before you run the game. Here 51,532 vectors showed 0 differences.
Fighters Megamix Recomp
Fighters Megamix
Started: 2026-11. First release: 2026-11. Code: C++.
AI: none stated
Lesson: Record what runs, translate it, and keep an interpreter fallback so the game always works.
pc-dragonballlegend
Dragon Ball Z: Idainaru Dragon Ball Densetsu (Dragon Ball Z: The Legend)
Started: 2026-10. First release: none. Code: Python.
AI: none stated
Lesson: Record every played session as text and replay it headless. Each toolkit change must pass the other ports too.
PAL-Saturn-Recomp
The Legend of Sword and Fairy (Saturn version)
Started: 2026-10. First release: 2026-10. Code: Python and C++.
AI: none stated
Lesson: Mark every claim as verified, pending or hypothesis. Its first black-screen diagnosis was wrong and was taken back.
Fighting Vipers Recomp
Fighting Vipers
Started: 2026-11. First release: 2026-11. Code: C++.
AI: none stated
Lesson: Hand-written readable routines are checked call by call against the original code with make check-rewrites.
pc-deepfear
Deep Fear
Started: 2026-09. First release: none. Code: Python.
AI: none stated
Lesson: Fix the runtime, not the game. Every first-room fault was a runtime bug, like DMA size or drive speed.
Daytona USA CCE (Saturn) AI Reverse Engineering Project
Daytona USA Championship Circuit Edition
Started: 2026-03. First release: none. Code: Assembly, C and Python.
AI: yes: README calls it AI-driven; CLAUDE.md, skills and a Mednafen MCP server Agent files: CLAUDE.md, .claude/rules/commit-discipline.md, .claude/skills/eval-midentry/SKILL.md, .claude/skills/re-toolkit/SKILL.md.
Lesson: Reach a byte-identical assembly rebuild first. Then prove pointers with a shifted build that still boots.
What we could not check
- Which compiler the Symphony of the Night Saturn build matches with. The saturn-splitter README names a Cygnus DOS compiler run under dosemu, but the sotn-decomp files we read do not say.
- Whether
ApplySig.py, a 2020 script, runs in Ghidra 12. Daytona used it, but its Ghidra version is not stated. - Whether the loader's 12.0.0 zip installs in Ghidra 12.0.1 to 12.0.4. Its file name says 12.0.
- Where the
saturnruntime saves--shotpictures. The saturnkit README does not say, so the check script in Path A step 2 copies them. - Whether
saturnrecomp.referenceworks with Japanese discs. Its README names onlympr-17933.binfor US and European discs. - Whether
mednafen-saturn-debugbuilds with a plain./configure && make. Its README says so, but SaturnAutoRE builds it with a GCC 4.9.4 cross script. - Whether objdiff reads Hitachi SHC object files. Its README lists SuperH, but no reviewed Saturn project used it.
- AI use in most reviewed projects. Only Baroque, Daytona and the saturn-recomp toolkit state it. Others only hint at it.
- Whether any reviewed port is playable from start to end. None claims a full playthrough.
- The licence status of the period compilers that project scripts fetch. This guide does not name a download source.
- Whether Ghidra 12.0, JDK 21, the Saturn loader and GhidrAssistMCP 2.8.0 work together. Each version comes from a README or release name. None of the tools in this guide was installed or run for this check.
- How long the Path A projects worked before their first commit. Repo dates can hide earlier work.
Sources
- saturnkit README
- saturn-recomp README
- satrecomp README
- SaturnRecomp README
- atolm README and CLAUDE.md
- saturn-splitter README
- Ghidra Sega Saturn Loader README
- Ymir README
- Mednafen Saturn documentation
- SaturnAutoRE README
- mednafen-saturn-debug README
- GhidrAssistMCP README
- m2c README
- asm-differ README
- objdiff README
- Saturn-SDK-GCC-SH2 README
- Ubuntu package binutils-sh-elf (noble)
- MSYS2 package mingw-w64-x86_64-sdl3
- Rodrigo Copetti, Sega Saturn architecture
- Retro Reversing, official Sega Saturn SDK
- Sega Saturn FAQ, GNU development environment
- Sega Saturn documentation list (antime)
- decomp.dev page for sotn-decomp
- decomp.dev page for the sotn-decomp Saturn version
- Beetle Saturn libretro README (BIOS names)
- Ghidra 12.0 README (JDK 21)
- GhidrAssistMCP releases (Ghidra version per zip)
- Ghidra Sega Saturn Loader releases
- splat README (supported platforms)
- Claude Code MCP docs (`claude mcp add --transport http`)