mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
181 lines
6.8 KiB
Markdown
181 lines
6.8 KiB
Markdown
# PSXRecomp v4 — config TOML schema
|
||
|
||
Consumed by:
|
||
- `psxrecomp-bios.exe` and `psxrecomp-game.exe` (via `--config <toml>`)
|
||
- `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)
|
||
- `../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
|
||
|
||
```toml
|
||
[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
|
||
|
||
```toml
|
||
[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.
|
||
|
||
```toml
|
||
[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
|
||
```
|
||
|
||
### Opt-in warm CD routes
|
||
|
||
Per-game read acceleration is disabled unless the game explicitly declares
|
||
one or more strict routes. Each route arms on one `SetLoc`, then requires every
|
||
later file start to match `lbas` in order. A mismatch immediately restores the
|
||
normal configured disc timing. Only data-read cadence is accelerated; XA/CDDA,
|
||
seek, and motor timing remain authentic.
|
||
|
||
```toml
|
||
[[runtime.warm_cd_routes]]
|
||
arm_lba = 95947
|
||
lbas = [298, 299, 306]
|
||
instant_max_per_frame = 32
|
||
```
|
||
|
||
Up to 16 routes may be declared, with 1–64 LBAs each. The old singular
|
||
`[runtime.warm_cd_route]` table is deprecated and emits a warning when loaded;
|
||
it remains readable for compatibility. This enhancement is intentionally
|
||
opt-in and must not acquire a global default.
|
||
|
||
The other load-time accelerators are likewise opt-in:
|
||
|
||
```toml
|
||
[runtime]
|
||
turbo_loads = true
|
||
idle_skip = true
|
||
turbo_audio_sink = true
|
||
```
|
||
|
||
`turbo_audio_sink` is meaningful only while `turbo_loads` is active. It keeps
|
||
the guest SPU timeline advancing but discards accelerated samples before host
|
||
playback, then fades normal output back in.
|
||
|
||
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.
|
||
|
||
```toml
|
||
[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).
|