Files
psxrecomp/tools/_dispatch_check_v3.py
Matthew Stanley 7a12a0baac two-process refactor: replace embedded oracle with independent psx-runtime + psx-beetle
Switches diagnostic methodology from a single binary running both backends
in lockstep (psx-beetleoracle.exe) to two independent processes:
  psx-runtime.exe (recomp only, port 4370)
  psx-beetle.exe  (Beetle libretro only, port 4380)

Both expose the same JSON wire protocol for the common debug commands
(read_ram, press, set_input, clear_input, pad_status, screenshot_file,
wtrace_*, fntrace_* on Beetle). Cross-process comparison is done by
querying both ports from a tool, NOT by sharing input or memory.

Why: the embedded-oracle setup required keyboard input to drive both
backends in lockstep. Once their state diverged, the same keypress
drove them to different screens and "compare on the same press" became
unreliable. Two independent processes lets each backend be navigated
to its own state and queried on its own timeline.

Removed:
  - runtime/src/beetle_psx_bridge.cpp (cannibalised into beetle_libretro.cpp)
  - runtime/src/duckstation_bridge.cpp
  - runtime/src/psx_oracle_cmds.c
  - runtime/src/psx_oracle_stub.c
  - runtime/include/psx_oracle_backend.h
  - psx-beetleoracle and psx-dsoracle cmake targets
  - 22 dual-backend tools (emu_read_ram / find_first_divergence / etc)

Added:
  - runtime/src/beetle_main.cpp     (SDL window + libretro driver + keyboard)
  - runtime/src/beetle_libretro.cpp (libretro callbacks + wtrace/fntrace/sio rings)
  - runtime/src/beetle_debug_server.c (TCP server, port 4380, same wire protocol)
  - psx-beetle cmake target

Also bumps tooling caps surfaced during modal investigation:
  - DIRTY_RAM_BLOCK_LOG_CAP: 16K -> 4M (28ms eviction -> ~7s retention)
  - WTRACE_MAX_RANGES:        16  -> 64  (boot defaults filled the prior cap)
  - DirtyRamBlockLogEntry: added a0/a1 fields for richer dispatch context

CLAUDE.md section 16 rewritten for the new methodology. New memory note
locks the direction so future sessions don't reach for the deleted
embedded-oracle commands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:06:44 -07:00

56 lines
2.1 KiB
Python

"""Re-run dispatch_check with ROM-physical addresses (subtract 0x80018000
from Beetle RAM PCs to get recomp dispatch target)."""
import socket, json
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")
# Shell relocation: RAM 0x80030000 = ROM 0x1FC18000
# Verified: RAM 0x800394B0 = ROM 0x1FC214B0
SHELL_RAM_BASE = 0x80030000
SHELL_ROM_BASE = 0x1FC18000
def ram_to_rom(ram):
if ram >= SHELL_RAM_BASE:
return (ram - SHELL_RAM_BASE) + SHELL_ROM_BASE
return ram # non-shell, leave unchanged
CANDIDATES = [
(0x8003A700, 'main_state=4 entry candidate'),
(0x8003A710, 'main_state=4 writer PC (inside func)'),
(0x8003A6F8, 'main_state=4 writer-2-instructions earlier'),
(0x80046470, 'SetStateForWidget alt entry'),
(0x80046468, 'SetStateForWidget body'),
(0x8004644C, 'SetStateForWidget candidate'),
(0x80039840, 'coordinator dispatch table internal'),
(0x800394B0, 'coordinator entry (CONFIRMED RAM=ROM map)'),
(0x800321BC, 'modal stub'),
(0x800397B0, 'case-A coordinator close'),
(0x8003C640, 'cursor_mirror2 writer 1'),
(0x80032300, 'cursor_mirror2 writer 2'),
(0x80032164, 'caller of cursor_mirror2 writer 1 (Beetle)'),
(0x80032174, 'caller of cursor_mirror2 writer 2 (Beetle)'),
(0x800465E0, 'caller of SetStateForWidget body (Beetle)'),
(0x80008A58, 'coord caller A'),
(0x80030558, 'coord caller B'),
(0x80031660, 'lookup caller'),
(0x80030534, 'coord parent'),
(0x80046664, 'lookup caller 2'),
(0x8003ACE4, 'cursor_mirror2 writer (group B PC)'),
]
print(f"=== Recomp dispatch_check — ROM-physical addresses ===")
print(f"{'RAM PC':<12} {'ROM PC':<12} {'found':<6} label")
for ram, lbl in CANDIDATES:
rom = ram_to_rom(ram)
r = call({'cmd':'dispatch_check','addr':f'0x{rom:08X}'})
found = r.get('found')
print(f"0x{ram:08X} 0x{rom:08X} {str(found):<6} {lbl}")