![Sonic Pocket](docs/images/banner.jpg) # Sonic Pocket A static recompilation of *Sonic the Hedgehog: Pocket Adventure* (Neo Geo Pocket Color) to native C++. The game's TLCS-900/H machine code is translated ahead of time into C++ functions, one per routine, and compiled into a native PC executable. The translated code runs on a small Neo Geo Pocket Color runtime that provides the video chip, sound chips, timers, interrupts, save flash and BIOS. ## Status - **Playable.** `sonic-pocket` runs the recompiled game in an SDL3 window with keyboard and gamepad input, sound and persistent save data. - **Exact.** `spa-verify` runs the recompiled game and an interpreter side by side and checks that registers, cycle counts, RAM and video memory stay identical every frame. Currently 1200 frames (boot, SEGA logo, title) are in exact lockstep. - **Checked against a reference.** With the interpreter, the machine's work RAM matches a BizHawk (Mednafen) capture byte for byte for 1077 of 1198 frames after boot; the remaining differences are understood timing details. - **Nearly all native.** All 2,771 known routines are recompiled. Only the flash-save routine the game copies into RAM and the BIOS entry points run through the interpreter. The generated code is correct but machine-shaped: every instruction calls the CPU core's handler for it. Next steps are lifting it to plain, readable C++ and then rebuilding game systems (player, objects, collision) as structured code, each change checked by the lockstep verifier. See [`docs/recomp-plan.md`](docs/recomp-plan.md). ## How it works ``` cartridge ──► spa-recomp ──► generated C++ (one function per routine) │ ▼ runtime: TLCS-900/H CPU state + interpreter fallback, K2GE video, T6W28 PSG + DACs, Z80 sound CPU, timers/interrupts, flash, high-level BIOS ──► SDL3 frontend ``` - `src/cpu/tlcs900/`: MAME's TLCS-900/H core (BSD-3), adapted to run standalone. Its opcode tables drive both the interpreter and the recompiler. - `src/ngpc/`: the machine: TMP95C061 timers and interrupts, K2GE video, T6W28 sound (from MAME), Z80 (superzazu/z80, MIT), flash and a high-level BIOS matching the Mednafen/BizHawk core. - `src/recomp/`: `spa-recomp`, which decodes the ROM with the interpreter's tables and emits C++ with native control flow. - `src/recomp_rt/`: runtime for the generated code: dispatch, calls and returns, interpreter fallback and the game thread. - `src/apps/`: `sonic-pocket` (the game), `spa-verify` (lockstep check) and `ngpc-run` (headless interpreter runs and RAM dumps). - `config/recomp/functions.txt`: routine entry points, generated by `tools/recomp_seeds.py` from ValleyBell's SPA disassembly. - `docs/notes/`: reverse-engineering notes on the game's systems (scheduler, VBlank, input, player, collision, camera). - `scripts/bizhawk-dump-reference.lua` and `tools/compare_ram_frames.py`: reference captures from BizHawk and comparison against the machine. - `tools/rominfo.py`: checks that a cartridge image is the expected release ([`config/rom.json`](config/rom.json)). ## Building Requirements: Visual Studio 2026 (or another C++20 compiler), CMake 4.2+ and a legally obtained copy of the cartridge. SDL3 is downloaded automatically. ```powershell cmake -S . -B build/recomp -G "Visual Studio 18 2026" -A x64 ` -DSPA_ROM="C:/path/to/Sonic The Hedgehog - Pocket Adventure (World) (En,Ja).ngc" cmake --build build/recomp --config Release --target sonic-pocket -- /m:1 ``` The recompiler runs as part of the build and writes the generated sources to `build/recomp/generated/`. They are large, so the first build takes a while; on low-power machines keep to one compiler process as above. ## Playing ```powershell build\recomp\Release\sonic-pocket.exe "path\to\cartridge.ngc" ``` | Action | Keyboard | Gamepad | |---|---|---| | Move | Arrow keys | D-pad / left stick | | A | Z | South button | | B | X | East button | | Option | Enter | Start | | Quit | Esc | | Options: `--scale N` (window size, default 4), `--japanese`, and `--interpreter` to run the same game on the interpreter instead of the recompiled code. Save data is stored in the SDL preferences folder (`%APPDATA%\SonicPocket\SonicPocket\flash_save.bin` on Windows). ## Verifying ```powershell cmake --build build/recomp --config Release --target spa-verify -- /m:1 build\recomp\Release\spa-verify.exe --rom "path\to\cartridge.ngc" --frames 1200 ``` To compare the machine against BizHawk, capture a reference with `scripts/bizhawk-dump-reference.lua` (see its header), dump the same frames with `ngpc-run --dump-ram`, and run `tools/compare_ram_frames.py`. ## Repository policy This repository contains no ROM data, extracted assets, BIOS or generated code. The recompiled C++ is produced at build time from your own cartridge. Committed files are original code, MIT/BSD-licensed third-party code with its notices, and facts about the ROM such as routine addresses. ## Documentation - [`docs/recomp-plan.md`](docs/recomp-plan.md): architecture, verification and roadmap. - [`docs/notes/`](docs/notes/README.md): how the game works. - [`docs/valleybell-reference.md`](docs/valleybell-reference.md): the SPA disassembly and how this project uses it.