Files
psxrecomp/docs/config_schema.md
T
Matthew Stanley ec7e482691 Ape Escape support: framework WIP snapshot (safe haven)
Uncommitted framework work on codex/ape-escape-support reaching the
post-boot DualShock-required screen. Recompiler codegen (code_generator,
full_function_emitter, function_analysis, config_loader) + runtime
(cdrom, sio, dirty_ram_interp, dma, iso_reader, mdec, gpu, memory,
traps, debug_server, fntrace, freeze_heartbeat, psx_cycles) and headers.

Committed as a restore point before rebuilding Tomba against this
framework. Build dirs (recompiler/build-codex*) intentionally excluded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:48:38 -07:00

5.8 KiB

PSXRecomp v4 — config TOML schema

Consumed by:

  • psxrecomp-bios.exe and psxrecomp-game.exe (once Phase A2/A3 ships --config <toml> support)
  • tools/audit_config.py and the audit tooling that wraps it
  • The runtime cmake macro (runtime/runtime.cmake)

Examples:

  • bios/SCPH1001.toml — BIOS-only config (no game; psx-runtime targets this)
  • F:/Projects/TombaRecomp/game.toml — game config (tomba-runtime targets this)

How configs combine

A PSXRecomp v4 process always has a BIOS config. It optionally also has a game config. Both are TOML files in this schema:

  • bios/SCPH1001.toml (or another BIOS .toml in bios/) — describes the BIOS. Always loaded.
  • <game>/game.toml — describes a single game. Loaded ONLY when running that game.
psxrecomp                            # BIOS-only regen (uses default bios.toml)
psxrecomp games/tomba/game.toml      # BIOS + game regen
psx-runtime                          # boots BIOS discless
psx-runtime games/tomba/game.toml    # boots BIOS, then loads game

When both are loaded, keys merge:

  • Scalar keys (debug_port, window_title, memcard_dir, ...): game wins if set, inherit from bios.toml otherwise. Shallow override.
  • [program] (BIOS) and [game] blocks: NOT merged — they describe different programs. Both are visible to the loader.
  • Generated dispatch tables and C output: ADDITIVE. BIOS contributes SCPH1001_*.c; game contributes <exe>_*.c. No address overlap is expected (BIOS lives at RAM 0x500-0x8500 + ROM 0xBFC..., game at 0x80010000+). The cmake macro psxrecomp_v4_add_runtime_target already links both.
  • [[audit.regions]] and [[audit.normalize.remap]]: additive — game adds its regions on top of BIOS's.

Top-level blocks

[program]    # in bios.toml; describes the BIOS
[game]       # in game.toml; describes the game
[recompiler]
[runtime]
[audit]

Program / game block

  • bios.toml has a [program] block describing the BIOS ROM.
  • game.toml has a [game] block describing the game EXE / disc.

These are NOT alternatives; they're complementary. A runtime loading both sees both blocks. The legacy single-file audit loader (tools/audit_config.py) accepts either as the program-info source for backwards compat, but going forward they are the canonical names for their respective files.

Fields

Field Required for Description
name both display name, e.g. "SCPH1001 BIOS"
id both canonical id, e.g. "SCPH-1001" or "SCUS-94236"
rom bios path to raw flat binary, relative to project root
exe game path to PS-X EXE file, relative to project root
load_address both hex string, virtual address of first byte ("0xBFC00000" BIOS, "0x80010000" typical game)
entry_pc both hex string, first PC to execute
text_size both hex string, size in bytes of code segment (used by audits to bound region walks)
stack_base game hex string, initial $sp value for the game
disc game (single-disc) path to .cue, relative to project root
discs game (multi-disc) array of .cue paths; disc is sugar for discs = [disc]

Recompiler block

[recompiler]
seeds       = "recompiler/seeds/phase2_ghidra_seeds.json"  # BIOS
seeds       = "seeds/ghidra_funcs.txt"                     # game (note: game seeds aren't json today)
bios_thunks = "seeds/tomba_bios_thunks.txt"                # game-only
out_dir     = "generated"                                  # both
strict      = true                                         # both — currently always true
out_stem    = "SCPH1001"                                   # optional; overrides the auto-derived stem

Output filenames: <out_dir>/<out_stem>_full.c and <out_dir>/<out_stem>_dispatch.c. If out_stem is omitted, it's derived from the rom/exe file basename with the trailing .BIN or .EXE stripped (Path.stem is NOT used because it mishandles SCUS_942.36).

Runtime block

Consumed by the cmake macro psxrecomp_v4_add_runtime_target (eventually) and by runtime/src/main.cpp as the source of compiled-in defaults.

[runtime]
debug_port    = 4370            # TCP port for the debug server
window_title  = "..."           # SDL window title
controller    = "digital"       # "digital" or "dualshock"
memcard_dir   = "."             # memcard files location, relative to project root

Reserved future fields:

  • default_disc_path — game runtimes can pre-mount a disc
  • default_game_root — for sibling-junction setups

Audit block

See docs/audit_inventory.md for the audit pipeline. The schema here is the input side: regions to walk, address-normalisation rules.

[audit]
function_starts = "generated/ghidra_function_starts.json"   # optional

[[audit.regions]]
name        = "..."             # e.g. "Boot", "Kernel", "Shell", "Text"
rom_start   = "0x..."           # byte offset in rom/exe file
rom_end     = "0x..."           # exclusive
vaddr_base  = "0x..."           # virtual address corresponding to rom_start

[audit.normalize]
kseg_mask = "0x1FFFFFFF"

[[audit.normalize.remap]]
description = "..."             # human-readable; not consumed by tooling
from_lo     = "0x..."           # inclusive
from_hi     = "0x..."           # exclusive
to_lo       = "0x..."           # target start offset (phys = phys - from_lo + to_lo)

What's NOT in the schema yet (Phase B+)

These are noted here so future work knows where to slot them:

  • Game discs field (Phase D). For now Tomba uses disc = "...".
  • [runtime] disc_swap_command — runtime-side disc swap (Phase D).
  • [recompiler] seeds as an array of paths (currently single file; Phase A might allow multiple).
  • [program] type explicit discriminator (currently inferred from rom vs exe field presence).