Game Gear decomp guide
Small Z80 games and one shared recompiler make Path A quick. No one has a full C decomp yet.
What this system is like
The Game Gear is a handheld Master System. It runs a Z80 chip at about 3.5 MHz. Games come on small cartridges, from 128 KB to 1 MB in the projects we read. Every game we found was written by hand in Z80 assembly, not in C.
Path A is new but works. Three projects turned the game's machine code into C by static recompilation. A shared framework, smsggrecomp, does this for both the Master System and the Game Gear. 43 of its 56 commits carry a Claude co-author line.
Path B is the hard part. Three projects made a disassembly that rebuilds the ROM byte for byte. A disassembly is the game's machine code written out as assembly text. No one has rewritten a whole Game Gear game in C. One project tried and stopped. We tell you plainly that this path is unproven.
Most work runs on Windows. Only a few tools need WSL: z80dasm, the PSP kit and some shell scripts. The field is small. We found only seven real Game Gear projects, so this guide adds three Master System ones.
It is a Master System with a flag
The Game Gear uses the same Z80, sound chip and video chip as the Master System. It differs in screen size, colour depth, stereo and a few ports. So one recompiler serves both. Master System work teaches you most of what you need.
Every game is assembly
We found no Game Gear game built from C. So there is no original compiler to match. On Path B, "matching" means a disassembly that rebuilds the exact ROM. A C version must be proven by tests instead.
Banks hide code
Most games are bigger than the Z80 can see at once. The game swaps 16 KB banks into three windows. The same address can hold different code at different times. Your tools must track which bank is live.
Z80 code is hard to split
Z80 instructions are one to four bytes long. A wrong start address decodes into nonsense. Games also jump through tables, push an address and return, or copy code into RAM. Each of these hides code from a simple tracer.
Small games, fast checks
A Game Gear ROM is tiny next to later consoles. A full rebuild takes seconds. A good interpreter can replay a whole session quickly. So you can check every change against the real behaviour.
Very few projects exist
We found seven real Game Gear projects. Most are from 2026 and have under 15 stars. Their claims are the authors' own. Treat each as one data point, not a proven recipe.
Two paths
Get it running on PC
You give your own ROM and a game.toml file to smsggrecomp. Its tool SmsRecomp.exe writes C, one function per Z80 routine. A runtime stands in for the video chip, sound chip, ports and mapper. Code it missed runs on a built-in interpreter for now. You close each gap and check the build against the interpreter and an emulator.
Full decomp for porting
You first make a disassembly that rebuilds the ROM byte for byte. You label it, split out the art and levels, and sort code from data. Then you rewrite routines in C and prove each one against a reference interpreter. Last, you put the hardware behind an interface and build for a new system. The first half is proven on this system. The C half is not.
Path A: Get it running on PC
You give your own ROM and a game.toml file to smsggrecomp. Its tool SmsRecomp.exe writes C, one function per Z80 routine. A runtime stands in for the video chip, sound chip, ports and mapper. Code it missed runs on a built-in interpreter for now. You close each gap and check the build against the interpreter and an emulator.
Method: static recompilation
Pick this first for any Game Gear game. Sonic Blast booted within days on this framework. The function list and the test routes also help Path B later.
Pick the game and write the scope
A different dump or region is a different program. So you pin the exact ROM by hash first. Then you look for prior work. A disassembly or a recomp of your game can save weeks.
- Print size, CRC32, SHA-1 and the header with Python:
python -c "import zlib,hashlib;d=open(r'<ABSOLUTE_PATH_TO_ROM>','rb').read();print(len(d),format(zlib.crc32(d),'08X'),hashlib.sha1(d).hexdigest(),d[0x7FF0:0x7FF8],hex(d[0x7FFF]))". - Check that bytes
$7FF0to$7FF7readTMR SEGA. Check that the high digit of the last byte is 5, 6 or 7. That marks a Game Gear region. Headers can hold mistakes, so the hash is what pins the ROM. - Read the game list in
smsggrecomp'sCLAUDE.md. It names Sonic Blast, Sonic Chaos, Sonic and Tails 1 and 2 with their CRC32 values. - Search GitHub, smspower.org and Sonic Retro for a disassembly of your game. Search for a Master System version too.
- Write
SCOPE.md: game, region, CRC32, SHA-1, size, goal, technique, first milestone and its check, and an out-of-scope list.
Prompt for ClaudeGOAL: Draft SCOPE.md for a Game Gear static recomp of <GAME> (<REGION>). READ FIRST: bytes $7FF0-$7FFF of `<ABSOLUTE_PATH_TO_ROM>` (read only), https://www.smspower.org/Development/ROMHeader, https://github.com/mstan/smsggrecomp/blob/main/CLAUDE.md FENCE: Create only `SCOPE.md` and `notes/prior-work.md`. Do not copy or move the ROM. Do not write code. CHECK: Run the Python one-liner from step 1 of the guide and paste its output. Done means SCOPE.md has the game, region, size in bytes, CRC32, SHA-1, the header text and region digit, goal, technique, first milestone and its check, and an out-of-scope list. BUDGET: Stop after 30 minutes of searching for prior work. IF BLOCKED: Stop. Do not guess a region or a hash. Tell me what is missing. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: paste the hash and header output. 3) Files changed. 4) Prior work found, with links. 5) New parking-lot items.
Done whenSCOPE.mdnames the exact ROM by CRC32, SHA-1 and size, lists prior work with links, and you approved it.Proof this works: SonicBlastGGRecomp (ROM pinned by CRC32 0x031B9DA9 and size), Devilish PSP (
embed_rom.py --checkrefuses other dumps), https://www.smspower.org/Development/ROMHeader- Print size, CRC32, SHA-1 and the header with Python:
Set up the repo, the recompiler and the one check
You install the build tools and make a small game repo. The framework sits in it as a pinned submodule. The ROM and the generated C stay out of git. You also write the one check command now, even if it does little yet.
- Install MSYS2 from msys2.org. In the MINGW64 shell run
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2. - Make your game repo. Add the framework:
git submodule add https://github.com/mstan/smsggrecompthengit submodule update --init --recursive. - Copy the shape of
SonicBlastGGRecomp:game.toml(withplatform = "gg"and yourcrc32),build.ps1, andtests/coverage/. ItsCMakeLists.txtis three lines: setSMSGG_ROOT, includesmsggrecomp/cmake/SmsGame.cmake, and callsms_add_game(<GAME>Recomp). - Add
*.gg,*.sms,*.bin,generated/,build/,out/andcoverage-*/to.gitignorebefore the ROM is anywhere near the repo. - Build once:
powershell -File build.ps1 -Rom '<ABSOLUTE_PATH_TO_ROM>'. The script builds the recompiler, regenerates the C and links the runtime. - The build looks for
cmake.exe,ninja.exeandgcc.exeinC:\msys64\mingw64\bin. If MSYS2 lives elsewhere, add-Sdl '<MSYS2_MINGW64_DIR>'. - Write
tools/check.ps1. It runsbuild.ps1, thenbuild\<GAME>Recomp.exe '<ABSOLUTE_PATH_TO_ROM>' --frames 600 --report out\boot.jsonwith no window. It prints PASS only if the report shows"dispatch_misses":0. Otherwise it prints FAIL and the count.
Prompt for ClaudeGOAL: Set up a game repo for <GAME> on smsggrecomp with one check command. READ FIRST: SCOPE.md, https://github.com/mstan/smsggrecomp/blob/main/README.md, https://github.com/mstan/SonicBlastGGRecomp (README, build.ps1, CMakeLists.txt, game.toml) FENCE: Edit only files in this repo. Add smsggrecomp as a submodule; never edit inside it. Do not add features. CHECK: Run `powershell -File tools/check.ps1 '<ABSOLUTE_PATH_TO_ROM>'`. Done means the build finishes, `git status` shows no ROM and no generated C, and the check prints PASS or a FAIL line with the miss count. BUDGET: Stop after 3 failed builds with the same error. IF BLOCKED: Stop. Paste the exact error. Do not switch compilers or install new tools without asking. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: paste the build tail and the check output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenbuild.ps1makes an exe from your ROM,git statusshows no ROM or generated C, andtools/check.ps1prints PASS or FAIL with a miss count.Proof this works: SonicBlastGGRecomp (build.ps1, MSYS2 default path C:\msys64\mingw64), https://github.com/mstan/smsggrecomp/blob/main/tools/build_game.ps1 (tool paths) and runner/main.c (
--frames,--report), Sonic the Hedgehog (Master System version) recomp (same build layout), https://github.com/mstan/smsggrecomp- Install MSYS2 from msys2.org. In the MINGW64 shell run
Map the ROM into a function list
The recompiler starts at the reset and interrupt vectors and follows calls. It cannot see code reached through tables or pushed addresses. You find those starts by reading the code. Every start needs proof, because a wrong Z80 start decodes into nonsense.
- Open the ROM in Emulicious. Use its disassembler, which splits code from data as the game runs. Play the attract demo and the first level.
- Load the ROM in Ghidra 12.2 with the Z80 language. The
Ghidra-SegaMasterSystem-Loaderfinds the header but does not map banks, so load each 16 KB bank at its window yourself. - In WSL, get a second opinion on a doubtful bank:
sudo apt install z80dasm, then runz80dasmon that bank's bytes. - Write
notes/functions.csvwith address, bank, size, name, proof and status. - Add proven starts to the
[functions]extralist ingame.toml, with jump tables beside them. Note which bank each one lives in.
Prompt for ClaudeGOAL: Build the first function list for <GAME> and feed proven starts to game.toml. READ FIRST: SCOPE.md, `game.toml`, the Emulicious or Ghidra listing at `<LISTING_PATH>`, https://github.com/mstan/smsggrecomp/blob/main/PRINCIPLES.md (sections 13 and 16) FENCE: Edit only `game.toml`, `notes/functions.csv` and scripts under `tools/map/`. Do not edit the framework or anything in `generated/`. CHECK: Run `powershell -File build.ps1 -Rom '<ABSOLUTE_PATH_TO_ROM>'`. Done means it finishes, every row in functions.csv names its bank and its proof, and no start sits inside another routine. BUDGET: Stop after 2 hours or 3 failed builds with the same error. IF BLOCKED: Stop. Do not guess entry points. List the addresses you could not prove. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: entry count and the build summary. 3) Files changed. 4) Unproven addresses. 5) New parking-lot items.
Done whennotes/functions.csvlists every start with its bank and proof, and the build runs on the newgame.tomlwithout errors.Proof this works: SonicBlastGGRecomp (its
dispatch_manifest.txtgrew from 40 to 198 ROM-verified entries, per smsggrecomp COVERAGE.md), https://github.com/mstan/smsggrecomp (README: the function finder starts at the vectors plus[functions].extraseeds and jump tables), KishinDoujiZenkiDecomp (bank-aware tracer, z80dasm as second opinion), https://github.com/VGKintsugi/Ghidra-SegaMasterSystem-LoaderWrite test routes you can replay
You need a check that does not trust your eyes. A route is a small text file of button presses and captures, tied to your ROM's CRC32. The framework runs it twice: once as native code and once in the interpreter. Then it compares the results.
- Write one route file per scene, such as
tests/coverage/<RUN>.txt. The first line isrom <CRC32>. Then lines like300 pad S,310 pad -and1250 capture title. Pad letters areUDLRABS, and-lets go. - Run one route:
build\<GAME>Recomp.exe '<ABSOLUTE_PATH_TO_ROM>' --route tests/coverage/<RUN>.txt --report out/<RUN>.json. - List your routes in
tests/coverage/suite.json:rom_crc32,rom_size, and acaseslist where each case has aname, aroutefile and aframescount. - Run the suite:
python smsggrecomp/tools/run_coverage_suite.py --runtime build/<GAME>Recomp.exe --rom <ABSOLUTE_PATH_TO_ROM> --suite tests/coverage/suite.json --out coverage-<N>. Use a new folder name each time. The tool refuses a folder that already exists. - For a second opinion, run the ROM in Mesen with no window:
Mesen.exe --testRunner <SCRIPT>.lua <ABSOLUTE_PATH_TO_ROM> --doNotSaveSettings. End the script withemu.stop(0).smsggrecomp/tools/oracle/mesen_vdp_dump.luais a working example.
Prompt for ClaudeGOAL: Write <N> replayable routes for <GAME> and run them as a coverage suite. READ FIRST: SCOPE.md, https://github.com/mstan/smsggrecomp/blob/main/COVERAGE.md, the `tests/coverage/` folder of https://github.com/mstan/SonicBlastGGRecomp FENCE: Edit only `tests/coverage/` (route files and suite.json, no ROM bytes) and `tools/ref/`. Do not change game logic or the framework. CHECK: Run `python smsggrecomp/tools/run_coverage_suite.py --runtime build/<GAME>Recomp.exe --rom <ABSOLUTE_PATH_TO_ROM> --suite tests/coverage/suite.json --out coverage-<N>` with a folder that does not exist yet. Done means it prints one `zero fallback:` line per route and writes `coverage-<N>/report.json`. BUDGET: Stop after 3 hours or 3 failed tries on the same route. IF BLOCKED: Stop. Do not loosen a capture or delete a route to get a pass. Tell me what differs. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the suite summary lines. 3) Files changed. 4) Which scenes the routes cover and which they skip. 5) New parking-lot items.
Done whenThe coverage suite prints azero fallback:line and anequal surface captures:count for every route, and writesreport.json.Proof this works: SonicBlastGGRecomp (tests/coverage/suite.json, 30 act and character cases), https://github.com/mstan/smsggrecomp/blob/main/COVERAGE.md, Devilish PSP (27 scripted button sessions)
- Write one route file per scene, such as
First light: boot to the title screen
You generate the C, build it and boot it. The interpreter fallback stays on for now, so missed code still runs. The goal is the Sega logo and the title screen, matching the interpreter.
- Build:
powershell -File build.ps1 -Rom '<ABSOLUTE_PATH_TO_ROM>'. - Run it:
.\build\<GAME>Recomp.exe '<ABSOLUTE_PATH_TO_ROM>' --window 3. - Run your boot route twice: once as is, and once with
--interp, which runs the reference interpreter. Compare the files eachcaptureline wrote. A one-case suite does both runs for you. - Read
dispatch_misses.log. The runner writes it in the folder you ran it from. Copy its line count intoPROGRESS.md. - Close old copies before each run. In PowerShell:
taskkill /F /IM <GAME>Recomp.exe. In Git Bash:taskkill //F //IM <GAME>Recomp.exe. The framework's rule 24 allows one copy at a time.
Prompt for ClaudeGOAL: Generate, build and boot <GAME> to its title screen with the interpreter fallback on. READ FIRST: SCOPE.md, PROGRESS.md, game.toml, https://github.com/mstan/smsggrecomp/blob/main/CLAUDE.md FENCE: Edit only `game.toml`, the per-game source files and `CMakeLists.txt`. Never edit `generated/`. Never edit the framework submodule. CHECK: Run `powershell -File tools/check.ps1 '<ABSOLUTE_PATH_TO_ROM>'` and the boot route. Done means the build runs to the title with no crash, and the boot captures match the interpreter. BUDGET: Stop after 4 failed builds or 2 hours without a new frame. IF BLOCKED: Stop. Paste the last log lines and the first differing capture. Do not stub a routine to get past a crash. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: check output, route report and a screenshot path. 3) Files changed. 4) Miss count. 5) New parking-lot items.
Done whenThe build reaches the title screen with no crash, and the boot route's captures match the interpreter.Proof this works: SonicBlastGGRecomp (v0.0.1 on 2026-06-23 boots through the intro to the title), Sonic the Hedgehog (Master System version) recomp (boots and plays Green Hill Zone)
- Build:
Close the code gaps
A dispatch miss means the game jumped to an address with no generated function. The interpreter hides it, so you must look. One unit of work is one missed address. You prove where its routine starts, then regenerate.
- After every run, read
dispatch_misses.log. Empty means done for that run. In a suite run, each route has its own log incoverage-<N>/<CASE>/native/. - For each address, find it in your Emulicious or Ghidra listing. Decide: real routine start, middle of a routine, or data.
- Check which bank was live when the jump happened. The same address can mean different code in different banks.
- Add proven starts to
game.tomlwith a note of the proof. Never add an address only because the log names it. - Regenerate, rebuild and rerun every route. Repeat until the log is empty on all of them. The suite exits with code 1 while any route still has a miss or interpreted cycles.
Prompt for ClaudeGOAL: Resolve dispatch miss <ADDRESS> (bank <BANK>) in <GAME>. READ FIRST: `dispatch_misses.log`, the listing at <ADDRESS>, `notes/functions.csv`, https://github.com/mstan/smsggrecomp/blob/main/PRINCIPLES.md (section 16) FENCE: Edit only `game.toml` and `notes/functions.csv`. Never edit `generated/`. Never add an address only because the miss log names it. CHECK: Rebuild and run the coverage suite. Done means <ADDRESS> no longer appears in `dispatch_misses.log`, no new miss appears, and every route still matches. BUDGET: Stop after 3 failed tries or 45 minutes. IF BLOCKED: Stop. Paste the listing and say why the start is unclear. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the listing, the miss count before and after, the suite summary. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenrun_coverage_suite.pyexits with code 0, so every route has zero misses and zero interpreted cycles, and the capture counts did not drop.Proof this works: SonicBlastGGRecomp (all 30 routes with zero fallback), https://github.com/mstan/smsggrecomp/blob/main/PRINCIPLES.md (13a and 16), MMPR: The Movie, Game Gear to PC (runtime miss log closes gaps)
- After every run, read
Fix differences at the first divergence
A wrong picture often starts with a wrong value many frames earlier. So you never chase the symptom. You find the first frame where native code and the interpreter differ. Then you narrow it to one instruction, one port or one mapper rule.
- Find the first route capture that differs in
coverage-<N>/report.json. The suite compares four files per capture:.png,.vram,.cramand.regs. - Copy that route to
tests/probe/<RUN>.txt. Addcapturelines at earlier frames and run it native and with--interp. Halve the gap until you have the first differing frame. - For a third opinion, dump the same frame from your build with
--frames <N> --dump-frame <F> --dump-out x.png. Dump it in Mesen withmesen_vdp_dump.lua. Compare withpython smsggrecomp/tools/oracle/vdp_diff.py x.png.vram x.png.cram <MESEN_VRAM> <MESEN_CRAM>. - Read the listing for the code that writes the first wrong byte. Name one instruction, one port or one mapper rule as the cause.
- Fix the cause in the recompiler, the runtime or
game.toml. Never in generated C. - Write each case in
notes/divergence-log.mdas frame, symptom, cause and fix.
Prompt for ClaudeGOAL: Find and fix the first divergence in route <RUN> of <GAME>. READ FIRST: `notes/divergence-log.md`, `coverage-<N>/report.json` for <RUN>, https://github.com/mstan/smsggrecomp/blob/main/COVERAGE.md (route controls), https://github.com/mstan/smsggrecomp/blob/main/ACCURACY.md (section 4) FENCE: Edit only the files named in CLAUDE.md for runtime fixes, `game.toml`, probe routes in `tests/probe/`, and `notes/divergence-log.md`. Never edit `generated/` or `tests/coverage/`. CHECK: Run the coverage suite into a new `coverage-<N>` folder. Done means <RUN> matches further than before, the cause is one instruction, port or mapper rule, and no other route got worse. BUDGET: Stop after 2 fix tries that do not move the first divergence. IF BLOCKED: Stop. Report the frame, both values, and your best two causes with proof for each. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: first divergent frame before and after. 3) Files changed. 4) The cause in one sentence. 5) New parking-lot items.
Done whenInreport.json, every capture of every route has all four files equal, and each fix has a line innotes/divergence-log.md.Proof this works: https://github.com/mstan/smsggrecomp/blob/main/COVERAGE.md (
capturelines, native and interpreter runs compared), https://github.com/mstan/smsggrecomp/blob/main/ACCURACY.md (--dump-frame,mesen_vdp_dump.lua,vdp_diff.py), SonicBlastGGRecomp (one 33-pixel ring-icon capture traced to one pending sprite byte), MMPR: The Movie, Game Gear to PC (RAM, VRAM, CRAM and frames compared every frame)- Find the first route capture that differs in
Harden it and ship without the game
You lock in what works. Old fixes must stay fixed. Then you package the build so nobody gets the game from you. Players bring their own ROM, and the build checks its CRC32.
- Cover every level and both endings with routes. Keep the suite in
tests/coverage/suite.json. - Keep zero fallback as the gate.
run_coverage_suite.pyalready exits with code 1 if any route has a miss or interpreted cycles. - Build from a fresh clone and rerun the whole suite.
- Ship an exe that refuses any ROM but yours, by CRC32 and size. Keep
SDL2.dllnext to it. - Scan the release zip for ROM bytes before you publish it. Play it through yourself and record that you did.
Prompt for ClaudeGOAL: Add a full regression suite and a ROM-free release package for <GAME>. READ FIRST: PROGRESS.md, `tests/coverage/suite.json`, the README of https://github.com/mstan/SonicBlastGGRecomp FENCE: Edit only `tests/`, `tools/release/` and `.github/`. Do not change game behaviour. Do not change any expected capture. CHECK: From a fresh clone, run the coverage suite, then `python tools/release/scan_rom_bytes.py dist/<ZIP> <ABSOLUTE_PATH_TO_ROM>`. Done means all routes pass with zero fallback and the scan finds no ROM bytes. BUDGET: Stop after 3 hours. IF BLOCKED: Stop. Say which check fails and paste its output. 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 a person has not yet played through. 5) New parking-lot items.
Done whenA fresh clone passes every route with zero fallback, the scan finds no ROM bytes, and you played it to the end.Proof this works: SonicBlastGGRecomp (pre-built Windows x64 zip, ROM never shipped), MMPR: The Movie, Game Gear to PC (two full playthroughs to the ending), Devilish PSP (generated output kept out of git)
- Cover every level and both endings with routes. Keep the suite in
Path B: Full decomp for porting
You first make a disassembly that rebuilds the ROM byte for byte. You label it, split out the art and levels, and sort code from data. Then you rewrite routines in C and prove each one against a reference interpreter. Last, you put the hardware behind an interface and build for a new system. The first half is proven on this system. The C half is not.
Method: byte-matching disassembly, then C checked by differential tests
Pick this after Path A works, or when you want an editable game you can port. Plan for months. Say yes only if you accept that no one has finished a Game Gear C rewrite yet.
Check prior work and pick the route
A disassembly may already exist for your game or its Master System twin. Starting from one saves weeks. You also decide how far to go. A byte-matching disassembly is a real, proven goal. A full C rewrite is not proven here yet.
- Search GitHub for
<GAME> disassemblyand<GAME> disasm. Check smspower.org and Sonic Retro. - Check for a Master System version of the game. Sonic Chaos, Sonic 2 and Sonic 1 have Master System disassemblies.
- Hash your ROM as in Path A step 1. A Japanese and a US ROM are different targets.
- Write in
SCOPE.mdwhich milestone you aim for: matching disassembly, labelled and split, or C rewrite. - Write down plainly that the C step has no Game Gear example to copy.
Prompt for ClaudeGOAL: Decide the Path B route for <GAME> (<REGION>, SHA-1 <SHA1>) and update SCOPE.md. READ FIRST: SCOPE.md, `notes/prior-work.md`, https://github.com/tbarnavon/KishinDoujiZenkiDecomp (README), https://github.com/TheRavenfreak/Sonic-1-Game-Gear-Disassembly (README) FENCE: Edit only `SCOPE.md` and `notes/prior-work.md`. No code. Do not download any ROM or any repo that contains one. CHECK: Done means SCOPE.md names the target milestone, the assembler (WLA DX or sdasz80), any existing disassembly with its link and licence, and the risks. BUDGET: 45 minutes. IF BLOCKED: Stop. Say what you could not check. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: links and hashes. 3) Files changed. 4) Risks you see. 5) New parking-lot items.
Done whenSCOPE.mdnames the milestone, the assembler and any prior disassembly, and you approved it.Proof this works: KishinDoujiZenkiDecomp (C rewrite tried and abandoned), Sonic Chaos (Master System version) disassembly, Sonic-1-Game-Gear-Disassembly (README: started in 2017)
- Search GitHub for
Set up the assembler and the byte check
You pick one assembler and pin its version. You write one build script and one verify script. The verify script compares your built ROM with your original, byte for byte. The original stays outside the repo and is read-only.
- Download
wla_dx_v10.7_Win64.zipfrom the WLA DX releases page and unzip it intotools/wla/. Or pin SDCC, as Zenki pinned 4.1.0. - Write
build.batortools/build.py. It runswla-z80 -v -o game.o game.asmand thenwlalink -d -v -S game.link build/game.gg. - Write
tools/verify.py. It prints MATCH or the first differing offset and bank. - Keep the original in a folder outside the repo, such as
<ABSOLUTE_PATH_TO_ORIGINAL_DIR>. Add*.gg,*.smsandbuild/to.gitignore. - Add a
PreToolUsehook that blocks edits totools/verify.pyand to the expected hash file.
Prompt for ClaudeGOAL: Set up a pinned assembler, a build script and a byte-check script for <GAME>. READ FIRST: SCOPE.md, https://wla-dx.readthedocs.io/en/latest/, the build scripts of https://github.com/Strugglemeat/supercolumnsgg-disasm (assemble.sh) FENCE: Edit only `build.bat`, `tools/`, `.gitignore`, `.claude/settings.json` and `CLAUDE.md`. Do not write game source yet. CHECK: Run `python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg` on a test file. Done means it prints MATCH for an identical file and the first differing offset for a changed copy. BUDGET: Stop after 90 minutes. IF BLOCKED: Stop. Paste the error. Do not install a different assembler without asking. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both verify outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whentools/verify.pyprints MATCH on an identical file and an offset on a changed one, and the hook blocks edits to it.Proof this works: supercolumnsgg-disasm (SHA-1 check in assemble.sh), KishinDoujiZenkiDecomp (tools/build.py and tools/verify.py), https://github.com/vhelin/wla-dx
- Download
First light: a disassembly that rebuilds the ROM
You turn the whole ROM into assembly that rebuilds byte for byte. At first, most of it is raw data. That is fine. The point is a source tree that passes the byte check from day one.
- Export a first listing from Emulicious, as Super Columns did. Or write a bank-aware tracer in Python, as Zenki and MMPR did.
- Set the WLA DX memory map with
.MEMORYMAPand.ROMBANKMAP. Put each 16 KB bank under its own.BANKand.ORG. - Keep unknown spans as
.INCBINfiles named by address. - Build and run
python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg. - Commit only when it prints MATCH. Never commit the ROM or any
.bincut from it.
Prompt for ClaudeGOAL: Produce a WLA DX source tree that rebuilds <GAME> byte for byte. READ FIRST: SCOPE.md, `<LISTING_PATH>` (the Emulicious export or tracer output), https://wla-dx.readthedocs.io/en/latest/asmdiv.html FENCE: Edit only `src/`, `game.link` and scripts under `tools/disasm/`. Do not edit `tools/verify.py`. Keep ROM-derived `.bin` files in the ignored `extracted/` folder. CHECK: Run `build.bat` then `python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg`. Done means it prints MATCH. BUDGET: Stop after 3 hours or 5 builds that do not move the first differing offset. IF BLOCKED: Stop. Paste the first differing offset, its bank, and both byte runs. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the verify output. 3) Files changed. 4) How much is code and how much is still raw data. 5) New parking-lot items.
Done whentools/verify.pyprints MATCH on a build from a clean checkout.Proof this works: supercolumnsgg-disasm (Emulicious export rebuilt by WLA DX), MMPR: The Movie, Game Gear to PC (all 32 banks reassemble byte-identical), KishinDoujiZenkiDecomp (both ROMs rebuild byte for byte)
Sort code from data and label it
Now you turn raw bytes into named routines and named data. You trace code while tracking which bank is live. You mark every claim as confirmed or supposed. One unit is one routine or one table.
- Run a tracer that follows jumps and calls and tracks bank writes to
$FFFD,$FFFEand$FFFF. Have it list jump tables it finds. - Check the tracer against
z80dasmin WSL. Test your decoder by round-tripping every documented Z80 instruction. - Log the addresses the game really runs, with an Emulicious trace log. Add those to the code list.
- Write
notes/functions.csvwith address, bank, size, name, status (confirmed or supposed) and proof. - Rebuild and verify after every rename. Once the source is stable, add a
FROZENmarker so the generator stops overwriting hand edits.
Prompt for ClaudeGOAL: Label routine <ADDRESS> (bank <BANK>) in <GAME> and mark it confirmed or supposed. READ FIRST: `notes/functions.csv`, `src/<FILE>.asm` around <ADDRESS>, `notes/ram-map.md` FENCE: Edit only labels and comments in `src/<FILE>.asm`, plus `notes/functions.csv` and `notes/ram-map.md`. Do not change any instruction or byte. CHECK: Run `build.bat` then `python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg`. Done means it prints MATCH and the CSV row names its proof: a caller, a trace hit, or a RAM write. BUDGET: Stop after 30 minutes on one routine. IF BLOCKED: Stop. Mark the routine supposed and say what proof is missing. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: verify output and the CSV row. 3) Files changed. 4) New questions. 5) New parking-lot items.
Done whenEvery routine innotes/functions.csvis confirmed or supposed with proof, and the build still prints MATCH.Proof this works: KishinDoujiZenkiDecomp (confirmed vs supposed marks; 73 routines still supposed), Devilish PSP (static survey plus recorded sessions), https://packages.ubuntu.com/noble/z80dasm
- Run a tracer that follows jumps and calls and tracks bank writes to
Split the art, levels and sound into files
A port needs data you can read and change. You extract each data format to an editable file. The build converts them back. The byte check proves nothing changed by accident.
- Write one extractor per format in Python: tiles to PNG, tile maps and levels to CSV, scripts to text.
- Write the matching packer. The build calls it before
wla-z80. - Make the build refuse to overwrite an edited asset unless you pass
FORCE=1. - Watch for fixed slots. If a split section grows past its old size, the ROM breaks. Keep a size check in the build.
- Rebuild and verify after every split.
Prompt for ClaudeGOAL: Split the <FORMAT> data at <ADDRESS_RANGE> of <GAME> into editable files that rebuild byte for byte. READ FIRST: `notes/functions.csv`, `notes/data-formats.md`, the routine that reads this data at <READER_ADDRESS> FENCE: Edit only `tools/assets/`, `assets/<FORMAT>/`, the `.INCBIN` or include lines in `src/`, and `notes/data-formats.md`. Do not change code bytes. CHECK: Run `build.bat` then `python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg`. Done means it prints MATCH and an edited asset changes the ROM only in its own range. BUDGET: Stop after 2 hours or 3 failed round trips. IF BLOCKED: Stop. Describe the bytes you cannot explain. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: verify output. 3) Files changed. 4) What the format is, in two lines. 5) New parking-lot items.
Done whenEvery split format round-trips to MATCH, and the format is written innotes/data-formats.md.Proof this works: KishinDoujiZenkiDecomp (PNG, CSV and script assets, FORCE=1 rule), Sonic-1-Game-Gear-Disassembly (build breaks if a split overflows), Sonic Chaos (Master System version) disassembly (flashes colours when a split grows)
Build the reference and one C routine
Now the unproven part begins. You need an oracle: a Z80 interpreter plus a hardware model that runs the original code. Then you rewrite one small routine in C. A hook calls your C instead of the Z80 code, and the test compares the state after each call.
- Use an interpreter that passes
zexdocandzexall, such assuperzazu/z80. In WSL, runsudo apt install build-essential, thenmake && ./z80_testsin its folder. - Wrap it with a video, sound and mapper model. Or reuse the
smsggrecompruntime from Path A. - Record sessions as inputs plus a hash of RAM, VRAM and palette RAM for each frame.
- Pick a leaf routine: one that calls nothing. Write it in C. Hook its address so the interpreter calls your C.
- Replay the sessions with the hook on. Every frame hash must still match.
Prompt for ClaudeGOAL: Rewrite leaf routine <ADDRESS> of <GAME> in C and prove it with the session hashes. READ FIRST: `notes/functions.csv`, `src/<FILE>.asm` at <ADDRESS>, `tests/sessions/`, https://github.com/superzazu/z80 (README) FENCE: Edit only `c/<NAME>.c`, `c/hooks.c` and `notes/c-progress.md`. Do not edit the interpreter core, the sessions or their hashes. CHECK: Run `python tools/replay.py --all --hook <ADDRESS>`. Done means every session matches every frame with the hook on, and the hook was called at least once. BUDGET: Stop after 5 failed tries. IF BLOCKED: Stop. Report the first differing frame and the RAM bytes that differ. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: replay output and hook call count. 3) Files changed. 4) What the routine does. 5) New parking-lot items.
Done whenAll sessions match every frame with the C routine hooked in, and the hook count is above zero.Proof this works: MMPR: The Movie, Game Gear to PC (interpreter passes zexdoc and zexall, used as oracle), Devilish PSP (reference interpreter, per-frame picture and audio CRCs), https://github.com/superzazu/z80
- Use an interpreter that passes
Grind: every routine as C, leaves first
You repeat the last step for every routine. Leaves go first, then their callers. Each worker takes one routine and proves it with the same replay. Some code will fight you: jump tables, pushed returns and code copied into RAM.
- Sort
notes/functions.csvso routines with no unconverted callees come first. - Give each worker one routine, its own git worktree and the replay check.
- Treat code copied into RAM as its own unit. Capture it from an interpreter RAM image, as Devilish did with its sound driver.
- Write odd control flow plainly in C. Name each case in
notes/c-progress.md. - Merge one batch at a time. Rerun every session after each merge.
Prompt for ClaudeGOAL: Convert the next <N> ready routines of <GAME> to C, one worker each. READ FIRST: `notes/functions.csv` (rows with status ready), `notes/c-progress.md`, one finished C routine as an example FENCE: Each worker edits only `c/<NAME>.c` and its hook line in its own worktree. The lead edits `notes/` only. Nobody edits sessions, hashes or the interpreter. CHECK: After each merge, run `python tools/replay.py --all`. Done means every session matches every frame, and each merged routine's hook was called. BUDGET: Each worker stops after 5 failed tries. The lead stops after <N> routines or 3 hours. IF BLOCKED: Stop that unit. Mark it hard in the CSV with the first differing frame. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: replay summary after the last merge. 3) Files changed. 4) Routines left, from the CSV. 5) New parking-lot items.
Done whenEvery routine innotes/functions.csvis C, every session matches, and no Z80 code runs except the boot stub.Proof this works: MMPR: The Movie, Game Gear to PC (push-and-jump dispatch and RAM-built OUTI code handled), Devilish PSP (sound driver captured from a RAM image), KishinDoujiZenkiDecomp (a C rewrite was tried and abandoned, so expect this to be slow)
- Sort
Port: build it for another system
You put the video, sound and input behind one small interface. Then you write a back end for the new system. The same sessions must match on the new build. Devilish did this with recompiled C on a PSP.
- Put every port write and read behind
hw_functions in one header. The game code calls only those. - Write a PC back end with SDL2 first. Check it against the sessions.
- For a PSP target, install
pspdevin WSL by its Windows guide, including itsapt-getlist. Build withpsp-cmakeandmake. - Build in WSL on the Linux disk, not under
/mnt/c. It is much faster. - Run the same sessions on each target. Compare per-frame picture and audio CRCs.
Prompt for ClaudeGOAL: Build <GAME> from C for <TARGET> and match the reference sessions there. READ FIRST: `notes/c-progress.md`, `c/hw.h`, https://pspdev.github.io/installation/windows.html (if the target is PSP), the README of https://github.com/slimhagrid/Devilish-PSP FENCE: Edit only `port/<TARGET>/` and `c/hw.h`. Do not change game routines in `c/`. Do not change sessions or hashes. CHECK: Run the sessions on the <TARGET> build, or its emulator, and compare frame CRCs. Done means every session matches. BUDGET: Stop after 4 hours or 3 failed builds with the same error. IF BLOCKED: Stop. Paste the error or the first differing frame. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: CRC comparison per session. 3) Files changed. 4) What was not tested on real hardware. 5) New parking-lot items.
Done whenEvery session matches on the new system, and the build ships no ROM data.Proof this works: Devilish PSP (same CRCs on the interpreter, a PC build and PPSSPP), KishinDoujiZenkiDecomp (one source builds a Game Gear and a Master System ROM), Tails Adventure Remake (one C++ code base for PC and Android)
- Put every port write and read behind
Tools you need
| Tool | What it does | How to get it | How we know |
|---|---|---|---|
| smsggrecomp (`SmsRecomp.exe`) Required both | A shared framework that turns Master System and Game Gear Z80 code into C. It comes with a runtime for video, sound, ports and mapper, plus an interpreter fallback. Path A Path B | Add it to your game repo with `git submodule add https://github.com/mstan/smsggrecomp` and `git submodule update --init --recursive`. A standalone `SmsRecomp.exe` is on release v0.0.4. | README, CLAUDE.md, PRINCIPLES.md, COVERAGE.md, DEBUG.md, ACCURACY.md, releases, tools/build_game.ps1, tools/run_coverage_suite.py and runner/main.c read 2026-11-13. Used by SonicBlastGGRecomp and the Sonic 1 Master System recomp. Licence not yet declared. The runner has no --port flag yet, so DEBUG.md's TCP commands are a plan, not a feature. |
| MSYS2 (GCC, CMake, Ninja, SDL2) Required Windows | A Windows shell and package manager. It gives you GCC, CMake, Ninja and SDL2 for building the recompiled game. Path A Path B | Run `msys2-x86_64-20260927.exe` from msys2.org. In the MINGW64 shell: `pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2` | msys2.org read 2026-11-13. All four package pages answer on packages.msys2.org. Package names also match the MMPR and Tails Adventure build steps. SonicBlastGGRecomp's build.ps1 defaults to C:\msys64\mingw64. msys2.org's own example uses the UCRT64 shell, but this build needs the MINGW64 packages. |
| Mesen (Community Edition) Helpful both | An accurate multi-system emulator with a debugger and Lua scripts. It can run a Lua script headless as a test, which makes it a second reference. Path A Path B | Download `Mesen_2.2.1_Windows.zip` from the MesenCE releases page and unzip it. Headless test: `Mesen.exe --testRunner <SCRIPT>.lua <ROM> --doNotSaveSettings`. The script ends the run with `emu.stop(<CODE>)`. | README (lists SMS/Game Gear), release 2.2.1 (2026-06-05) and source of CommandLineHelper.cs and LuaApi.cpp read 2026-11-13. The original Mesen2 repo is archived and points here. The help text says emu.exit, but the Lua API registers emu.stop, and smsggrecomp's Mesen scripts call emu.stop(0). smsggrecomp compared its VRAM and palette with Mesen 2.1.1. |
| Emulicious Helpful Windows | A Game Gear and Master System emulator with a strong debugger. Its disassembler splits code from data as the game runs. It also has a tracer and a memory tracer. Path A Path B | Download the build with 64-bit Java for Windows from emulicious.net/downloads. Unzip it fully, then run `Emulicious.exe`. | Home and downloads pages read 2026-11-13. Used by supercolumnsgg-disasm (source of the disassembly) and KishinDoujiZenkiDecomp. It has no headless mode and allows one copy at a time (Zenki card). |
| WLA DX (`wla-z80`, `wlalink`) Required both | A cross assembler and linker for Z80 and many other chips. It has directives for Master System and Game Gear headers and checksums. Path B | Download `wla_dx_v10.7_Win64.zip` from the GitHub releases and unzip it. The same release also carries `vc_redist.x64.exe`, the Microsoft Visual C++ runtime. Or build from source: `mkdir build && cd build`, `cmake ..`, then `cmake --build . --config Release`. | README and release v10.7 (2026-06-28) read 2026-11-13; directive list read on wla-dx.readthedocs.io. Used by Sonic-1-Game-Gear-Disassembly, supercolumnsgg-disasm and both Master System disassemblies. |
| Ghidra Helpful both | A free reverse-engineering tool with a Z80 language and a decompiler. Use it to read routines and check function starts. Path A Path B | Install JDK 25 64-bit. Download `ghidra_12.2_PUBLIC_20261016.zip`, unzip it, and run `ghidraRun.bat`. | README and release 12.2 read 2026-11-13. Z80 language files confirmed in Ghidra/Processors/Z80. No reviewed Game Gear project names Ghidra; this is our suggestion. |
| Ghidra-SegaMasterSystem-Loader Helpful both | A Ghidra loader that spots Master System and Game Gear ROMs by their header and sets the CPU to Z80. It does not map banks. Path A Path B | Set `GHIDRA_INSTALL_DIR` and run `gradle` in the repo. Copy the zip from `dist/` to `<GHIDRA_DIR>/Extensions/Ghidra`. Then use File, Install Extensions in Ghidra. | README read 2026-11-13. Last pushed in 2019. Whether it loads in Ghidra 12.2 was not checked. |
| z80dasm Helpful WSL/Linux | A small Z80 disassembler for the command line. Use it as a second opinion on your tracer. Path B | In WSL: `sudo apt install z80dasm` | Ubuntu 24.04 package page read 2026-11-13 (version 1.1.6, universe). KishinDoujiZenkiDecomp used 1.1.6 through WSL. |
| SDCC (`sdasz80`, `sdldz80`) Helpful both | A small C compiler suite with a Z80 assembler and linker. Zenki rebuilt its ROMs with them. Its C compiler can build the Game Gear side of a Path B port. Path B | Download the Windows amd64 installer from the SDCC SourceForge page. Pin the version you need; Zenki pinned 4.1.0. | Site read 2026-11-13 (4.6.0, 2026-06-22). The site names the suite sdas and sdld. The 4.6.0 source tag still builds sdasz80 and sdldz80 (sdas/asz80/Makefile.in, sdas/linksrc/Makefile.in). Zenki used them at 4.1.0. |
| superzazu z80 Helpful both | A small Z80 interpreter in C99 that passes the zexdoc and zexall instruction tests. It is a good core for your reference interpreter.Path B | In WSL: `sudo apt install build-essential`, `git clone https://github.com/superzazu/z80`, `cd z80`, then `make && ./z80_tests`. On Windows, `smsggrecomp` already compiles the same `z80.c` with MSYS2 GCC. | README read 2026-11-13. MIT licence. smsggrecomp vendors it as its fallback and its oracle. |
| pspdev Helpful WSL/Linux | The open PSP toolchain: psp-gcc, psp-cmake and packaging tools. Use it if your port target is the PSP.Path B | In WSL, first: `sudo apt-get update` and `sudo apt-get install build-essential cmake pkgconf libreadline8 libusb-0.1 libgpgme11 libarchive-tools fakeroot wget`. Then, in your home folder: `wget https://github.com/pspdev/pspdev/releases/latest/download/pspdev-ubuntu-latest-x86_64.tar.gz`, `tar -xvf pspdev-ubuntu-*.tar.gz`, then add `export PSPDEV="$HOME/pspdev"` and `export PATH="$PATH:$PSPDEV/bin"` to `~/.bashrc`. | Windows install guide (WSL steps, apt-get list, PSPDEV lines) and release v20261101 (2026-11-01) read 2026-11-13. Used by Devilish PSP. |
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 the proof is an empty dispatch_misses.log, a suite report, or a MATCH line from verify.py.
npx skills add obra/superpowers --skill verification-before-completion -a claude-code
systematic-debugging
No fix until the cause is found. That matches the first-divergence rule in smsggrecomp's PRINCIPLES.md.
npx skills add obra/superpowers --skill systematic-debugging -a claude-code
handoff
Writes a short note so a fresh session can carry on. Tell it to save in notes/handoff.md inside your project, not in a temp folder.
npx skills add mattpocock/skills --skill handoff -a claude-code
using-git-worktrees
Gives each Path B worker its own copy of the repo. Watch its setup step the first time, since it may run installs.
npx skills add obra/superpowers --skill using-git-worktrees -a claude-code
ghidra-headless
Runs Ghidra with no window and saves functions and code to files. Ghidra has a Z80 language. Load each bank yourself, since a raw ROM needs a loader. On Windows, set GHIDRA_HOME.
npx skills add trailofbits/skills-curated --skill ghidra-headless -a claude-code
static-recomp-scope-plan
Makes you write down what a correct port means before work starts: the exact ROM, the scenes to test and the numbers to hit. It is text only.
npx skills add bgyss/switchrecomp --skill static-recomp-scope-plan -a claude-code
gg-miss-harvest (write your own)
This is the loop smsggrecomp calls mandatory in PRINCIPLES 13a. A skill makes every session follow it the same way.
A `.claude/skills/gg-miss-harvest/SKILL.md` that: 1) runs the coverage suite; 2) collects new lines from `dispatch_misses.log`; 3) for each address, reads the listing in the bank that was live; 4) adds proven starts to `game.toml` with their proof; 5) regenerates and reruns. Rule: never add an address only because the log names it.
gg-first-divergence (write your own)
PRINCIPLES 3 and 22 ask for the first divergence, and COVERAGE.md gives the route tools. A skill keeps the steps and the proof rule fixed.
A `.claude/skills/gg-first-divergence/SKILL.md` that: 1) closes old copies with `taskkill`; 2) reads `report.json` for the first capture that differs; 3) copies the route to `tests/probe/` and adds earlier `capture` lines; 4) runs it native and with `--interp`, halving the gap to the first differing frame; 5) names the writing code from the listing; 6) writes frame, cause and fix to `notes/divergence-log.md`. Rule: no code change until the first differing byte and its writer are named.
Always-on debug server (write your own runtime tool)
Claude can ask the running game what just happened without pausing it. No reviewed Game Gear project used an MCP server. smsggrecomp's DEBUG.md plans this design, but its runner does not have the server yet, so you build it.
For Path B, add a TCP command server to your reference interpreter like the one in `smsggrecomp`'s DEBUG.md. Keep always-on rings for bus writes, port writes and frames. Document the commands in `notes/debug.md`.
Claude setup for this system
Cut Game Gear work by address, by bank and by route. On Path A, one unit is one dispatch miss, one divergent frame, or one runtime bug, each tied to a route. On Path B, one unit is one routine to label, one data format to split, or one routine to rewrite in C. Every unit has one check: an empty miss log, a suite report, a MATCH line, or a session replay. Always name the bank with the address.
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 ROM by CRC32 and SHA-1. Find any disassembly, including the Master System version. Decide how far Path B can honestly go. 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 | Install MSYS2 packages, add smsggrecomp as a submodule, write tools/check.ps1. On Path B, pin WLA DX or SDCC and write verify.py and its hooks. | Opus 5.5 effort medium | Sonnet 5.5 effort medium |
| Study the game file | Trace code with bank tracking. Find jump tables, pushed returns and code copied into RAM. Fill game.toml seeds and notes/functions.csv with proof. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for function edges and data layouts. A mistake there spreads. |
| Bulk units | Misses with clear proof, routine labels, data splits and leaf routines in C. One small unit per worker, each with its 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 | Bank-switched dispatch, raster effects tied to line interrupts, nested interrupts, and routines that failed five tries in bulk. | 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 | The VDP in Game Gear mode, the 12-bit palette, PSG stereo on port $06, the mapper and frame timing. On Path B, the port back end. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for timing and graphics bugs. |
| Find a bug | Find the first frame where native code and the interpreter differ, then the first wrong write. 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 suite or the byte check. It hunts for stubs, edited captures, loosened hashes, edits to generated C and fallback counted as done. | 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/divergence-log.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 sessions at once, each on its own miss or route in its own worktree. Runtime files are shared, so one writer per file. Path B: 3 to 6 workers plus one lead, each in its own worktree. Labelling and data splits suit bulk workers well. Merge one batch at a time and rerun the byte check.
Max 5x (now called Max)
Path A: 1 session, sometimes 2. Path B: 2 workers plus the lead. Send hard units to one session at a time. Do the docs updates once at the end of the day.
Lines for this project's CLAUDE.md
- Read `SCOPE.md`, `PROGRESS.md` and `notes/divergence-log.md` at the start of every session. - Never edit generated C under `generated/`. Fix the recompiler, the runtime or `game.toml`, then regenerate. - No stubs. If execution reaches unknown code, stop and find the real routine. Never fake its effect. - Function starts come from the ROM listing, never from `dispatch_misses.log` alone. Name the bank with every address. - After every run, `dispatch_misses.log` must be empty. Interpreter fallback is not a finished recompilation. - Debug the first divergent frame, never the last visible symptom. - The Game Gear is the Master System plus a `platform` flag. Never fork the engine for Game Gear work. - The one check is `powershell -File tools/check.ps1 '<ABSOLUTE_PATH_TO_ROM>'` (Path A) or `python tools/verify.py <ABSOLUTE_PATH_TO_ROM> build/game.gg` (Path B). No pasted output means not done. - Do not edit `tests/coverage/`, expected hashes, `tools/verify.py` or check scripts. A change needs my approval. - The ROM lives at `<ABSOLUTE_PATH_TO_ROM>`. Never copy, commit or paste it or bytes cut from it. - Close old copies with `taskkill /F /IM <EXE>` before each run (in Git Bash: `taskkill //F //IM <EXE>`). Run one copy at a time. - In a worktree, use absolute paths for the ROM and tools. - Never commit without my say-so. A fix is done only after I confirm it in the game. - 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 a few lines.
- Pass an address and its bank. Let Claude read only that routine in the listing.
- Give Claude the first divergent frame and the two capture files that differ, not whole logs.
- Do not paste a 390 KB disassembly. Split it into one file per bank first.
- Add
Readdeny rules forgenerated/**,build/**andcoverage-*/**. - 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, to choose Path A, Path B or both for one game.
GOAL: Tell me if <GAME> (<REGION>, CRC32 <CRC32>) suits Path A, Path B, or both, and draft SCOPE.md. READ FIRST: bytes $7FF0-$7FFF of `<ABSOLUTE_PATH_TO_ROM>`, https://github.com/mstan/smsggrecomp/blob/main/CLAUDE.md, https://www.smspower.org/Development/ROMHeader FENCE: Create only `SCOPE.md` and `notes/prior-work.md`. No code. Do not copy the ROM. CHECK: Done means SCOPE.md lists ROM size, header text, region digit, CRC32, SHA-1, mapper guess, prior work with links, the chosen path, the first milestone with its check, and an out-of-scope list. BUDGET: 45 minutes. IF BLOCKED: Stop. Say what you could not check. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: header output and hashes. 3) Files changed. 4) Risks you see. 5) New parking-lot items.
A good answer: A one-page SCOPE.md with the hashes, the region and links to any prior work. It says plainly that a C rewrite has no Game Gear example yet.
Map the ROM
After setup, before first light, or when many misses point to one bank.
GOAL: Map bank <BANK> of <GAME> into routines and data, with proof for each start. READ FIRST: `notes/functions.csv`, the Emulicious or Ghidra listing for bank <BANK>, an Emulicious trace log at `<TRACE_PATH>` FENCE: Edit only `notes/functions.csv` and `notes/banks.md`. Do not edit `game.toml` yet. Do not edit code. CHECK: Done means every byte range in bank <BANK> is code, data or unknown, every routine start names its proof, and the totals add up to 16,384 bytes. BUDGET: 2 hours. IF BLOCKED: Stop. List the ranges you could not sort and why. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: counts by type and the byte total. 3) Files changed. 4) Jump tables found. 5) New parking-lot items.
A good answer: A bank map whose ranges add up to 16,384 bytes. Every routine has a caller, a table entry or a trace hit as proof.
Unit loop, Path A: one miss or one divergence
The daily Path A unit. Use it once per address or per route.
GOAL: Remove dispatch miss <ADDRESS> (bank <BANK>) or the first divergence in route <RUN> for <GAME>. READ FIRST: `dispatch_misses.log`, the suite report for <RUN>, the listing at <ADDRESS>, `notes/divergence-log.md` FENCE: Edit only `game.toml`, `notes/functions.csv`, `notes/divergence-log.md` and runtime files named in CLAUDE.md. Never edit `generated/` or `tests/coverage/`. CHECK: Rebuild and run the coverage suite. Done means the miss is gone or the divergence moved later, and no other route got worse. BUDGET: Stop after 3 failed tries or 45 minutes. IF BLOCKED: Stop. Paste the evidence and your two best causes. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: suite summary before and after. 3) Files changed. 4) What is left. 5) New parking-lot items.
A good answer: One small change to game.toml or the runtime, a suite summary that improved, and one new line in the log.
Unit loop, Path B: one routine as C
The daily Path B unit, after the reference and the hook work.
GOAL: Rewrite routine <ADDRESS> (bank <BANK>) of <GAME> in C and prove it. READ FIRST: `src/<FILE>.asm` at <ADDRESS>, `notes/functions.csv`, one finished routine in `c/` as an example FENCE: Edit only `c/<NAME>.c`, its hook line and its CSV row. Do not edit sessions, hashes, the interpreter or other routines. CHECK: Run `python tools/replay.py --all --hook <ADDRESS>`. Done means every session matches every frame and the hook ran at least once. BUDGET: Stop after 5 failed tries. IF BLOCKED: Stop. Mark the row hard and report the first differing frame and bytes. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: replay output and hook count. 3) Files changed. 4) What the routine does. 5) New parking-lot items.
A good answer: Plain C with real names, a replay that matches every frame, and a hook count above zero.
Batch dispatch
In a lead session, to hand out the next set of units to workers.
GOAL: Pick the next <N> units for <GAME> and start one worker per unit. READ FIRST: `PROGRESS.md`, `notes/functions.csv` or `dispatch_misses.log`, `notes/parking-lot.md` FENCE: The lead edits only `notes/`. Each worker gets one task card, its own git worktree, and absolute paths to the ROM and tools. No two workers touch the same file. CHECK: After each merge, run the one check from CLAUDE.md. Done means every merged unit passes it on the merged branch, not only in its worktree. BUDGET: Stop after <N> units or 3 hours. IF BLOCKED: Stop that worker. Mark the unit hard with its evidence. OTHER PROBLEMS: Workers write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: check output after the last merge. 3) Units done and units marked hard. 4) What to send next. 5) New parking-lot items.
A good answer: A short table of units with DONE or hard, and one check output from the merged branch.
Debug with evidence
When a crash, a wrong colour or a sound bug appears and its cause is not clear.
GOAL: Find the cause of <SYMPTOM> in <GAME> at about frame <FRAME>. Do not fix it yet. READ FIRST: `notes/divergence-log.md`, https://github.com/mstan/smsggrecomp/blob/main/COVERAGE.md (route controls), the route that shows the bug FENCE: Read only, except new probe routes in `tests/probe/`. No game or runtime fixes. CHECK: Run the probe route native and with `--interp`, then compare the capture files. Done means you name the first frame where native and interpreter differ, the first differing byte, the code that wrote it and the bank that was live. BUDGET: 90 minutes. IF BLOCKED: Stop. Say which data you need that no capture records. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the two capture files that differ and the writer. 3) Files changed. 4) The cause in one sentence and a proposed fix. 5) New parking-lot items.
A good answer: One frame number, one address, one writer, and one sentence of cause. No words like maybe or likely.
Verify and hunt for cheating
In a fresh session, after any batch or any claim of done.
GOAL: Check that the work in <BRANCH_OR_COMMITS> for <GAME> is real. READ FIRST: `git diff <BASE>..<BRANCH_OR_COMMITS>`, CLAUDE.md, the last report FENCE: Read only. Do not fix anything. CHECK: Rerun the one check from CLAUDE.md from a clean build. Then look for: edits in `generated/`, stubs or fake events, changed captures or hashes, edits to `verify.py` or check scripts, routes deleted or shortened, fallback counted as done, and files outside the fence. BUDGET: 60 minutes. IF BLOCKED: Stop. Say what you could not rerun. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) PASS or FAIL. 2) Proof: the check output. 3) Each problem with file and line. 4) Claims you could not confirm. 5) New parking-lot items.
A good answer: A fresh check output and a list of problems with file and line, or a plain PASS.
Status report
At the end of a day or a week.
GOAL: Report the state of <GAME> with numbers only. READ FIRST: `PROGRESS.md`, `notes/functions.csv`, the latest suite report or verify output FENCE: Edit only `PROGRESS.md`. CHECK: Done means each number comes from a file or a command you ran now. BUDGET: 15 minutes. IF BLOCKED: Stop. Say which number you could not get. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Routes passing, misses left, fallback cycles, routines confirmed, supposed and in C. 3) Files changed. 4) Top three blockers. 5) New parking-lot items.
A good answer: Six or seven numbers, each with its source, and three blockers. No padding.
Session handoff
Before you stop, or when the chat grows long.
GOAL: Write what the next session needs to carry on with <GAME>. READ FIRST: `PROGRESS.md`, `notes/divergence-log.md`, `notes/findings.md`, this session's work FENCE: Edit only `PROGRESS.md`, `notes/findings.md` and `notes/handoff.md`. CHECK: Done means a fresh session could start from `notes/handoff.md` alone: the current unit, its last check output, dead ends tried, and the next command to run. BUDGET: 15 minutes. IF BLOCKED: Stop. Say what you could not record. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the handoff text. 3) Files changed. 4) The next unit. 5) New parking-lot items.
A good answer: A short notes/handoff.md with the next command, the last result and the dead ends.
Blocked or cannot deliver
When a unit keeps failing, or Claude keeps hinting it is impossible.
GOAL: Tell me plainly whether <UNIT> for <GAME> can be done, and what it would take. READ FIRST: the unit's notes, the last three reports, `notes/findings.md` FENCE: Read only. CHECK: Done means you give one answer: can do, can do with <CHANGE>, or cannot do. Each answer needs proof from a listing, a log or a check output. BUDGET: 30 minutes. IF BLOCKED: Say what data would settle it. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof. 3) Files changed: none. 4) Options with their cost in hours. 5) New parking-lot items.
A good answer: One clear answer with proof, and two or three options with rough costs.
Scope change request
When Claude wants to go outside the fence, for example to change the shared framework.
GOAL: Ask me to approve a change outside the fence for <GAME>. Do not make it. READ FIRST: SCOPE.md, CLAUDE.md, the evidence that the change is needed FENCE: Read only. No edits until I say yes. CHECK: Done means you state the change, the files it touches, why the current fence cannot solve the unit, and how we will check it. BUDGET: 15 minutes. IF BLOCKED: Say what you still need to know. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof of need. 3) Files that would change. 4) Risk to other games or routes. 5) New parking-lot items.
A good answer: A short request with proof and risk. The work waits until you say yes.
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 to make a crash go away. The next regeneration wipes the fix and hides the real bug. | Never edit generated C. Fix the recompiler, the runtime or game.toml, then regenerate. Add a PreToolUse hook that blocks writes to generated/. |
Claude copies every address from dispatch_misses.log into game.toml. Some are middles of routines, and they decode into nonsense. | Every new start needs proof from the ROM listing in the live bank. The log only says that code exists, not where it begins. |
| Claude calls the game done while the interpreter still runs missed code. | Done means zero fallback on every route. Paste the suite's fallback count with every report. |
| Claude writes a stub or pokes RAM to skip a screen it cannot reach. | No stubs and no fake events. Stop, find the real routine and fix discovery. Route writes are for test setup only, never for game fixes. |
| Claude builds a separate Game Gear branch of the engine for one odd behaviour. | The Game Gear is the Master System plus a flag. A Game Gear change must map to screen crop, palette, stereo or system ports. |
| Claude arms a trace, runs the game, and then reads the trace. The event already passed, so it says nothing happened. | Record first, then read what was recorded. Use route capture lines, --dump-frame and --vdp-trace, which save state as the game runs. If data is missing, add an always-on record first (PRINCIPLES 17). |
| On Path B, Claude edits the expected hash or the verify script when a build stops matching. | tools/verify.py and the hash are read-only. Block them with a hook. A failed match is a failed unit. |
| Claude hand-edits files that the disassembly generator will overwrite. | Edit generated .s or .asm only after the source is frozen with a FROZEN marker. Before that, change the generator. |
Problems other projects hit
Static tracing misses code reached through jp (hl), pushed addresses or pointers in object RAM.
Fix: Add seeds and jump tables from the listing. Record interpreter sessions to find more targets. Then prove each start in the ROM.
Seen in: SonicBlastGGRecomp, MMPR: The Movie, Game Gear to PC, Devilish PSP
A routine compiled for one bank got calls meant for another live bank.
Fix: Dispatch by the mapper's real bank, even when only one version of the routine is known.
Seen in: SonicBlastGGRecomp (smsggrecomp COVERAGE.md)
Some code is copied into RAM or built at run time, such as a sound driver or an unrolled OUTI loop.
Fix: Capture the code from an interpreter RAM image. Translate it as its own module or native routine.
Seen in: Devilish PSP, MMPR: The Movie, Game Gear to PC
A split data section grew past its old size and the ROM broke or flashed colours.
Fix: Add a size check to the build. Move data only when the code that reads it knows the new place.
Seen in: Sonic-1-Game-Gear-Disassembly, Sonic Chaos (Master System version) disassembly
A newer SDCC broke the build. From 4.2 the calling convention changed and the precompiled library failed.
Fix: Pin the tool version in the repo and the docs. Zenki pinned SDCC 4.1.0. The sdasz80 assembler also has no .incbin.
Seen in: KishinDoujiZenkiDecomp
Emulicious has no headless mode and runs one copy at a time, so it cannot drive automated tests.
Fix: Use the framework's interpreter, Mesen's --testRunner, or a small headless emulator of your own.
Seen in: KishinDoujiZenkiDecomp
Builds under /mnt/c in WSL were much slower.
Fix: Keep WSL work on the Linux disk, for example under ~/projects.
Seen in: Devilish PSP
A ROM was committed to the public repo next to the source.
Fix: Add *.gg and *.sms to .gitignore before the first commit. Pass the ROM path as an argument.
Seen in: Sonic-1-Game-Gear-Disassembly, Sonic the Hedgehog 2 (Master System version) disassembly
The video interrupt handler turned interrupts back on, so line interrupts fired inside it.
Fix: Model nested interrupts. Count cycles after every instruction so raster effects land on the right line.
Seen in: MMPR: The Movie, Game Gear to PC
A stale background copy of the game can hold a TCP port and feed probes old data. The framework's rules warn about this.
Fix: Run taskkill /F /IM <EXE> (Git Bash: taskkill //F //IM <EXE>) before every launch.
Seen in: SonicBlastGGRecomp (smsggrecomp PRINCIPLES 24)
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 | 1 to 5 weeks | 3 to 14 weeks | 3 to 12 months | medium confidence |
| Path B: full decomp | 8 to 30 weeks | 5 to 17 months | 2 to 6 years | low confidence |
Read this first
These numbers assume one medium game, your first Game Gear project, and one person giving 10 to 15 hours a week. Path A is medium confidence. One framework with dated Claude commits shows a boot in days and full route coverage about four months after its first commit. Its author had already built a Genesis framework, so your first game will be slower. Path B is low confidence. Zenki matched two ROMs in two days, but nobody has finished a C rewrite. The no-AI numbers rest on hand-made disassemblies that took years and are still partial.
What makes it faster or slower
- Whether your game is on
smsggrecompalready, or close to one that is. Sonic games share engines. - Whether a disassembly exists for your game or its Master System version.
- How much code hides behind jump tables, pushed returns and code copied into RAM.
- How many banks the game uses. Each bank adds places where the same address means different code.
- On Path B, how far you go. A matching disassembly took days with Claude. A C rewrite has no finished example.
- Your review time. Each unit 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 |
|---|---|---|
| smsggrecomp | First commit 2026-06-19. v0.0.3 on 2026-10-18 and v0.0.4 on 2026-11-02. 1 contributor. 43 of 56 commits carry a Claude co-author line. | source |
| SonicBlastGGRecomp | First commit and v0.0.1 on 2026-06-23, booting to the title. All 30 act and character routes with zero fallback by 2026-10-18. 1 contributor. 8 of 15 commits carry a Claude co-author line. | source |
| KishinDoujiZenkiDecomp | First commit 2026-11-11 already rebuilds both ROMs byte for byte. 11 commits over two days, all with a Claude co-author line. 73 routines still marked supposed. C rewrite abandoned. | source |
| Sonic the Hedgehog (Master System version) recomp | First commit 2026-06-22. v0.0.1 on 2026-06-23. Same framework and author. 9 of 16 commits carry a Claude co-author line. | source |
| MMPR: The Movie, Game Gear to PC | One commit on 2026-10-27 that claims a complete game. The work history is hidden. No AI use stated. | source |
| Sonic-1-Game-Gear-Disassembly | README says work began 2017-05-13. Repo commits from 2019-01 to 2019-07. Still a partial split. 1 contributor. No AI. | source |
| Sonic the Hedgehog 2 (Master System version) disassembly | Commits dated from 2009-02 and pushed in 2013-12. No release. 2 contributors. No AI. | source |
| Tails Adventure Remake | First commit 2022-09-04. First release 2023-10-30. 3 contributors. A remake written by hand, not a decomp. | source |
Projects reviewed (10)
There are fewer than 10 games on RecompLauncher for the Game Gear: it lists one, Tails Adventure. We found six more Game Gear projects outside it, and no others. The Sonic Retro and Sega Retro lists blocked our reader, so we may have missed one there. To reach ten, we added three Master System projects. The Master System uses the same chip, video and sound, and each is marked as the Master System version.
What each project teaches
Tails Adventure Remake
Tails Adventure
Started: 2022-09. First release: 2023-10. Code: C++.
AI: none stated (the README allows AI code if the contributor reviews and tests it)
Lesson: A full remake in a new engine works, and it reaches Android too. But it is a rewrite, not a decomp, and some original features are still missing.
s2smsdisasm
Sonic the Hedgehog 2 (Master System version)
Started: 2009-02. First release: none. Code: Z80 assembly.
AI: none stated
Lesson: Sister system. A pre-AI community disassembly with the same WLA DX build and byte compare. It also shows the mistake of committing the ROM.
Sonic-1-Game-Gear-Disassembly
Sonic the Hedgehog (Game Gear)
Started: 2019-01. First release: none. Code: Z80 assembly.
AI: none stated
Lesson: Split one piece at a time and compare after every build. By hand this took years and is still partial.
SonicTheHedgehogSMSRecomp
Sonic the Hedgehog (Master System version)
Started: 2026-06. First release: 2026-06. Code: PowerShell and CMake (the C is generated).
AI: yes: 9 of 16 commits carry a Claude co-author line Agent files: CLAUDE.md (in the smsggrecomp submodule).
Lesson: Sister system, reviewed here because few Game Gear projects exist. The same framework serves both, so its 29 routes show what Game Gear coverage can look like.
SonicBlastGGRecomp
Sonic Blast
Started: 2026-06. First release: 2026-06. Code: PowerShell and CMake (the C is generated).
AI: yes: 8 of 15 commits carry a Claude co-author line; the framework has a CLAUDE.md Agent files: CLAUDE.md (in the smsggrecomp submodule), PRINCIPLES.md (in the smsggrecomp submodule).
Lesson: A thin game repo on a shared framework boots in days. Route tests then prove each act with zero fallback, and the README says honestly what is still unverified.
supercolumnsgg-disasm
Super Columns
Started: 2022-11. First release: none. Code: Z80 assembly.
AI: none stated
Lesson: An Emulicious export that WLA DX rebuilds is a fast start. Left as one raw 390 KB file, it is hard to use.
MMPR: The Movie, Game Gear to PC
Mighty Morphin Power Rangers: The Movie
Started: 2026-10. First release: unknown. Code: C and Python.
AI: none stated
Lesson: Build and test an interpreter first, then use it as the oracle. Compare RAM, video RAM and palette with the recompiled build every frame.
Devilish PSP
Devilish
Started: 2026-11. First release: none. Code: C, Python and C++.
AI: none stated
Lesson: Recompiled C can port a Game Gear game to another console. With no fallback, a missed jump stops loudly instead of going quietly wrong.
KishinDoujiZenkiDecomp
Kishin Douji Zenki
Started: 2026-11. First release: none. Code: Z80 assembly and Python.
AI: yes: all 11 commits carry a Claude co-author line; docs/decisions.md records an agent-style workflow
Lesson: With Claude, a byte-matching disassembly with editable assets took about two days. Marking each claim confirmed or supposed keeps guesses visible.
schaosdisasm
Sonic Chaos (Master System version)
Started: 2026-09. First release: none. Code: Z80 assembly.
AI: none stated
Lesson: Sister system. A bit-perfect hash check is easy to add. Its README warns that a split which grows breaks the game.
What we could not check
- Which assembler Sega's teams used for Game Gear games. No source we read says.
- That no retail Game Gear game was written in C. We found none, but did not check every game.
- Whether
Ghidra-SegaMasterSystem-Loader, last pushed in 2019, loads in Ghidra 12.2. - No step in this guide was run for this check. Nothing was built and no ROM was used. Commands were checked against docs and source code only. The hash one-liner was run on a made-up test file.
- Whether a game other than Sonic Blast builds on
smsggrecompwithout framework changes. Only two games use it so far. - The Path B steps for a C rewrite with hooked routines. No Game Gear project has done this. The method comes from Genesis projects.
- How long MMPR and Devilish took before their first public commit. Both hide their history.
- Whether MMPR and Devilish used AI. Neither says.
- The verification numbers of MMPR, Devilish and Zenki. They are the authors' own claims.
- The script names
tools/check.ps1,tools/verify.py,tools/replay.pyandscan_rom_bytes.py. They follow the reviewed projects; you write your own. - The Sonic Retro and Sega Retro disassembly lists. Bot checks blocked them, so we may have missed a project hosted only there.
- The TCP debug server in
smsggrecomp's DEBUG.md (state,frame,rdb_window). Itsrunner/main.cparses no--portflag, though CLAUDE.md still shows--port 4390. The guide does not rely on it. - Whether every capture can match. Sonic Blast still has one ring-icon capture that differs by 33 pixels.
Sources
- smsggrecomp README
- smsggrecomp CLAUDE.md
- smsggrecomp PRINCIPLES.md
- smsggrecomp COVERAGE.md
- smsggrecomp DEBUG.md
- smsggrecomp ACCURACY.md
- smsggrecomp runner command line (runner/main.c)
- smsggrecomp game build script
- smsggrecomp coverage suite runner
- SonicBlastGGRecomp suite.json
- SonicBlastGGRecomp README
- SonicTheHedgehogSMSRecomp README
- KishinDoujiZenkiDecomp
- SMS Power: ROM header
- SMS Power: Mappers
- SMS Power: Game Gear VDP
- SMS Power: Game Gear I/O port map
- SMS Power: Palette
- Wikipedia: Game Gear
- WLA DX repository
- WLA DX directives
- Mesen Community Edition
- Emulicious
- SDCC
- z80dasm in Ubuntu 24.04
- Ghidra
- Ghidra Sega Master System and Game Gear loader
- superzazu z80
- pspdev Windows install guide
- pspdev releases
- SDCC 4.6.0 source: Z80 assembler build file
- Original Mesen2 repo (archived)
- MSYS2
- Sonic Chaos (Master System) disassembly
- Sonic 2 (Master System) disassembly