-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgame.toml
More file actions
294 lines (268 loc) · 13.1 KB
/
Copy pathgame.toml
File metadata and controls
294 lines (268 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
[game]
name = "Tomba! 2 - The Evil Swine Return"
id = "SCUS-94454"
exe = "tomba2/SCUS_944.54"
disc = "tomba2/Tomba! 2 - The Evil Swine Return (USA).cue"
load_address = "0x80010000"
entry_pc = "0x80018B6C"
text_size = "0x00028800"
stack_base = "0x801FFFF0"
[recompiler]
seeds = "seeds/ghidra_funcs.txt"
# bios_thunks = "seeds/tomba2_bios_thunks.txt" # optional; add once inventoried
out_dir = "generated"
strict = true
[runtime]
# HLE boot shell-skip (master 582aecc): skips the PSX boot animation via the
# HLE tier's one-shot shell intercept; kernel init + game EXE load still run
# on the real recompiled BIOS at host speed. Set false to watch BIOS logos.
# Full HLE kernel tier (bios_hle) stays OFF here — LLE is the baseline; Tomba1
# is the HLE validation title.
fast_boot = true
# Loading speed is mod-owned for this title ("Fast Loading (host pacing)" and
# "CD Speed" on the Mods page, both default-off). The legacy generic
# turbo_loads / offer_turbo_loads keys were retired framework-side -- the
# runtime now ignores them and warns on sight -- so they are gone from here.
# Tomba2's OWN debug port — 4500 collides with the SNES mmx_cosim processes.
# Taken elsewhere: 4370/4380 psxrecomp-v4, 4470 Tomba1, 4510 Tsumu, 4520 MMX5.
debug_port = 4515
window_title = "Tomba! 2 Recompiled"
controller = "digital"
memcard_dir = "saves"
# Overlay cache (the real perf fix). Tomba 2's title/menu/level/FMV-driver code
# is runtime-loaded overlay, not in the 474 compiled boot-EXE funcs, so by
# default it ALL interprets (~4fps game logic). The cache JITs those overlays to
# native via the *gcc* backend: autocapture writes overlay_captures.json, the
# autocompile_cmd spawns the recompiler+gcc in the background to produce CPS
# overlay DLLs in build-t2/cache, and the loader hot-swaps them in live.
#
# overlay_backend = "gcc" (NOT sljit): on 2026-06-23 the in-process sljit backend
# declined ~31/39 Tomba 2 shards (no payoff) and hard-HUNG the boot on the
# Whoopee-Camp logo. With gcc selected the loader runs gcc>interp and never
# starts sljit live (overlay_loader_apply_live_policy forces sljit off when the
# active backend is gcc), so the gap before DLLs land is the interpreter (slow
# but correct), never the sljit hang path.
#
# No --cps in the command: CPS is the recompiler DEFAULT (PSX_CPS unset), which
# matches Tomba 2's CPS boot + CPS runtime. flavor 0 (not widescreen).
overlay_cache = true
# Preserve each coherent runtime discovery without replacing earlier launches.
# Production keeps the append-only addendum beside the executable; dev configs
# additionally opt into immutable project-local snapshots.
overlay_capture_history = true
# "auto" = gcc when a gcc toolchain is present, else the toolchain-free tcc tier
# (post-2026-06-25 tcc refactor). On a dev machine with mingw this resolves to gcc,
# so behaviour matches the old explicit "gcc"; on a clean install it falls back to
# tcc instead of leaving overlays interpreted. The in-process sljit producer stays
# OFF in every case (it hung Tomba 2's Whoopee-Camp logo — see below).
overlay_backend = "auto"
# Keep the timing-sensitive splash/FMV task setup routines on the interpreter.
# Native execution of these small setup paths leaves the Whoopee-Camp logo stuck
# before the intro FMV; the rest of the overlay cache still runs native.
overlay_native_block = [
"0x80096A90",
"0x80052078",
"0x800520C0",
]
# All paths are RELATIVE to the project root (the runtime spawns this with cwd =
# project root), so the shipped config is portable across machines. The
# recompiler exe + runtime-include are resolved to absolute by compile_overlays.py
# itself (a relative Windows exe path isn't resolved against the child cwd).
# This hot computed-dispatch routine has no stable callable boundary in the
# surrounding overlay, so keep it in the isolated fragment failure domain.
overlay_autocompile_cmd = "py -3 psxrecomp-v4/tools/compile_overlays.py --captures build-t2/overlay_captures.json --game-toml game.toml --recompiler psxrecomp-v4/recompiler/build/psxrecomp-game.exe --runtime-include psxrecomp-v4/runtime/include --out-dir build-t2/cache --force-interior 0x8008D030 && py -3 psxrecomp-v4/tools/coverage_vault.py merge --vault ../_coverage_vault/SCUS-94454 --captures build-t2/overlay_captures.json --cache build-t2/cache/SCUS-94454"
# Tomba 2 is a d-pad platformer. Real PS1 hardware powers a DualShock up in
# DIGITAL mode (analog LED off, controller id 0x41) and Tomba 2's pad driver
# only runs the DualShock config-mode handshake (0x43/0x4D...) when it sees the
# analog id 0x73. The framework's default HYBRID mode boots analog-on (0x73),
# which triggers that handshake every frame; our SIO config emulation doesn't
# satisfy the driver, so it intermittently reads 0x00 button bytes (all buttons
# "pressed") -> menu unresponsive + idle timer never reaches the attract demo.
# Booting DIGITAL (id 0x41, never 0x73) matches the Beetle oracle exactly: the
# game just polls with 0x42 and reads clean 0xFFFF idle.
#
# Analog / Hybrid are NOT offered for Tomba 2: the DualShock config-mode
# handshake emulation is incomplete, so any non-digital mode re-triggers the
# phantom-input bug above. lock_mode hides the launcher's whole pad-mode
# selector (Hybrid | Analog | D-Pad) and forces every port to default_mode, so
# the player can never pick a broken mode. allow_hybrid=false is redundant under
# lock_mode but documents intent. Re-enable the selector (drop lock_mode) only
# once the analog config handshake is emulated end-to-end.
[controller]
default_mode = "digital"
allow_hybrid = false
lock_mode = true
# --- Renderer: optimized hardware path.
# Supersampling: internal-resolution SSAA factor. 2 is the quality default now
# that Tomba 2 holds full speed on the OpenGL path; lower to 1 for slower GPUs.
# Antialiasing: linear present filtering for the sampled frame. The launcher
# exposes both controls on the Video page and persists overrides to settings.toml.
[video]
renderer = "opengl"
supersampling = 2
antialiasing = true
texture_filtering = "nearest"
# Tomba 2 owns temporal frame blending through its built-in Frame Blending mod.
# Hide the generic Display controls and ignore stale settings.toml values.
frame_interpolation = false
frame_interpolation_fps = 0
offer_frame_interpolation = false
# Authentic 4:3 is the baseline. The Widescreen mod activates Tomba 2's
# game-specific native-wide hooks and selects the presentation aspect.
aspect_ratio = "4:3"
# FMV auto-skip (debug iteration speed). Tomba2's streamed movies end on a
# frame-total cell (single u32 at 0x8010271C, checked by the sector pump
# FUN_8008d110 against the streamed frame counter 0x801026E8; 0 = play to EOF)
# rather than Tomba1's per-movie table — the START-hold fallback handles the
# START-skippable ones. The Whoopee Camp logo is a SILENT RAM-preloaded movie
# (no CD sectors, no XA during playback): fmv_skip_no_xa broadens detection to
# MDEC activity alone so it fast-forwards too (presentation-side only).
# The longer silent-MDEC hold also covers the logo's post-decode wait. Tomba 2
# owns activation through its Skip FMVs mod; hide the legacy Display toggle and
# keep the faithful baseline until that mod activates.
auto_skip_fmv = false
offer_skip_fmv = false
fmv_skip_no_xa = true
fmv_skip_no_xa_hold = 600
# Native-wide gameplay. The runtime keeps BIOS, FMV, and true 2D screens at
# their authored 4:3 aspect; GTE-active gameplay uses the wider compositor.
[widescreen]
# Widescreen is game-owned on the Mods page, not a generic Display setting.
offer = false
gte_game_mode = true
offer_ultrawide = true
adaptive_view = true
nw_hud_corners = false
nw_backdrop = false
nw_flat_backdrop = true
nw_phase_backdrop = true
[widescreen.cull]
# Tomba 2's overlay render funnels reject projected vertices against the
# original 320x240 bounds. Widen the horizontal comparisons only while a wide
# aspect is active. The explicit height immediate qualifies the signature but
# is not itself changed.
auto_screen_x = true
screen_w_imms = ["0x140"]
screen_h_imms = ["0xF0"]
# Keep a small resident-area guard beyond the live wide edge. The aspect-cone
# hook below treats this separately from the visible field and reserves queue
# headroom for candidates actually intersecting the wide frustum.
guard_pixels = 16
# Advance only the proven player-relative X/Z activation windows by the
# maximum supported resident-area lead. This does not widen terrain-cell
# angles or fixed-capacity model cones; at 21:9 the activation margin is
# 120px visible reveal + 16px render guard + 256px activation lead = 392px.
activation_guard_pixels = 256
# Proven model participation windows. Overlay code at the same address is
# opcode-checked and left untouched when it differs. FUN_80069B6C is a
# behavior/teleport proximity trigger, not a pure render cull; retain only its
# ground-plane X/Z pairs. Removing all three pairs caused missing nearby
# composite scenery and terrain in the starting-area demo. Its Y pair
# (0x80069B84/0x80069B8C) stays vanilla so vertical behavior reach is not
# extended.
bias_sites = [
"0x80069BA8", "0x80069BCC", "0x80110A08",
]
range_sites = [
"0x80069BB0", "0x80069BD8", "0x80110A10",
]
screen_x_sites = ["0x8003E228"]
# Three captured overlay producers build terrain-cell selection quads consumed
# by bounded, deduplicating rasterizers. These are positive 12-bit angular
# half-extents, not pixels: widen their tangent by the live horizontal aspect
# factor. Full-word guards make overlay aliases inert; every observed producer
# retains the fixed 0xFE terrain-list cap.
[[widescreen.cull.angle]]
address = "0x8010E9A0"
expected = "0x240301C7"
[[widescreen.cull.angle]]
address = "0x8012EEB8"
expected = "0x2403012C"
[[widescreen.cull.angle]]
address = "0x8013F138"
expected = "0x24020155"
[[widescreen.cull.angle]]
address = "0x8013F190"
expected = "0x240301C7"
[[widescreen.cull.angle]]
address = "0x8013F224"
expected = "0x2402013E"
[[widescreen.cull.angle]]
address = "0x8013F244"
expected = "0x240201C7"
[widescreen.cull.aspect_cone]
# FUN_8007712C clears model+1, applies a spherical camera cone, then inserts
# accepted type 2/9, 4, and 5 models into fixed 24/40/28-entry scratch queues.
# These full-word-guarded sites preserve every vanilla acceptance and widen
# only camera-horizontal participation. Vertical reach and distance gates stay
# vanilla. Hysteresis is outside the 16px activation guard.
forward_addr = "0x1F8000E8"
object_type_offset = 12
object_reg = 19 # s3
x_reg = 16 # s0
z_reg = 17 # s1
y_reg = 18 # s2
hysteresis_pixels = 24
queue_reserve = 4
queue_count_addrs = ["0x1F800144", "0x1F800150", "0x1F80015C"]
queue_capacities = [24, 40, 28]
queue_type_masks = ["0x00000204", "0x00000010", "0x00000020"]
# FUN_8002B278 is the lower-level per-model/per-child cone. It does not append
# to the fixed scratch queues. Its SLT compares dot(camera_forward, delta)
# against distance * 0xD60; 0xD60 Q12 is 0x358 in the hook's Q10 units.
[[widescreen.cull.aspect_cone.sites]]
address = "0x8002B368"
expected = "0x0082202A"
cosine_threshold = 856
object_reg = 20 # s4
x_reg = 19 # s3
z_reg = 18 # s2
y_reg = 17 # s1
queue_guard = false
[[widescreen.cull.aspect_cone.sites]]
address = "0x800772D4"
expected = "0x28620370"
[[widescreen.cull.aspect_cone.sites]]
address = "0x80077368"
expected = "0x28620358"
[[widescreen.cull.aspect_cone.sites]]
address = "0x80077414"
expected = "0x28620358"
[[widescreen.cull.aspect_cone.sites]]
address = "0x800774A8"
expected = "0x28620370"
[[widescreen.cull.aspect_cone.sites]]
address = "0x8007753C"
expected = "0x28620350"
[[widescreen.cull.aspect_cone.sites]]
address = "0x800775D0"
expected = "0x28620368"
# ── Audit-specific config (consumed by psxrecomp/tools/*.py and tests) ──
# Schema mirrors psxrecomp/bios/SCPH1001.toml. Paths are relative to the
# project root.
[audit]
# Dynamic discovery — functions are found by walking control flow from
# entry_pc. No Ghidra function-starts file is required to bootstrap.
# Code region: text segment is contiguous from load_address for text_size bytes.
[[audit.regions]]
name = "Text"
rom_start = "0x800" # offset within the PS-X EXE file (skip header)
rom_end = "0x29000" # rom_start + text_size
vaddr_base = "0x80010000"
# Address normalization: KSEG masking only (game loads contiguously, no remaps).
[audit.normalize]
kseg_mask = "0x1FFFFFFF"
# Conservative load-time optimization.
# Verified against SCUS_944.54's PsyQ VSync(mode) routine: VSync(-1) returns
# the guest VBlank counter at 0x800267B4. The adjacent GPUSTAT and Timer1 reads
# are used only to stabilize the query path; the framework hook preserves the
# original instruction timing, stack traffic, cache fetches, and IRQ checkpoints
# while bypassing those side-effect-free MMIO handlers. This is intentionally
# not a turbo/speedhack path: no CD speed, pacing, idle-skip, or event-horizon
# fast-forward is enabled here.
[load_accel.vsync_query]
func = "0x80017E4C"
counter_addr = "0x800267B4"
gpustat_ptr_addr = "0x8002567C"
timer1_ptr_addr = "0x80025680"
timer1_cache_addr = "0x80025684"