Files
psxrecomp/CURRENT_STATE.md
T
Matthew Stanley 2f709ee542 Phase B: config-driven unified runtime + BIOS shell boot restored
- 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>
2026-05-13 01:31:27 -07:00

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.exe so 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 -g debug; .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 to codegen_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 ✓ → ASCII OK).
  • 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)

  1. 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> vs psx-runtime: <state> so this can't be mistaken.

  2. Rebuilding psxrecomp-bios.exe is destructive in two ways: (a) overwrites the binary itself, (b) any subsequent --emit-full run overwrites generated/SCPH1001_*.c. There was no backup of the prior working generated/. Now there is — .happypath/ has the compiled .obj files for it.

  3. Debug vs Release matters. The working tomba-runtime is a Debug build (-g, no -O). psx-runtime's CMakeCache had BUILD_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.)

  4. Two runtimes look symmetric but aren't. psx-runtime and tomba-runtime both link the same generated/SCPH1001_*.c, but only tomba-runtime is being actively exercised. Always check tomba-runtime first if a "boot" question comes up.

  5. generated/ is not in git (commit 802e0fb stopped 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 for B0:0x17 ReturnFromException), func_000005E0 (B0 dispatcher).
  • i_stat = 0x09 (bits 0 = VBlank, 3 = CDROM pending) with i_mask = 0x4D (bits 0, 2, 3, 6 enabled). CDROM gets ACK'd via 0xFFFFFFF7; 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.