Files
psxrecomp/tools/decode_insn.py
T
Matthew Stanley 8e81afd111 fix: conditional branch fall-through + Tier 1 reverse debugger
Recompiler bug fix: full_function_emitter treated conditional branch
delay slots at function boundaries as fully resolved control flow,
suppressing the fall-through tail call for the "not taken" path.
This broke 15 cross-function fall-throughs across the BIOS, most
critically the find-free-EvCB-slot function (BFC11800) whose search
loop was silently skipped — causing OpenEvent to return garbage handles
(0xF100E1E8) instead of valid slot indices (0xF1000000..0xF1000005).

Fix: only suppress fall-through for unconditional flow (j/jr/jal/jalr/rfe).
Conditional branches (beq/bne/blez/bgtz/bltz/bgez) now always emit
`cpu->pc = next_addr; return;` for the not-taken path.

Also included:
- Tier 1 reverse debugger: 1M-entry write trace ring (32 MB),
  64K-entry MMIO trace ring (2 MB), 8-slot multi-range address
  filtering, function attribution via g_debug_current_func_addr.
  6 new TCP commands: wtrace_add/del/ranges/stats, mmio_dump/clear.
- 3 new dispatch seeds for functions exposed by fall-through fix
  (SIO epilogue, exception chain walker, GTE init).
- Diagnostic tools: analyze_sio_trace, decode_insn, decode_jt, mmio_tally.
- Pattern 5 trampoline fix + PLAN.md Phase 4 status update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 14:23:09 -07:00

37 lines
1.2 KiB
Python

#!/usr/bin/env python3
"""Decode MIPS instructions from hex."""
import struct
hex_str = "020004240c0000000800e00300000000a0000a2408004001"
data = bytes.fromhex(hex_str)
addr = 0x8005AA10
for i in range(0, len(data), 4):
w = struct.unpack('<I', data[i:i+4])[0]
op = (w >> 26) & 0x3F
rs = (w >> 21) & 0x1F
rt = (w >> 16) & 0x1F
rd = (w >> 11) & 0x1F
imm = w & 0xFFFF
simm = imm if imm < 0x8000 else imm - 0x10000
target26 = (w & 0x03FFFFFF) << 2
func = w & 0x3F
pc = addr + i
if op == 0x09: # ADDIU
print(f" {pc:08X}: addiu ${rt}, ${rs}, {simm} (0x{w:08X})")
elif op == 0x0F: # LUI
print(f" {pc:08X}: lui ${rt}, 0x{imm:04X} (0x{w:08X})")
elif op == 0x00 and func == 0x08: # JR
print(f" {pc:08X}: jr ${rs} (0x{w:08X})")
elif op == 0x00 and func == 0x00 and w == 0: # NOP
print(f" {pc:08X}: nop (0x{w:08X})")
elif op == 0x03: # JAL
jtarget = (pc & 0xF0000000) | target26
print(f" {pc:08X}: jal 0x{jtarget:08X} (0x{w:08X})")
elif op == 0x02: # J
jtarget = (pc & 0xF0000000) | target26
print(f" {pc:08X}: j 0x{jtarget:08X} (0x{w:08X})")
else:
print(f" {pc:08X}: ??? op={op} 0x{w:08X}")