From 6889f5c5d29c182f9426acc72ae5e766f79c7fb1 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Tue, 5 May 2026 22:13:06 -0700 Subject: [PATCH] recompiler: seed missing modal_stub function (BFC1A1BC), add unknown_dispatch_log ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modal close on YES/NO COPY confirm now works on recomp. Cause: function discovery (Ghidra + transitive walk) missed the function at 0xBFC1A1BC which the BIOS shell calls indirectly during modal close. The 5 nearby "missing" PCs the diagnostic identified are all in the same gap from 0xBFC1A1B8 to 0xBFC1A3B8; seeding 0xBFC1A1BC discovers the rest transitively. Status: modal closes cleanly on X. Actual copy execution still has downstream missing-function-discovery issues (3 more PCs hit psx_unknown_dispatch on copy: 0xBFC09890, 0xBFC0989C, 0xBFC02918) plus likely additional bugs that softlock when those are seeded. Those remain for follow-up; this commit is the modal-close milestone. This is a BANDAID per user permission. The proper fix is to improve function discovery so missed functions like 0xBFC1A1BC are found automatically. Ghidra didn't see this function, and our transitive walk didn't reach it either. Tooling additions: - psx_unknown_dispatch_record() ring buffer + unknown_dispatch_log debug command. Replaces the prior file-based miss log per CLAUDE.md §3 (no log files, ever). Always-on; queryable summary (per-target counts) or tail (last N entries with addr/phys/ra/a0/a1). - WTRACE_MAX_RANGES bumped from 16 -> 64 (boot defaults were crowding out investigative arms). - DirtyRamBlockLogEntry +a0/a1 fields, ring CAP 16K -> 4M (previous 28ms eviction made retroactive press-window analysis impossible). Diagnostic scripts (kept): tools/_unknown_dispatch.py — query unknown_dispatch_log tools/_dispatch_check_v3.py — was a PC ever dispatched (RAM->ROM map) tools/_dispatch_tail.py — last N dispatched targets tools/_freeze_diag2.py — softlock investigator Co-Authored-By: Claude Opus 4.7 (1M context) --- generated/SCPH1001_dispatch.c | 74 +- generated/SCPH1001_full.c | 785 +++++++++++++++++++++- recompiler/seeds/phase2_ghidra_seeds.json | 9 +- runtime/src/debug_server.c | 157 +++++ runtime/src/traps.c | 24 +- tools/_freeze_diag2.py | 38 ++ tools/_unknown_dispatch.py | 38 ++ 7 files changed, 1102 insertions(+), 23 deletions(-) create mode 100644 tools/_freeze_diag2.py create mode 100644 tools/_unknown_dispatch.py diff --git a/generated/SCPH1001_dispatch.c b/generated/SCPH1001_dispatch.c index 779a4f64..2e5fd915 100644 --- a/generated/SCPH1001_dispatch.c +++ b/generated/SCPH1001_dispatch.c @@ -1,7 +1,7 @@ /* AUTO-GENERATED by psxrecomp-bios --emit-full. DO NOT EDIT. * * BIOS SHA256: 71af94d1e47a68c11e8fdb9f8368040601514a42a5a399cda48c7d3bff1e99d3 - * Dispatch entries: 4354 + * Dispatch entries: 4388 */ #include "cpu_state.h" @@ -1767,6 +1767,40 @@ extern void func_1FC1A17C(CPUState* cpu); extern void func_1FC1A17C_cont_BFC1A18C(CPUState* cpu); extern void func_1FC1A19C(CPUState* cpu); extern void func_1FC1A19C_cont_BFC1A1AC(CPUState* cpu); +extern void func_1FC1A1BC(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A1DC(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A1E4(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A1F0(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A1F8(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A204(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A20C(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A218(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A220(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A22C(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A234(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A240(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A248(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A254(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A25C(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A268(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A270(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A27C(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A284(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A290(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2B8(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2C0(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2CC(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2D4(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2E0(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2E8(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A2F0(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A300(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A310(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A320(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A378(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A380(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A394(CPUState* cpu); +extern void func_1FC1A1BC_cont_BFC1A3A8(CPUState* cpu); extern void func_1FC1A3B8(CPUState* cpu); extern void func_1FC1A414(CPUState* cpu); extern void func_1FC1A420(CPUState* cpu); @@ -4380,7 +4414,7 @@ typedef struct { PsxRecompFunc func; } DispatchEntry; -static const DispatchEntry dispatch_table[4354] = { +static const DispatchEntry dispatch_table[4388] = { { 0x00000500u, func_00000500 }, { 0x00000510u, func_00000510 }, { 0x00000520u, func_00000520 }, @@ -6130,6 +6164,40 @@ static const DispatchEntry dispatch_table[4354] = { { 0x1FC1A18Cu, func_1FC1A17C_cont_BFC1A18C }, { 0x1FC1A19Cu, func_1FC1A19C }, { 0x1FC1A1ACu, func_1FC1A19C_cont_BFC1A1AC }, + { 0x1FC1A1BCu, func_1FC1A1BC }, + { 0x1FC1A1DCu, func_1FC1A1BC_cont_BFC1A1DC }, + { 0x1FC1A1E4u, func_1FC1A1BC_cont_BFC1A1E4 }, + { 0x1FC1A1F0u, func_1FC1A1BC_cont_BFC1A1F0 }, + { 0x1FC1A1F8u, func_1FC1A1BC_cont_BFC1A1F8 }, + { 0x1FC1A204u, func_1FC1A1BC_cont_BFC1A204 }, + { 0x1FC1A20Cu, func_1FC1A1BC_cont_BFC1A20C }, + { 0x1FC1A218u, func_1FC1A1BC_cont_BFC1A218 }, + { 0x1FC1A220u, func_1FC1A1BC_cont_BFC1A220 }, + { 0x1FC1A22Cu, func_1FC1A1BC_cont_BFC1A22C }, + { 0x1FC1A234u, func_1FC1A1BC_cont_BFC1A234 }, + { 0x1FC1A240u, func_1FC1A1BC_cont_BFC1A240 }, + { 0x1FC1A248u, func_1FC1A1BC_cont_BFC1A248 }, + { 0x1FC1A254u, func_1FC1A1BC_cont_BFC1A254 }, + { 0x1FC1A25Cu, func_1FC1A1BC_cont_BFC1A25C }, + { 0x1FC1A268u, func_1FC1A1BC_cont_BFC1A268 }, + { 0x1FC1A270u, func_1FC1A1BC_cont_BFC1A270 }, + { 0x1FC1A27Cu, func_1FC1A1BC_cont_BFC1A27C }, + { 0x1FC1A284u, func_1FC1A1BC_cont_BFC1A284 }, + { 0x1FC1A290u, func_1FC1A1BC_cont_BFC1A290 }, + { 0x1FC1A2B8u, func_1FC1A1BC_cont_BFC1A2B8 }, + { 0x1FC1A2C0u, func_1FC1A1BC_cont_BFC1A2C0 }, + { 0x1FC1A2CCu, func_1FC1A1BC_cont_BFC1A2CC }, + { 0x1FC1A2D4u, func_1FC1A1BC_cont_BFC1A2D4 }, + { 0x1FC1A2E0u, func_1FC1A1BC_cont_BFC1A2E0 }, + { 0x1FC1A2E8u, func_1FC1A1BC_cont_BFC1A2E8 }, + { 0x1FC1A2F0u, func_1FC1A1BC_cont_BFC1A2F0 }, + { 0x1FC1A300u, func_1FC1A1BC_cont_BFC1A300 }, + { 0x1FC1A310u, func_1FC1A1BC_cont_BFC1A310 }, + { 0x1FC1A320u, func_1FC1A1BC_cont_BFC1A320 }, + { 0x1FC1A378u, func_1FC1A1BC_cont_BFC1A378 }, + { 0x1FC1A380u, func_1FC1A1BC_cont_BFC1A380 }, + { 0x1FC1A394u, func_1FC1A1BC_cont_BFC1A394 }, + { 0x1FC1A3A8u, func_1FC1A1BC_cont_BFC1A3A8 }, { 0x1FC1A3B8u, func_1FC1A3B8 }, { 0x1FC1A414u, func_1FC1A414 }, { 0x1FC1A420u, func_1FC1A420 }, @@ -8757,7 +8825,7 @@ void psx_dispatch(CPUState* cpu, uint32_t addr) { for (;;) { cpu->pc = 0; uint32_t phys = normalize(addr); - int lo = 0, hi = 4354 - 1; + int lo = 0, hi = 4388 - 1; int found = 0; while (lo <= hi) { int mid = (lo + hi) / 2; diff --git a/generated/SCPH1001_full.c b/generated/SCPH1001_full.c index 575b7cc5..cc9001b0 100644 --- a/generated/SCPH1001_full.c +++ b/generated/SCPH1001_full.c @@ -1,7 +1,7 @@ /* AUTO-GENERATED by psxrecomp-bios --emit-full. DO NOT EDIT. * * BIOS SHA256: 71af94d1e47a68c11e8fdb9f8368040601514a42a5a399cda48c7d3bff1e99d3 - * Functions: 1272 + * Functions: 1273 */ #include "cpu_state.h" @@ -562,6 +562,7 @@ void func_1FC1A11C(CPUState* cpu); void func_1FC1A15C(CPUState* cpu); void func_1FC1A17C(CPUState* cpu); void func_1FC1A19C(CPUState* cpu); +void func_1FC1A1BC(CPUState* cpu); void func_1FC1A3B8(CPUState* cpu); void func_1FC1A414(CPUState* cpu); void func_1FC1A420(CPUState* cpu); @@ -80753,6 +80754,621 @@ label_BFC1A1AC: return; } +void func_1FC1A1BC(CPUState* cpu) { + debug_server_log_call_entry(0x1FC1A1BCu); + if (cpu->pc != 0) { + uint32_t _cont = cpu->pc; + cpu->pc = 0; + switch (_cont) { + case 0xBFC1A1DCu: goto label_BFC1A1DC; + case 0xBFC1A1E4u: goto label_BFC1A1E4; + case 0xBFC1A1F0u: goto label_BFC1A1F0; + case 0xBFC1A1F8u: goto label_BFC1A1F8; + case 0xBFC1A204u: goto label_BFC1A204; + case 0xBFC1A20Cu: goto label_BFC1A20C; + case 0xBFC1A218u: goto label_BFC1A218; + case 0xBFC1A220u: goto label_BFC1A220; + case 0xBFC1A22Cu: goto label_BFC1A22C; + case 0xBFC1A234u: goto label_BFC1A234; + case 0xBFC1A240u: goto label_BFC1A240; + case 0xBFC1A248u: goto label_BFC1A248; + case 0xBFC1A254u: goto label_BFC1A254; + case 0xBFC1A25Cu: goto label_BFC1A25C; + case 0xBFC1A268u: goto label_BFC1A268; + case 0xBFC1A270u: goto label_BFC1A270; + case 0xBFC1A27Cu: goto label_BFC1A27C; + case 0xBFC1A284u: goto label_BFC1A284; + case 0xBFC1A290u: goto label_BFC1A290; + case 0xBFC1A2B8u: goto label_BFC1A2B8; + case 0xBFC1A2C0u: goto label_BFC1A2C0; + case 0xBFC1A2CCu: goto label_BFC1A2CC; + case 0xBFC1A2D4u: goto label_BFC1A2D4; + case 0xBFC1A2E0u: goto label_BFC1A2E0; + case 0xBFC1A2E8u: goto label_BFC1A2E8; + case 0xBFC1A2F0u: goto label_BFC1A2F0; + case 0xBFC1A300u: goto label_BFC1A300; + case 0xBFC1A310u: goto label_BFC1A310; + case 0xBFC1A320u: goto label_BFC1A320; + case 0xBFC1A378u: goto label_BFC1A378; + case 0xBFC1A380u: goto label_BFC1A380; + case 0xBFC1A394u: goto label_BFC1A394; + case 0xBFC1A3A8u: goto label_BFC1A3A8; + default: break; + } + } + int psx_taken_BFC1A1CC = 0; + int psx_taken_BFC1A2F0 = 0; + int psx_taken_BFC1A300 = 0; + int psx_taken_BFC1A310 = 0; + int psx_taken_BFC1A320 = 0; + int psx_taken_BFC1A334 = 0; + int psx_taken_BFC1A33C = 0; + int psx_taken_BFC1A344 = 0; + int psx_taken_BFC1A34C = 0; + int psx_taken_BFC1A358 = 0; + int psx_taken_BFC1A360 = 0; + int psx_taken_BFC1A384 = 0; + int psx_taken_BFC1A398 = 0; +label_BFC1A1BC: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(6u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1BC: 3C0100F0 lui $at, 0xF0 */ + cpu->gpr[1] = 0x00F00000u; + /* 0xBFC1A1C0: 342100F0 ori $at, $at, 0xF0 */ + cpu->gpr[1] = cpu->gpr[1] | 0xF0u; + /* 0xBFC1A1C4: 27BDFFE8 addiu $sp, $sp, -24 */ + cpu->gpr[29] = (uint32_t)((int32_t)cpu->gpr[29] + (-24)); + /* 0xBFC1A1C8: 00817024 and $t6, $a0, $at */ + cpu->gpr[14] = cpu->gpr[4] & cpu->gpr[1]; + /* 0xBFC1A1CC: 11C00076 beq $t6, $zero, 0xBFC1A3A8 */ + uint32_t psx_brA_BFC1A1CC = cpu->gpr[14]; uint32_t psx_brB_BFC1A1CC = cpu->gpr[0]; + psx_taken_BFC1A1CC = (psx_brA_BFC1A1CC == psx_brB_BFC1A1CC); + /* 0xBFC1A1D0: AFBF0014 sw $ra, 20($sp) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[29] + (20)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A1D0u); return; } g_debug_last_store_pc = 0xBFC1A1D0u; cpu->write_word(psx_addr, cpu->gpr[31]); } + if (psx_taken_BFC1A1CC) goto label_BFC1A3A8; +label_BFC1A1D4: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1D4: 0C00F928 jal 0xB003E4A0 */ + /* 0xBFC1A1D8: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x800321DCu; + psx_dispatch(cpu, 0x8003E4A0u); +label_BFC1A1DC: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1DC: 0C011997 jal 0xB004665C */ + /* 0xBFC1A1E0: 2404000A addiu $a0, $zero, 10 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (10)); + cpu->gpr[31] = 0x800321E4u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A1E4: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1E4: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A1E8: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A1EC: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x800321F0u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A1F0: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1F0: 0C011997 jal 0xB004665C */ + /* 0xBFC1A1F4: 2404000B addiu $a0, $zero, 11 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (11)); + cpu->gpr[31] = 0x800321F8u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A1F8: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A1F8: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A1FC: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A200: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032204u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A204: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A204: 0C011997 jal 0xB004665C */ + /* 0xBFC1A208: 2404000C addiu $a0, $zero, 12 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (12)); + cpu->gpr[31] = 0x8003220Cu; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A20C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A20C: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A210: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A214: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032218u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A218: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A218: 0C011997 jal 0xB004665C */ + /* 0xBFC1A21C: 2404000D addiu $a0, $zero, 13 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (13)); + cpu->gpr[31] = 0x80032220u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A220: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A220: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A224: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A228: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x8003222Cu; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A22C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A22C: 0C011997 jal 0xB004665C */ + /* 0xBFC1A230: 2404006E addiu $a0, $zero, 110 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (110)); + cpu->gpr[31] = 0x80032234u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A234: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A234: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A238: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A23C: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032240u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A240: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A240: 0C011997 jal 0xB004665C */ + /* 0xBFC1A244: 2404006F addiu $a0, $zero, 111 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (111)); + cpu->gpr[31] = 0x80032248u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A248: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A248: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A24C: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A250: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032254u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A254: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A254: 0C011997 jal 0xB004665C */ + /* 0xBFC1A258: 24040011 addiu $a0, $zero, 17 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (17)); + cpu->gpr[31] = 0x8003225Cu; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A25C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A25C: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A260: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A264: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032268u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A268: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A268: 0C011997 jal 0xB004665C */ + /* 0xBFC1A26C: 24040012 addiu $a0, $zero, 18 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (18)); + cpu->gpr[31] = 0x80032270u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A270: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A270: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A274: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A278: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x8003227Cu; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A27C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A27C: 0C011997 jal 0xB004665C */ + /* 0xBFC1A280: 24040013 addiu $a0, $zero, 19 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (19)); + cpu->gpr[31] = 0x80032284u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A284: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A284: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A288: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A28C: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x80032290u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A290: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(10u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A290: 3C0F8008 lui $t7, 0x8008 */ + cpu->gpr[15] = 0x80080000u; + /* 0xBFC1A294: 8DEF9E24 lw $t7, -25052($t7) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[15] + (-25052)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A294u); return; } cpu->gpr[15] = cpu->read_word(psx_addr); } + /* 0xBFC1A298: 3C19800F lui $t9, 0x800F */ + cpu->gpr[25] = 0x800F0000u; + /* 0xBFC1A29C: 000FC0C0 sll $t8, $t7, 3 */ + cpu->gpr[24] = cpu->gpr[15] << 3u; + /* 0xBFC1A2A0: 030FC023 subu $t8, $t8, $t7 */ + cpu->gpr[24] = cpu->gpr[24] - cpu->gpr[15]; + /* 0xBFC1A2A4: 0018C280 sll $t8, $t8, 10 */ + cpu->gpr[24] = cpu->gpr[24] << 10u; + /* 0xBFC1A2A8: 273986A8 addiu $t9, $t9, -31064 */ + cpu->gpr[25] = (uint32_t)((int32_t)cpu->gpr[25] + (-31064)); + /* 0xBFC1A2AC: 03192021 addu $a0, $t8, $t9 */ + cpu->gpr[4] = cpu->gpr[24] + cpu->gpr[25]; + /* 0xBFC1A2B0: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A2B4: 240503FE addiu $a1, $zero, 1022 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (1022)); + cpu->gpr[31] = 0x800322B8u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A2B8: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2B8: 0C011997 jal 0xB004665C */ + /* 0xBFC1A2BC: 24040004 addiu $a0, $zero, 4 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (4)); + cpu->gpr[31] = 0x800322C0u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A2C0: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2C0: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A2C4: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A2C8: 24050004 addiu $a1, $zero, 4 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (4)); + cpu->gpr[31] = 0x800322CCu; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A2CC: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2CC: 0C011997 jal 0xB004665C */ + /* 0xBFC1A2D0: 24040005 addiu $a0, $zero, 5 */ + cpu->gpr[4] = (uint32_t)((int32_t)cpu->gpr[0] + (5)); + cpu->gpr[31] = 0x800322D4u; + psx_dispatch(cpu, 0x8004665Cu); +label_BFC1A2D4: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2D4: 00402021 addu $a0, $v0, $zero */ + cpu->gpr[4] = cpu->gpr[2] + cpu->gpr[0]; + /* 0xBFC1A2D8: 0C011294 jal 0xB0044A50 */ + /* 0xBFC1A2DC: 24050005 addiu $a1, $zero, 5 */ + cpu->gpr[5] = (uint32_t)((int32_t)cpu->gpr[0] + (5)); + cpu->gpr[31] = 0x800322E0u; + psx_dispatch(cpu, 0x80044A50u); +label_BFC1A2E0: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2E0: 0C01195D jal 0xB0046574 */ + /* 0xBFC1A2E4: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x800322E8u; + psx_dispatch(cpu, 0x80046574u); +label_BFC1A2E8: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2E8: 0C011934 jal 0xB00464D0 */ + /* 0xBFC1A2EC: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x800322F0u; + psx_dispatch(cpu, 0x800464D0u); +label_BFC1A2F0: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2F0: 10000019 beq $zero, $zero, 0xBFC1A358 */ + uint32_t psx_brA_BFC1A2F0 = cpu->gpr[0]; uint32_t psx_brB_BFC1A2F0 = cpu->gpr[0]; + psx_taken_BFC1A2F0 = (psx_brA_BFC1A2F0 == psx_brB_BFC1A2F0); + /* 0xBFC1A2F4: 2401000A addiu $at, $zero, 10 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (10)); + if (psx_taken_BFC1A2F0) goto label_BFC1A358; +label_BFC1A2F8: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A2F8: 0C00C857 jal 0xB003215C */ + /* 0xBFC1A2FC: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032300u; + psx_dispatch(cpu, 0x8003215Cu); +label_BFC1A300: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A300: 10000011 beq $zero, $zero, 0xBFC1A348 */ + uint32_t psx_brA_BFC1A300 = cpu->gpr[0]; uint32_t psx_brB_BFC1A300 = cpu->gpr[0]; + psx_taken_BFC1A300 = (psx_brA_BFC1A300 == psx_brB_BFC1A300); + /* 0xBFC1A304: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A300) goto label_BFC1A348; +label_BFC1A308: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A308: 0C00C85F jal 0xB003217C */ + /* 0xBFC1A30C: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032310u; + psx_dispatch(cpu, 0x8003217Cu); +label_BFC1A310: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A310: 1000000D beq $zero, $zero, 0xBFC1A348 */ + uint32_t psx_brA_BFC1A310 = cpu->gpr[0]; uint32_t psx_brB_BFC1A310 = cpu->gpr[0]; + psx_taken_BFC1A310 = (psx_brA_BFC1A310 == psx_brB_BFC1A310); + /* 0xBFC1A314: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A310) goto label_BFC1A348; +label_BFC1A318: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A318: 0C00C867 jal 0xB003219C */ + /* 0xBFC1A31C: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032320u; + psx_dispatch(cpu, 0x8003219Cu); +label_BFC1A320: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A320: 10000009 beq $zero, $zero, 0xBFC1A348 */ + uint32_t psx_brA_BFC1A320 = cpu->gpr[0]; uint32_t psx_brB_BFC1A320 = cpu->gpr[0]; + psx_taken_BFC1A320 = (psx_brA_BFC1A320 == psx_brB_BFC1A320); + /* 0xBFC1A324: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A320) goto label_BFC1A348; +label_BFC1A328: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(5u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A328: 3C088006 lui $t0, 0x8006 */ + cpu->gpr[8] = 0x80060000u; + /* 0xBFC1A32C: 8D086BB8 lw $t0, 27576($t0) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[8] + (27576)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A32Cu); return; } cpu->gpr[8] = cpu->read_word(psx_addr); } + /* 0xBFC1A330: 24010004 addiu $at, $zero, 4 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (4)); + /* 0xBFC1A334: 1101FFF0 beq $t0, $at, 0xBFC1A2F8 */ + uint32_t psx_brA_BFC1A334 = cpu->gpr[8]; uint32_t psx_brB_BFC1A334 = cpu->gpr[1]; + psx_taken_BFC1A334 = (psx_brA_BFC1A334 == psx_brB_BFC1A334); + /* 0xBFC1A338: 24010005 addiu $at, $zero, 5 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (5)); + if (psx_taken_BFC1A334) goto label_BFC1A2F8; +label_BFC1A33C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A33C: 1101FFF2 beq $t0, $at, 0xBFC1A308 */ + uint32_t psx_brA_BFC1A33C = cpu->gpr[8]; uint32_t psx_brB_BFC1A33C = cpu->gpr[1]; + psx_taken_BFC1A33C = (psx_brA_BFC1A33C == psx_brB_BFC1A33C); + /* 0xBFC1A340: 24010006 addiu $at, $zero, 6 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (6)); + if (psx_taken_BFC1A33C) goto label_BFC1A308; +label_BFC1A344: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(1u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A344: 1101FFF4 beq $t0, $at, 0xBFC1A318 */ + uint32_t psx_brA_BFC1A344 = cpu->gpr[8]; uint32_t psx_brB_BFC1A344 = cpu->gpr[1]; + psx_taken_BFC1A344 = (psx_brA_BFC1A344 == psx_brB_BFC1A344); +label_BFC1A348: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(1u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A348: 3C018006 lui $at, 0x8006 */ + cpu->gpr[1] = 0x80060000u; + if (psx_taken_BFC1A344) goto label_BFC1A318; +label_BFC1A34C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A34C: 10000006 beq $zero, $zero, 0xBFC1A368 */ + uint32_t psx_brA_BFC1A34C = cpu->gpr[0]; uint32_t psx_brB_BFC1A34C = cpu->gpr[0]; + psx_taken_BFC1A34C = (psx_brA_BFC1A34C == psx_brB_BFC1A34C); + /* 0xBFC1A350: AC206BBC sw $zero, 27580($at) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[1] + (27580)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A350u); return; } g_debug_last_store_pc = 0xBFC1A350u; cpu->write_word(psx_addr, cpu->gpr[0]); } + if (psx_taken_BFC1A34C) goto label_BFC1A368; +label_BFC1A354: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(1u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A354: 2401000A addiu $at, $zero, 10 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (10)); +label_BFC1A358: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A358: 1041FFF3 beq $v0, $at, 0xBFC1A328 */ + uint32_t psx_brA_BFC1A358 = cpu->gpr[2]; uint32_t psx_brB_BFC1A358 = cpu->gpr[1]; + psx_taken_BFC1A358 = (psx_brA_BFC1A358 == psx_brB_BFC1A358); + /* 0xBFC1A35C: 2401000B addiu $at, $zero, 11 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (11)); + if (psx_taken_BFC1A358) goto label_BFC1A328; +label_BFC1A360: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A360: 1041FFF9 beq $v0, $at, 0xBFC1A348 */ + uint32_t psx_brA_BFC1A360 = cpu->gpr[2]; uint32_t psx_brB_BFC1A360 = cpu->gpr[1]; + psx_taken_BFC1A360 = (psx_brA_BFC1A360 == psx_brB_BFC1A360); + /* 0xBFC1A364: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A360) goto label_BFC1A348; +label_BFC1A368: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(4u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A368: 3C048006 lui $a0, 0x8006 */ + cpu->gpr[4] = 0x80060000u; + /* 0xBFC1A36C: 8C846BB8 lw $a0, 27576($a0) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[4] + (27576)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A36Cu); return; } cpu->gpr[4] = cpu->read_word(psx_addr); } + /* 0xBFC1A370: 0C011913 jal 0xB004644C */ + /* 0xBFC1A374: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032378u; + psx_dispatch(cpu, 0x8004644Cu); +label_BFC1A378: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A378: 0C01195D jal 0xB0046574 */ + /* 0xBFC1A37C: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032380u; + psx_dispatch(cpu, 0x80046574u); +label_BFC1A380: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A380: 2401FFFF addiu $at, $zero, -1 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (-1)); + /* 0xBFC1A384: 10410006 beq $v0, $at, 0xBFC1A3A0 */ + uint32_t psx_brA_BFC1A384 = cpu->gpr[2]; uint32_t psx_brB_BFC1A384 = cpu->gpr[1]; + psx_taken_BFC1A384 = (psx_brA_BFC1A384 == psx_brB_BFC1A384); + /* 0xBFC1A388: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A384) goto label_BFC1A3A0; +label_BFC1A38C: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A38C: 0C01195D jal 0xB0046574 */ + /* 0xBFC1A390: 00000000 nop */ + /* nop */ + cpu->gpr[31] = 0x80032394u; + psx_dispatch(cpu, 0x80046574u); +label_BFC1A394: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(3u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A394: 2401FFFF addiu $at, $zero, -1 */ + cpu->gpr[1] = (uint32_t)((int32_t)cpu->gpr[0] + (-1)); + /* 0xBFC1A398: 1441FFFC bne $v0, $at, 0xBFC1A38C */ + uint32_t psx_brA_BFC1A398 = cpu->gpr[2]; uint32_t psx_brB_BFC1A398 = cpu->gpr[1]; + psx_taken_BFC1A398 = (psx_brA_BFC1A398 != psx_brB_BFC1A398); + /* 0xBFC1A39C: 00000000 nop */ + /* nop */ + if (psx_taken_BFC1A398) goto label_BFC1A38C; +label_BFC1A3A0: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(2u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A3A0: 0C00ED40 jal 0xB003B500 */ + /* 0xBFC1A3A4: 00002021 addu $a0, $zero, $zero */ + cpu->gpr[4] = cpu->gpr[0] + cpu->gpr[0]; + cpu->gpr[31] = 0x800323A8u; + psx_dispatch(cpu, 0x8003B500u); +label_BFC1A3A8: +#ifdef PSX_ENABLE_BLOCK_CYCLES + psx_advance_cycles(4u); +#endif + psx_check_interrupts(cpu); + /* 0xBFC1A3A8: 8FBF0014 lw $ra, 20($sp) */ + { uint32_t psx_addr = (uint32_t)((int32_t)cpu->gpr[29] + (20)); if (psx_addr & 3u) { psx_unaligned_access(cpu, psx_addr, 0xBFC1A3A8u); return; } cpu->gpr[31] = cpu->read_word(psx_addr); } + /* 0xBFC1A3AC: 27BD0018 addiu $sp, $sp, 24 */ + cpu->gpr[29] = (uint32_t)((int32_t)cpu->gpr[29] + (24)); + /* 0xBFC1A3B0: 03E00008 jr $ra */ + /* 0xBFC1A3B4: 00000000 nop */ + /* nop */ + return; +} + void func_1FC1A3B8(CPUState* cpu) { debug_server_log_call_entry(0x1FC1A3B8u); int psx_taken_BFC1A3F8 = 0; @@ -221830,7 +222446,7 @@ void func_1FC02324(CPUState* cpu) { } -/* --- 3082 continuation wrappers for jal/jalr return routing --- */ +/* --- 3115 continuation wrappers for jal/jalr return routing --- */ void func_00000C80_cont_BFC107C0(CPUState* cpu) { cpu->pc = 0xBFC107C0u; @@ -227877,6 +228493,171 @@ void func_1FC1A19C_cont_BFC1A1AC(CPUState* cpu) { func_1FC1A19C(cpu); } +void func_1FC1A1BC_cont_BFC1A1DC(CPUState* cpu) { + cpu->pc = 0xBFC1A1DCu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A1E4(CPUState* cpu) { + cpu->pc = 0xBFC1A1E4u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A1F0(CPUState* cpu) { + cpu->pc = 0xBFC1A1F0u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A1F8(CPUState* cpu) { + cpu->pc = 0xBFC1A1F8u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A204(CPUState* cpu) { + cpu->pc = 0xBFC1A204u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A20C(CPUState* cpu) { + cpu->pc = 0xBFC1A20Cu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A218(CPUState* cpu) { + cpu->pc = 0xBFC1A218u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A220(CPUState* cpu) { + cpu->pc = 0xBFC1A220u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A22C(CPUState* cpu) { + cpu->pc = 0xBFC1A22Cu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A234(CPUState* cpu) { + cpu->pc = 0xBFC1A234u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A240(CPUState* cpu) { + cpu->pc = 0xBFC1A240u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A248(CPUState* cpu) { + cpu->pc = 0xBFC1A248u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A254(CPUState* cpu) { + cpu->pc = 0xBFC1A254u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A25C(CPUState* cpu) { + cpu->pc = 0xBFC1A25Cu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A268(CPUState* cpu) { + cpu->pc = 0xBFC1A268u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A270(CPUState* cpu) { + cpu->pc = 0xBFC1A270u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A27C(CPUState* cpu) { + cpu->pc = 0xBFC1A27Cu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A284(CPUState* cpu) { + cpu->pc = 0xBFC1A284u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A290(CPUState* cpu) { + cpu->pc = 0xBFC1A290u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2B8(CPUState* cpu) { + cpu->pc = 0xBFC1A2B8u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2C0(CPUState* cpu) { + cpu->pc = 0xBFC1A2C0u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2CC(CPUState* cpu) { + cpu->pc = 0xBFC1A2CCu; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2D4(CPUState* cpu) { + cpu->pc = 0xBFC1A2D4u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2E0(CPUState* cpu) { + cpu->pc = 0xBFC1A2E0u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2E8(CPUState* cpu) { + cpu->pc = 0xBFC1A2E8u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A2F0(CPUState* cpu) { + cpu->pc = 0xBFC1A2F0u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A300(CPUState* cpu) { + cpu->pc = 0xBFC1A300u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A310(CPUState* cpu) { + cpu->pc = 0xBFC1A310u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A320(CPUState* cpu) { + cpu->pc = 0xBFC1A320u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A378(CPUState* cpu) { + cpu->pc = 0xBFC1A378u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A380(CPUState* cpu) { + cpu->pc = 0xBFC1A380u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A394(CPUState* cpu) { + cpu->pc = 0xBFC1A394u; + func_1FC1A1BC(cpu); +} + +void func_1FC1A1BC_cont_BFC1A3A8(CPUState* cpu) { + cpu->pc = 0xBFC1A3A8u; + func_1FC1A1BC(cpu); +} + void func_1FC1A430_cont_BFC1A470(CPUState* cpu) { cpu->pc = 0xBFC1A470u; func_1FC1A430(cpu); diff --git a/recompiler/seeds/phase2_ghidra_seeds.json b/recompiler/seeds/phase2_ghidra_seeds.json index d88e9055..9fe8317e 100644 --- a/recompiler/seeds/phase2_ghidra_seeds.json +++ b/recompiler/seeds/phase2_ghidra_seeds.json @@ -1,7 +1,7 @@ { "schema": "psxrecomp-v4 phase2 seeds", - "source": "generated/ghidra_function_starts.json + phase1c seeds + dispatch_miss_seeds + preserved manual + audit_2026_05_04 trampoline dispatch-miss + audit_2026_05_04 trampoline dispatch-miss", - "seed_count": 1063, + "source": "generated/ghidra_function_starts.json + phase1c seeds + dispatch_miss_seeds + preserved manual + audit_2026_05_04 trampoline dispatch-miss + audit_2026_05_04 trampoline dispatch-miss + modal_stub_2026_05_05", + "seed_count": 1064, "seeds": [ { "address": "0xBFC00000", @@ -1728,6 +1728,11 @@ "label": "ghidra_BFC1A19C", "rationale": "Ghidra function start" }, + { + "address": "0xBFC1A1BC", + "label": "modal_stub_dispatch_miss", + "rationale": "Runtime dispatch miss confirmed 2026-05-05: psx_unknown_dispatch hit during YES/NO COPY confirm modal CROSS press. Beetle wtrace+fntrace shows this PC fires on modal close via JAL caller_pc=0x8004673C. Ghidra function discovery missed it. BANDAID per user permission — should be replaced by an improved heuristic that catches this gap." + }, { "address": "0xBFC1A430", "label": "ghidra_BFC1A430", diff --git a/runtime/src/debug_server.c b/runtime/src/debug_server.c index ff4080af..89b01a65 100644 --- a/runtime/src/debug_server.c +++ b/runtime/src/debug_server.c @@ -169,6 +169,59 @@ void debug_server_log_sio_write(uint32_t addr, uint32_t value, uint8_t width) { static uint32_t s_dispatch_ring[DISPATCH_TRACE_CAP]; static uint64_t s_dispatch_seq = 0; +/* ---- Unknown-dispatch ring buffer ---- + * Always-on log of every psx_dispatch target that doesn't resolve to a + * generated function AND doesn't match any trampoline pattern in + * traps.c. Used to identify functions the recompiler missed. + * 64K entries × 32 bytes = 2 MB. Replaces the prior file-based log. */ +#define UNKNOWN_DISPATCH_CAP (1 << 16) +typedef struct { + uint64_t seq; + uint32_t addr; + uint32_t phys; + uint32_t ra; + uint32_t a0; + uint32_t a1; + uint32_t frame; + uint32_t pad; +} UnknownDispatchEntry; +static UnknownDispatchEntry s_unknown_ring[UNKNOWN_DISPATCH_CAP]; +static uint64_t s_unknown_seq = 0; +/* Per-target hit count — bounded set, ~N unique targets typically. */ +#define UNKNOWN_UNIQUE_CAP 1024 +typedef struct { uint32_t phys; uint64_t count; } UnknownUniqueEntry; +static UnknownUniqueEntry s_unknown_unique[UNKNOWN_UNIQUE_CAP]; +static int s_unknown_unique_count = 0; + +void psx_unknown_dispatch_record(uint32_t addr, uint32_t phys, + uint32_t ra, uint32_t a0, uint32_t a1) +{ + uint64_t seq = s_unknown_seq++; + UnknownDispatchEntry *e = &s_unknown_ring[seq & (UNKNOWN_DISPATCH_CAP - 1u)]; + e->seq = seq; + e->addr = addr; + e->phys = phys; + e->ra = ra; + e->a0 = a0; + e->a1 = a1; + e->frame = (uint32_t)s_frame_count; + /* Per-target count (linear probe). */ + uint32_t idx = (phys >> 2) % UNKNOWN_UNIQUE_CAP; + for (int i = 0; i < UNKNOWN_UNIQUE_CAP; i++) { + uint32_t slot = (idx + i) % UNKNOWN_UNIQUE_CAP; + if (s_unknown_unique[slot].phys == phys) { + s_unknown_unique[slot].count++; + return; + } + if (s_unknown_unique[slot].phys == 0) { + s_unknown_unique[slot].phys = phys; + s_unknown_unique[slot].count = 1; + s_unknown_unique_count++; + return; + } + } +} + /* Unique dispatch set — tracks every unique function address ever dispatched. * Simple hash set with linear probing. */ #define DISPATCH_UNIQUE_CAP 4096 @@ -638,6 +691,7 @@ static const char *json_get_str(const char *json, const char *key, char *out, int out_sz); static uint32_t hex_to_u32(const char *s); static void handle_dirty_ram_stats(int id, const char *json); +static void send_err(int id, const char *msg); void debug_server_send_fmt(const char *fmt, ...); #define send_fmt debug_server_send_fmt @@ -764,6 +818,108 @@ static void handle_dirty_block_log(int id, const char *json) free(out); } +/* ---- unknown_dispatch_log: dump psx_unknown_dispatch hits ---- + * Two modes: + * - default: per-target count summary (sorted by hit count) + * - tail=N: most recent N entries from the ring */ +static void handle_unknown_dispatch_log(int id, const char *json) +{ + int tail = json_get_int(json, "tail", 0); + + if (tail > 0) { + if (tail > (int)UNKNOWN_DISPATCH_CAP) tail = UNKNOWN_DISPATCH_CAP; + uint64_t total = s_unknown_seq; + uint64_t avail = (total < UNKNOWN_DISPATCH_CAP) ? total : UNKNOWN_DISPATCH_CAP; + if ((uint64_t)tail > avail) tail = (int)avail; + + const size_t BUF_SZ = 2 * 1024 * 1024; + char *out = (char *)malloc(BUF_SZ); + if (!out) { send_err(id, "oom"); return; } + size_t pos = 0; + pos += snprintf(out + pos, BUF_SZ - pos, + "{\"id\":%d,\"ok\":true,\"total\":%llu,\"unique\":%d," + "\"tail\":%d,\"entries\":[", + id, (unsigned long long)total, s_unknown_unique_count, tail); + uint64_t start = total - (uint64_t)tail; + for (int i = 0; i < tail; i++) { + UnknownDispatchEntry *e = + &s_unknown_ring[(start + i) & (UNKNOWN_DISPATCH_CAP - 1u)]; + if (pos > BUF_SZ - 256) break; + pos += snprintf(out + pos, BUF_SZ - pos, + "%s{\"seq\":%llu,\"addr\":\"0x%08X\",\"phys\":\"0x%08X\"," + "\"ra\":\"0x%08X\",\"a0\":\"0x%08X\",\"a1\":\"0x%08X\"," + "\"frame\":%u}", + i == 0 ? "" : ",", + (unsigned long long)e->seq, + e->addr, e->phys, e->ra, e->a0, e->a1, e->frame); + } + pos += snprintf(out + pos, BUF_SZ - pos, "]}\n"); + debug_server_send_line(out); + free(out); + return; + } + + /* Summary mode: per-phys hit count, sorted descending. */ + const size_t BUF_SZ = 2 * 1024 * 1024; + char *out = (char *)malloc(BUF_SZ); + if (!out) { send_err(id, "oom"); return; } + size_t pos = 0; + pos += snprintf(out + pos, BUF_SZ - pos, + "{\"id\":%d,\"ok\":true,\"total\":%llu,\"unique\":%d," + "\"summary\":[", + id, (unsigned long long)s_unknown_seq, s_unknown_unique_count); + /* Sort by count desc — small cap, simple selection. */ + int emitted = 0; + for (int round = 0; round < UNKNOWN_UNIQUE_CAP && emitted < 200; round++) { + uint64_t best_count = 0; + int best_idx = -1; + for (int i = 0; i < UNKNOWN_UNIQUE_CAP; i++) { + if (s_unknown_unique[i].phys == 0) continue; + if (s_unknown_unique[i].count > best_count) { + best_count = s_unknown_unique[i].count; + best_idx = i; + } + } + if (best_idx < 0) break; + if (pos > BUF_SZ - 128) break; + pos += snprintf(out + pos, BUF_SZ - pos, + "%s{\"phys\":\"0x%08X\",\"count\":%llu}", + emitted == 0 ? "" : ",", + s_unknown_unique[best_idx].phys, + (unsigned long long)s_unknown_unique[best_idx].count); + s_unknown_unique[best_idx].count = 0; /* mark consumed */ + emitted++; + } + /* Restore: re-walk the ring once to rebuild counts. Cheap since cap is 1024. */ + /* (We mutated counts above to drive selection; rebuild by replaying the + * ring's most recent UNKNOWN_DISPATCH_CAP entries.) */ + for (int i = 0; i < UNKNOWN_UNIQUE_CAP; i++) s_unknown_unique[i].phys = 0; + s_unknown_unique_count = 0; + uint64_t avail = (s_unknown_seq < UNKNOWN_DISPATCH_CAP) ? s_unknown_seq : UNKNOWN_DISPATCH_CAP; + uint64_t start = s_unknown_seq - avail; + for (uint64_t i = 0; i < avail; i++) { + UnknownDispatchEntry *e = &s_unknown_ring[(start + i) & (UNKNOWN_DISPATCH_CAP - 1u)]; + uint32_t phys = e->phys; + uint32_t idx = (phys >> 2) % UNKNOWN_UNIQUE_CAP; + for (int k = 0; k < UNKNOWN_UNIQUE_CAP; k++) { + uint32_t slot = (idx + k) % UNKNOWN_UNIQUE_CAP; + if (s_unknown_unique[slot].phys == phys) { + s_unknown_unique[slot].count++; + break; + } + if (s_unknown_unique[slot].phys == 0) { + s_unknown_unique[slot].phys = phys; + s_unknown_unique[slot].count = 1; + s_unknown_unique_count++; + break; + } + } + } + pos += snprintf(out + pos, BUF_SZ - pos, "]}\n"); + debug_server_send_line(out); + free(out); +} + /* ---- SIO write PC tracer dump ---- * Returns the most recent N entries from the SIO PC tracer ring. * Optional addr_lo/addr_hi (hex-string) filter restricts to a single @@ -3012,6 +3168,7 @@ static const CmdEntry s_commands[] = { { "sio_pc_trace", handle_sio_pc_trace }, { "dirty_ram_stats", handle_dirty_ram_stats }, { "dirty_block_log", handle_dirty_block_log }, + { "unknown_dispatch_log", handle_unknown_dispatch_log }, { "card_txn_dump", handle_card_txn_dump }, { "card_read_summary", handle_card_read_summary }, { "card_read_summary_reset", handle_card_read_summary_reset }, diff --git a/runtime/src/traps.c b/runtime/src/traps.c index e0af0f8e..1474f798 100644 --- a/runtime/src/traps.c +++ b/runtime/src/traps.c @@ -359,22 +359,14 @@ void psx_unknown_dispatch(CPUState* cpu, uint32_t addr, uint32_t phys) { } { - /* Log dispatch miss to file and continue (collect all misses). */ - static FILE* miss_log = NULL; - static int miss_count = 0; - if (!miss_log) miss_log = fopen("psx_dispatch_misses.txt", "w"); - if (miss_log) { - fprintf(miss_log, "0x%08X phys=0x%08X ra=0x%08X t9=0x%08X pc=0x%08X\n", - addr, phys, cpu->gpr[31], cpu->gpr[25], cpu->pc); - fflush(miss_log); - } - miss_count++; - if (miss_count > 100000) { - fprintf(stderr, "DISPATCH MISS limit reached (%d misses). See psx_dispatch_misses.txt\n", miss_count); - fflush(stderr); - if (miss_log) fclose(miss_log); - exit(1); - } + /* Always-on ring buffer of dispatch misses. Queryable via the + * `unknown_dispatch_log` debug command. Replaces the prior + * file-based log per CLAUDE.md §3. */ + extern void psx_unknown_dispatch_record(uint32_t addr, uint32_t phys, + uint32_t ra, uint32_t a0, + uint32_t a1); + psx_unknown_dispatch_record(addr, phys, cpu->gpr[31], + cpu->gpr[4], cpu->gpr[5]); /* Return without executing — function is a no-op. */ cpu->pc = 0; } diff --git a/tools/_freeze_diag2.py b/tools/_freeze_diag2.py new file mode 100644 index 00000000..f6d3f35f --- /dev/null +++ b/tools/_freeze_diag2.py @@ -0,0 +1,38 @@ +"""Diagnose freeze: ping debug server, then dump unknown_dispatch_log +and dispatch_tail to see what's looping/hanging.""" +import socket, json, sys +def call(payload, port=4370, timeout=5): + s = socket.create_connection(('127.0.0.1', port), timeout=timeout) + s.sendall((json.dumps(dict(payload, id=1))+'\n').encode()) + buf = b'' + while True: + c = s.recv(1<<20) + if not c: break + buf += c + try: return json.loads(buf.decode()) + except: pass + raise RuntimeError("incomplete") + +try: + print("=== ping ===") + print(call({'cmd':'ping'}, timeout=2)) +except Exception as e: + print(f"DEBUG SERVER UNRESPONSIVE: {e}") + sys.exit(1) + +# It's responsive — diagnose +print("\n=== unknown_dispatch_log summary ===") +r = call({'cmd':'unknown_dispatch_log'}) +print(f"total={r.get('total')} unique={r.get('unique')}") +for s in r.get('summary', [])[:10]: + print(f" {s['phys']}: {s['count']:>8}") + +print("\n=== unknown_dispatch_log tail (last 20) ===") +r = call({'cmd':'unknown_dispatch_log','tail':20}) +for e in r.get('entries', [])[-20:]: + print(f" seq={e['seq']:>5} phys={e['phys']} ra={e['ra']} a0={e['a0']} a1={e['a1']} frame={e['frame']}") + +print("\n=== dispatch_tail (last 50 dispatched targets) ===") +r = call({'cmd':'dispatch_tail','count':50}) +for a in r.get('addrs', [])[-50:]: + print(f" {a}") diff --git a/tools/_unknown_dispatch.py b/tools/_unknown_dispatch.py new file mode 100644 index 00000000..d42b7e57 --- /dev/null +++ b/tools/_unknown_dispatch.py @@ -0,0 +1,38 @@ +"""Query psx-runtime for psx_unknown_dispatch hits since boot. +Default: per-target summary sorted by hit count. +With tail=N: most recent N entries from the ring.""" +import socket, json, sys +def call(payload): + s = socket.create_connection(('127.0.0.1', 4370), timeout=10) + s.sendall((json.dumps(dict(payload, id=1))+'\n').encode()) + buf = b'' + while True: + c = s.recv(1<<20) + if not c: break + buf += c + try: return json.loads(buf.decode()) + except: pass + raise RuntimeError("incomplete") + +if len(sys.argv) > 1 and sys.argv[1] == 'tail': + r = call({'cmd':'unknown_dispatch_log','tail':50}) + print(f"total={r.get('total')} unique={r.get('unique')} tail={r.get('tail')}") + for e in r.get('entries', [])[-30:]: + print(f" seq={e['seq']:>6} addr={e['addr']} phys={e['phys']} ra={e['ra']} a0={e['a0']} a1={e['a1']} frame={e['frame']}") +else: + r = call({'cmd':'unknown_dispatch_log'}) + print(f"=== Unknown dispatch summary ===") + print(f"total hits={r.get('total')} unique targets={r.get('unique')}\n") + summary = r.get('summary', []) + for s in summary[:30]: + phys = s['phys'] + cnt = s['count'] + # Highlight modal-investigation PCs + marker = '' + for known_phys, lbl in [ + (0x1FC1A1BC, 'MODAL STUB'), + (0x1FC1A300, 'cursor_mirror2 writer 2'), + ]: + if int(phys, 16) == known_phys: + marker = f' <-- {lbl}' + print(f" {phys}: {cnt:>8}{marker}")