mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
interrupts: never publish pc=0 from same-thread restore at top-level depth; exit-reg diagnostics
pc=0 from the same-thread-restore epilogue means "the interrupted native frame is still on the host stack below - return and it continues". At dispatch depth <= 0 no such frame can exist and the 0 reaches the main loop as a bogus GUEST_EXIT, so prefer the compiled interrupt resume PC there (the same remedy the scheduler top-level-resume case already uses). Honest scope note: this closes a real hole by construction, but does NOT fix the observed WipEout 3 static-bake boot exit (deterministic "execution completed, PC=0", ra=0x800D7FC0, epc=0x8015FAEC) - that death reproduces unchanged, so its escape route is elsewhere; investigation continues. Also: the top-level exit path now prints the exit registers (ra/sp/epc/sr/func/last_store_pc/v0/a0/t9), which is how the crash was attributed on play builds without debug tools. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1844,7 +1844,18 @@ irq_deliver_eval:
|
||||
same_thread_resume = 1;
|
||||
{
|
||||
extern int psx_scheduler_top_level_resume_active(void);
|
||||
if (psx_scheduler_top_level_resume_active()) {
|
||||
/* pc=0 means "the interrupted native frame is still on the host
|
||||
* stack below us — return and it continues". That contract also
|
||||
* breaks whenever dispatch has already collapsed to TOP LEVEL
|
||||
* (depth 0): statically-baked overlay functions cross into AOT
|
||||
* text via CPS returns, so the interrupted chain may hold no
|
||||
* host frames at all, and a published 0 reaches the main loop
|
||||
* as a bogus GUEST_EXIT (WipEout 3 ntsc120full8 static bake:
|
||||
* deterministic "execution completed, PC=0" ~10 s into boot,
|
||||
* ra=0x800D7FC0 epc=0x8015FAEC). Same remedy as the scheduler
|
||||
* case: prefer the compiled interrupt resume PC. */
|
||||
if (psx_scheduler_top_level_resume_active() ||
|
||||
g_psx_dispatch_depth <= 0) {
|
||||
uint32_t resume = s_compiled_interrupt_resume_pc;
|
||||
if (resume == 0u)
|
||||
resume = s_last_interrupt_check_pc;
|
||||
|
||||
@@ -14380,6 +14380,20 @@ session_reboot:
|
||||
}
|
||||
|
||||
std::fprintf(stdout, "psxrecomp runtime: execution completed, PC=0x%08X\n", cpu.pc);
|
||||
/* The PC=0 top-level exit is an abnormal-boot class (see interrupts.c:
|
||||
* approximate exception-resume PCs severing the live native chain). The
|
||||
* registers at exit name the culprit without needing a debug-tools build:
|
||||
* ra = who returned/jumped here, epc = the last exception context. */
|
||||
{
|
||||
extern uint32_t g_debug_current_func_addr, g_debug_last_store_pc;
|
||||
std::fprintf(stdout,
|
||||
"psxrecomp runtime: [exit regs] ra=0x%08X sp=0x%08X "
|
||||
"epc=0x%08X sr=0x%08X func=0x%08X last_store_pc=0x%08X "
|
||||
"v0=0x%08X a0=0x%08X t9=0x%08X\n",
|
||||
cpu.gpr[31], cpu.gpr[29], cpu.cop0[14], cpu.cop0[12],
|
||||
g_debug_current_func_addr, g_debug_last_store_pc,
|
||||
cpu.gpr[2], cpu.gpr[4], cpu.gpr[25]);
|
||||
}
|
||||
{ extern uint64_t g_slice_fired, g_slice_irq_taken, g_dirty_ram_insns_run;
|
||||
extern uint32_t g_slice_exit_pc, g_slice_exit_reason, g_slice_exit_iter;
|
||||
extern uint32_t g_slice_exit_dispatchable, g_slice_exit_dirty, g_slice_exit_in_text, g_slice_exit_want;
|
||||
|
||||
Reference in New Issue
Block a user