mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
2439d4dd44
Bug D root cause (Tomba chest freeze, also QA issue #1): the game's own dispatcher func_80056E08 has a dead jumptable case (type 0x21 -> jal 0x80120B3C) whose target is mid-function in EVERY overlay variant on the disc (only the boot EXE references it; the real handler entry is 0x80120AC8). Entering mid-function skips the prologue, runs an epilogue for a frame that was never pushed, and returns through garbage. Our C model then resumed the suspended generated continuations on the moved guest stack -> double-executed tails -> infinite zombie loop (~3K wild calls/frame) -> MMIO fatal. Family root of Bugs A/C/D. The contract: a generated C continuation may only run if the guest actually arrived at it ($ra == call site return address, $sp == caller sp at the call). Violations begin a "bail" unwind: cpu->pc := the wild jr's true target, every generated frame returns immediately, and the unwind resolves at the first enclosing site whose contract matches (or flattens at the outermost dispatch loop, re-dispatching the wild target on a clean host stack -- matching real-HW one-stack semantics). - cpu_state.h: bail state + psx_call_contract() helper (+ overlay-DLL pointer indirection under PSX_OVERLAY_DLL_BUILD) - emitters: (ra, sp) checks at every BIOS and game jal/jalr site; psx_dispatch_impl validates pc==0 and stop-hits against (stop, sp), handles bail resolve/propagate/flatten - dirty_ram_interp: surfaced calls validate the contract on return; bail aborts the interp run; tail transfers into compiled code now run with pc cleared (closes a latent double-run on plain C returns) - overlay cache ABI v2: DLLs export overlay_abi(); loader rejects and deletes stale DLLs (autocompile regenerates with contract checks) - telemetry: bail_first/resolved/flattened/anomaly in heartbeat + dump headers; anomaly guard at exception entry; TCP_COMMANDS.md docs Verified: BIOS+Tomba regen, boot to intro at locked 60.0 fps, all bail counters 0 through boot/title/attract (no false positives). Chest-area gameplay verification pending (requires user play). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
66 lines
2.4 KiB
C
66 lines
2.4 KiB
C
#ifndef OVERLAY_API_H
|
|
#define OVERLAY_API_H
|
|
|
|
/* Shared ABI between psx-runtime.exe and overlay DLLs.
|
|
*
|
|
* After LoadLibrary, the runtime calls overlay_init() with this struct.
|
|
* The DLL stores the pointers and routes all cross-module calls through them.
|
|
*/
|
|
|
|
#include "cpu_state.h"
|
|
#include <stdint.h>
|
|
|
|
/* ABI version exported by every overlay DLL as `overlay_abi()`. The loader
|
|
* rejects (and deletes, so autocompile regenerates) any DLL whose version
|
|
* doesn't match — including all pre-versioning DLLs, which lack the export.
|
|
*
|
|
* v2: dispatch call-contract (Bug D family) — DLL call sites carry (ra, sp)
|
|
* contract checks and share the runtime's bail state via the appended
|
|
* callback pointers below. */
|
|
#define PSX_OVERLAY_ABI_VERSION 2
|
|
|
|
typedef struct {
|
|
/* Core dispatch: routes call_by_address() and out-of-overlay jal */
|
|
void (*dispatch_call)(CPUState *cpu, uint32_t addr, uint32_t ra);
|
|
/* Interrupt check: called after every function return in overlay */
|
|
void (*check_interrupts)(CPUState *cpu);
|
|
/* GTE coprocessor 2 execution */
|
|
void (*gte_execute)(CPUState *cpu, uint32_t cmd);
|
|
/* MIPS syscall (break/syscall instructions) */
|
|
void (*psx_syscall)(CPUState *cpu, uint32_t code);
|
|
/* Unresolved dispatch target */
|
|
void (*psx_unknown_dispatch)(CPUState *cpu, uint32_t addr, uint32_t phys);
|
|
/* Debug instrumentation: called at every function entry (may be NULL) */
|
|
void (*log_call_entry)(uint32_t func_addr);
|
|
/* RestoreState/ReturnFromException longjmp escape (interrupts.c). The
|
|
* recompiler emits this at longjmp-return sites in exception-context
|
|
* kernel code (the install-slot / kernel-window class). Appended LAST:
|
|
* overlay_init copies the struct by value, so older DLLs built against
|
|
* the shorter struct simply never read this member. */
|
|
void (*psx_restore_state_escape)(void);
|
|
/* Call-contract state shared with the runtime (ABI v2; see the contract
|
|
* model in cpu_state.h). DLL code reads the bail flag and bumps the
|
|
* counters through these pointers. */
|
|
int *call_bail_flag;
|
|
uint64_t *bail_first;
|
|
uint64_t *bail_resolved;
|
|
} OverlayCallbacks;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Exported by every overlay DLL. Call once after LoadLibrary. */
|
|
#ifdef _WIN32
|
|
__declspec(dllexport)
|
|
#else
|
|
__attribute__((visibility("default")))
|
|
#endif
|
|
void overlay_init(const OverlayCallbacks *cbs);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* OVERLAY_API_H */
|