- Config loader (recompiler/src/config_loader.{h,cpp}): single source of
truth for both BIOS and game runtime settings (debug_port, window_title,
memcard_dir, disc path). psxrecomp-bios and psxrecomp-game both accept
--config <toml>; runtime takes --game <toml> (no more CLI overrides).
- runtime/src/main.cpp: replaced --disc/--memcard-dir/--game-root CLI
overrides with --game <toml>; game.toml is the single source of truth.
Discless launch (no args) goes to BIOS shell.
- runtime/src/dma.c: fixed update_master_irq() re-asserting I_STAT bit 3
on every DICR read. BIOS shell DMA handler at 0x80058628 only clears
DICR bit 27 (ch3 flag), so level-sensitive re-assert pinned the kernel
in the exception loop. Bit 3 is now edge-triggered (one assert per DMA
completion). Discless boot now reaches MAIN MENU / MEMORY CARD / CD
PLAYER. With-disc Tomba boots through to Whoopee Camp splash.
- Audit tooling: codegen_audit.py (BIOS), codegen_audit_game.py (game),
audit_config.py (config loader for tools), verify_audit_schema.py.
Replaces older tools/_codegen_audit.py probe.
- Docs: CURRENT_STATE.md (project state), UNIFICATION_PLAN.md (Phase C
translator merge plan), docs/config_schema.md (TOML schema reference),
docs/audit_inventory.md (audit tier inventory).
- .gitignore: tools/_*.py convention for ad-hoc scratch probes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.8 KiB
CURRENT_STATE — read this before doing anything
Last updated: 2026-05-12 (post-confusion-session)
TL;DR
- The working binary is
F:\Projects\TombaRecomp\build\tomba-runtime.exe(built 2026-05-12 11:55). It boots BIOS → Tomba → main menu. - A copy is preserved at
.happypath/tomba-runtime.exeso a future rebuild cannot erase it. psx-runtime.exe(the BIOS-only runtime in this repo) is not the test target. Past handoff references to "main menu reachable" mean Tomba's main menu, not the BIOS shell.- We are about to start the unification work described in
UNIFICATION_PLAN.md. Do not start that work without re-reading both files.
What the project layout actually is
There are two repos and several binaries. Get this straight before doing anything.
F:\Projects\psxrecomp-v4\ ← THIS repo
recompiler\
src\strict_translator.cpp ← BIOS-only path (psxrecomp-bios)
src\full_function_emitter.cpp ← shared between bios + game paths
src\code_generator.cpp ← PS1-EXE / game-only path (psxrecomp-game)
src\function_analysis.cpp ← game-only path
src\main_bios.cpp ← entry point for psxrecomp-bios.exe
src\main_psx.cpp ← entry point for psxrecomp-game.exe / PSXRecomp.exe
runtime\ ← the runtime library + psx-runtime.exe target
generated\ ← BIOS recomp output (SCPH1001_*.c)
bios\SCPH1001.BIN ← the ROM (and SCPH1001.toml audit config)
F:\Projects\TombaRecomp\ ← sibling repo
generated\SCUS_942.36_*.c ← Tomba EXE recomp output (separate from BIOS)
build\tomba-runtime.exe ← THE BINARY THE USER ACTUALLY TESTS
game.toml ← Tomba config
tomba-runtime.exe is built from this repo's runtime/ plus
TombaRecomp/generated/. It also links this repo's
generated/SCPH1001_*.c for the BIOS half. The cmake macro that does this
is psxrecomp_v4_add_runtime_target in this repo's runtime/CMakeLists.txt.
psx-runtime.exe is a BIOS-only build target in this repo's runtime/. It's
the test runner for the discless BIOS shell (memcard / CD player screen).
Nobody has been actively testing it recently; expect it to be subtly broken.
Two recompilers
| Binary | Source set | Input | Output |
|---|---|---|---|
psxrecomp-bios.exe |
strict_translator.cpp + full_function_emitter.cpp + function_discovery.cpp + bios_slice_walker.cpp + main_bios.cpp |
flat BIOS ROM at 0xBFC00000 | generated/SCPH1001_*.c |
psxrecomp-game.exe (also aliased as PSXRecomp.exe) |
code_generator.cpp + function_analysis.cpp + control_flow.cpp + ps1_exe_parser.cpp + main_psx.cpp |
PS-X EXE header + body | <game>_full.c + <game>_dispatch.c |
They share only mips_decoder.cpp. No code path is shared between BIOS
and game translation. Fixes in one don't apply to the other.
The seeds file (recompiler/seeds/phase2_ghidra_seeds.json) is the BIOS
seeds, passed positionally to psxrecomp-bios.exe --emit-full. Tomba seeds
live at TombaRecomp/seeds/. bios/SCPH1001.toml and
TombaRecomp/game.toml exist but are currently only consumed by audit tools,
not by the recompilers themselves. (This is one of the things unification
fixes.)
.happypath/ — what it contains, when to use it
.happypath/tomba-runtime.exe— copy of the May 12 11:55 working binary..happypath/SCPH1001_full.c.obj— May 11 23:49 BIOS recomp object file (compiled with-gdebug; .text size 0x371440 = 3.6 MB; this is the reference for "the BIOS output that works")..happypath/SCPH1001_dispatch.c.obj— same era.
Restore drill: if a future session breaks tomba-runtime, copy
.happypath/tomba-runtime.exe back to F:\Projects\TombaRecomp\build\ and
stop touching anything until you understand why.
Sanity check that we haven't drifted:
PATH=/c/msys64/mingw64/bin:$PATH objdump -h .happypath/SCPH1001_full.c.obj
→ .text size MUST be 0x00371440 (debug build with -g, no -O)
If a fresh BIOS regen + debug build doesn't produce a matching size, the generated/ output has changed.
What is currently in working-tree (M / ??)
These were already modified at session start (carried in from prior session):
M ISSUES.md— pre-existing Issue #1-#3; this session also added Issue #4 and Issue #5.M recompiler/src/code_generator.cpp— pre-existing mid-function split pre-pass cap raised 3 → 16 (Tomba fix; doesn't affect BIOS regen).M runtime/src/debug_server.c— pre-existing wtrace slot 24/25 ranges for Tomba pad-poll + gflag observation.D tools/_codegen_audit.py— pre-existing rename tocodegen_audit.py.M tools/gte_audit.py,M tools/scan_branch_delay_hazards.py— pre-existing parameterization for audit-config.
This session also added:
- New audit infrastructure:
tools/audit_config.py,tools/codegen_audit.py,tools/codegen_audit_game.py,tools/verify_audit_schema.py,bios/SCPH1001.toml. docs/audit_inventory.md.- An encoding fix to
tools/gte_audit.py(Unicode✓→ ASCIIOK). - This file (
CURRENT_STATE.md). UNIFICATION_PLAN.md(next-step plan)..happypath/(backup of working binaries).
This session's recompiler-source changes were reverted after they caused confusion; the recompiler/src/ tree is back to clean HEAD.
Why prior sessions got lost (and how to not repeat it)
-
The handoff said "main menu reachable, Load Game enter/exit works." That meant Tomba's main menu, not the BIOS shell. "Load Game" is the in-game save-load menu inside Tomba, not the BIOS shell's load-from-disc action. Future handoffs should explicitly write
tomba-runtime: <state>vspsx-runtime: <state>so this can't be mistaken. -
Rebuilding
psxrecomp-bios.exeis destructive in two ways: (a) overwrites the binary itself, (b) any subsequent--emit-fullrun overwritesgenerated/SCPH1001_*.c. There was no backup of the prior workinggenerated/. Now there is —.happypath/has the compiled.objfiles for it. -
Debug vs Release matters. The working
tomba-runtimeis a Debug build (-g, no-O).psx-runtime's CMakeCache hadBUILD_TYPE=Release(-O3 -DNDEBUG). The same generated C may behave differently at the two optimization levels. If you build the wrong one to validate, you will mis-diagnose. For now, always test the Debug build. (The underlying generated C presumably has undefined-behavior the Release optimizer exploits — that's a real bug, but not one we're chasing yet.) -
Two runtimes look symmetric but aren't.
psx-runtimeandtomba-runtimeboth link the samegenerated/SCPH1001_*.c, but onlytomba-runtimeis being actively exercised. Always checktomba-runtimefirst if a "boot" question comes up. -
generated/is not in git (commit802e0fbstopped tracking it). The recompiler is the source of truth. If you regenerate, you cannot easily undo.
The actual broken thing right now
psx-runtime.exe does not boot to the BIOS shell. It hangs in the kernel
exception handler / RestoreState loop, with VBlank pending in I_STAT but
never ACK'd. Symptoms (captured in starvation_dump.jsonl earlier):
- Tight loop between
func_00000C80(kernel exception handler),func_00000EA0(mfc0 helper),func_00000F40(RestoreState),func_1FC40628(the I_STAT ACK helper for CDROM bit 3 — note: NOT bit 0 for VBlank),func_1FC40700,func_1FC42BA0(B0 trampoline at RAM 0xB0 forB0:0x17 ReturnFromException),func_000005E0(B0 dispatcher). i_stat = 0x09(bits 0 = VBlank, 3 = CDROM pending) withi_mask = 0x4D(bits 0, 2, 3, 6 enabled). CDROM gets ACK'd via0xFFFFFFF7; VBlank never gets ACK'd.- The chain handler that should ACK VBlank apparently isn't being invoked, or returns 0 (not-handled) so the kernel doesn't ACK.
This is not the immediate problem to fix — the unification plan happens
first. But note it here so it doesn't get forgotten. See ISSUES.md for
the full open-issue list.
How to verify the happy path is still happy
# Kill any running runtimes first.
taskkill //F //IM psx-runtime.exe 2>/dev/null
taskkill //F //IM tomba-runtime.exe 2>/dev/null
# Launch the backed-up working binary.
"./.happypath/tomba-runtime.exe" # debug port 4470
# In a second shell, ping it. If you get a frame number back, it booted.
python tools/_ping_tomba.py
# Expected: {"id":1,"ok":true,"frame":<some-number-going-up>}
If the SDL window shows the Tomba main menu, you are at the happy path. Do
not rebuild tomba-runtime (which would re-link against whatever
generated/SCPH1001_*.c currently exists) without first verifying the
generated output matches .happypath/SCPH1001_full.c.obj's .text size.