Commit Graph

6 Commits

Author SHA1 Message Date
Alex Vanderveen fe403e6ce1 rollback patches 2026-07-31 17:14:35 -04:00
Alex Vanderveen 31015ceab1 feat: launcher polish and recomp-net lobby netplay
Wire MotK-style lobby (recomp-net submodule, WS client, match_caps),
netplay delay-sync, and launcher UX so host sim settings stay aligned
across peers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 21:37:57 -07:00
Matthew Stanley 4f80d22096 fix(sched): defer in-exception thread switch to a clean block leader (memcard fix #2)
The Ape Escape "Checking MEMORY CARD" thread-switch smear: a genuine in-exception
ChangeThread detected deep in nested host dispatch commits a poisoned TCB context
(stale resume-PC latch ahead of the live GPRs) -> the resumed consumer faults on
a smeared jumptable index (DISPATCH FATAL).

Fix #2 (user-agreed architecture): don't honor the switch at the poisoned nested
point. Resume the outgoing thread transparently at its OWN EPC, record the switch
as pending, and honor it at the next block leader where that thread is running
with a materialized resume PC -- re-saving it cleanly there. Do NOT require the
outermost STATIC dispatch boundary: the memcard consumer lives permanently inside
the nested dirty-RAM interpreter and never reaches it; the scheduler landing
already resets the nested dispatch/call-unit counters on the longjmp, same as the
immediate-switch path.

- interrupts.c: the kind-30 escape splits into immediate (outermost / toggle-off
  / no clean resume PC) vs deferred; new honor hook at the top of
  psx_check_interrupts; always-on thread_trace kinds 31 (defer) / 32 (honor) /
  33 (stale-drop). The deferred branch restores the outgoing thread's clean
  GPRs/HI/LO/SR AND cpu->pc (the in-exception RFE had left cpu->pc at the target).
- traps.c: psx_sched_save_context / set_current_tcb / current_tcb exports over
  the scheduler's private TCB accessors.
- A/B toggle PSX_DEFER_SWITCH (default ON); =0 forces baseline immediate switch.

Validated (LLE + HLE, ring-verified): converts the smear DISPATCH-FATAL into
forward progress -- the card driver now reads 108 blocks. A/B (PSX_DEFER_SWITCH=0)
proves the fix is SOUND: the remaining stall (SIO IRQ bit 7 masked in I_MASK, card
read never completing) reproduces IDENTICALLY with the fix off, so it is a
SEPARATE, pre-existing SIO-mask bug -- the next blocker, not this fix's residual.
Goal (file-select showing File 1-4) NOT yet reached.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 12:29:53 -07:00
Matthew Stanley 582aeccdac bios: HLE as a first-class swappable tier (gbarecomp model) + HLE boot shell-skip
USER PIVOT 2026-07-02 (CLAUDE.md §0 amendment included): psxrecomp now
carries an opt-in High-Level Emulation backend alongside LLE. LLE (the
recompiled BIOS) stays the default, the reference implementation, and the
correctness/timing oracle; every service HLE does not implement falls
through to LLE, so HLE is never load-bearing beyond what it covers.

Mechanism: full_function_emitter.cpp emits a null-by-default hook
g_psx_bios_hle_hook consulted at the top of every psx_dispatch_impl
iteration, on the pre-normalize physical address, BEFORE any backend
(game image / dirty-RAM / static table) claims the target. A handled
call resumes at $ra through the trampoline's existing return/tail
contract. NULL (default) = pure LLE, dispatch-identical. Regenerating
BIOS+game images is required (emitter change).

v1 call-HLE (runtime/src/bios_hle.c): the B0 event family — DeliverEvent
(incl. callback dispatch with the kernel-true $ra 0x1720), OpenEvent,
CloseEvent, TestEvent, EnableEvent, DisableEvent — each ground-truthed
instruction-by-instruction against the SCPH1001 kernel disassembly
(0xBFC11644..0xBFC11A84) and operating on the REAL guest EvCB table
([0x120]/[0x124], stride 0x1C). WaitEvent/threads/pads/card/A0/C0 fall
through to LLE. Cycle charges are documented approximations; LLE remains
the timing oracle. No-stubs stands.

Boot HLE: with the tier on (and no keep-intro opt-out) the hook one-shot
intercepts the first dispatch of the BIOS shell entry (RAM 0x30000 —
LoadRunShell's indirect call always routes through the dispatcher), so
BIOS Main() proceeds straight to SYSTEM.CNF + game EXE load with kernel
state built entirely by the real recompiled kernel init, unpaced (boot
turbo) until game handoff. This REPLACES the fast_boot snapshot
capture/restore; fast_boot=true now aliases the boot-skip alone.

Selection: [runtime] bios_hle / bios_hle_keep_intro (+ settings.toml
bios_hle mirror), PSX_BIOS_HLE / PSX_BIOS_HLE_KEEP_INTRO env overrides,
startup banner bios_backend=/bios_boot=. The PSX_HLE_SCHEDULER spike is
folded in as the tier's standing subsystem replacement: default from
[runtime] hle_scheduler via psx_hle_scheduler_set_default, env wins.

Observability: always-on 16K-entry HLE ring (route LLE-fallthrough /
HLE / boot-skip per record) + hle_dump TCP command (TCP_COMMANDS.md).

VALIDATED on Tomba (build-wt): LLE pass byte-identical behavior (real
intro, card check, save/load OK); HLE pass boots shell-less, TestEvent/
DeliverEvent route HLE, ChangeTh/ReturnFromException/OpenTh/CloseTh and
the card stack fall through to LLE, save/load OK (user-driven).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:27:33 -07:00
Matthew Stanley 0f7d0f1645 spike(scheduler): deterministic TCB scheduler LIVE + HLE/LLE toggle (minimal A+)
Replace the non-deterministic host-fiber thread-switch bridge with a deterministic
TCB scheduler (HLE_SCHEDULER_CARVEOUT_PLAN.md steps 2-8, minimal "A+" scope):

- psx_scheduler_run (traps.c): outer trampoline wrapping the top-level dispatch
  (main.cpp calls it instead of bare psx_dispatch). setjmp(g_scheduler_jmpbuf);
  restore current TCB / dispatch / on-escape reset g_psx_dispatch_depth +
  g_psx_call_bail; boot/pre-TCB runs raw cpu->pc; one-level switch-back safety
  net; fail-closed psx_is_dispatchable on every restored EPC.
- psx_request_thread_switch: save yielder ctx (resume=$ra), repoint
  dword_108->entry, longjmp to the scheduler. No fibers, no cpu->pc=0 signal.
  Fires only with in_exception==0, so it never unwinds a live exception_jmpbuf
  frame (the in-exception RFE path stays LLE/intact).
- sched_escape_ring (step 8) for always-on observability.
- Hidden toggle PSX_HLE_SCHEDULER (default 1=HLE, 0=legacy fibers), read once;
  psx_change_thread branches on it; startup banner prints the mode. The
  trampoline is transparent in LLE mode. Fiber funcs kept compiled-but-dead.

Validated live (HLE): thread1 trace shows ONLY the new TCB-switch events and
ZERO fiber kinds 10/11/13 — the per-frame fiber recreate is eliminated. Builds
clean. Freeze NOT resolved: same 0x800CD3F8 wedge persists (separate upstream
root, per ChatGPT Q5). Keep HLE default until the upstream cause is fixed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 15:52:51 -07:00
Matthew Stanley ab8ed36b47 spike(scheduler): step 1-2 scaffolding — structured-escape types + jmpbuf + fail-closed guard (INERT)
First step of the deterministic TCB cooperative-thread scheduler carve-out
(HLE_SCHEDULER_CARVEOUT_PLAN.md §9, ChatGPT-approved "A+"). Replaces the
non-deterministic host-fiber bridge (confirmed root of the MMX6 cutscene freeze:
thread1's fiber recreate-per-frame, pc=0 silent exit).

- runtime/include/psx_scheduler.h: psx_run_reason_t (CONTINUE / YIELD_TO_TCB /
  RESUME_CURRENT / GUEST_EXIT / FATAL) + psx_sched_escape_t, the design rationale
  (pure-TCB BIOS scheduler, no stack switch; guest state lives only in
  CPUState/RAM/TCB), and the load-bearing invariant.
- traps.c: g_scheduler_jmpbuf + g_sched_escape definitions + psx_is_dispatchable
  (fail-closed on pc==0 and the exception sentinel — the known-bad resume PCs the
  old pc=0 pathology produced).

INERT: nothing calls these yet; psx_change_thread_fiber (host-fiber bridge) is
still authoritative. Builds clean (traps.c only, no game-C regen). No behavior
change. Next: outer scheduler loop + route ChangeThread/RFE through structured
escapes, then remove cpu->pc=0 + fiber recreation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 14:42:43 -07:00