mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
534dcd5df3bbfe4585f8024b0032615d962f843a
22 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
81b449d7c9 |
Merge V8:2 framework branch (b9f9ba23) into master for render passes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
b210446460 |
Support native-wide presentation diagnostics and verified external mod media
Checkpoint exact NCLIP and cull-scale code generation, overlay ABI 25, draw-area clipping, timeline and presented-image rings, mod counters, hotkey matching and savestate messages. Add canonical external ROM/disc verification with immutable plugin-scoped snapshots. Focused recompiler/runtime validation: 16 tests passed. |
||
|
|
82a835b20b |
frame_fingerprint reset_on_load for A/B runs from one savestate
frame_fingerprint reset_on_load=1 restarts the rolling hashes and the ring when the next savestate load completes, so two runs that load the same state (for example with and without a presentation mod) compare frame by frame from the same guest point. Debug tooling only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e6ce5006b4 |
docs: move root and stale docs into docs/ and docs/internal/
The repository root carried seven markdown files that were not onboarding
material, plus two that had been superseded by the code they described. This
sorts them: reader-facing docs to docs/, working notes to docs/internal/, and
the two superseded ones merged into the docs that replaced them.
Moved to docs/: WIDESCREEN.md, ENHANCEMENTS.md, TCP_COMMANDS.md
Moved to docs/internal/: PRINCIPLES.md, ISSUES.md, DEBUG.md, GTE_LM_FIX.md,
and from docs/: bios-hardening.md, overlay-status.md,
overlay-plan.md, overlay-recompilation-design.md,
overlay-discovery.md, TOMBA2_EXC_CONSULT_RESPONSE.md,
CASE_A_AOT_GAP.md, audit_inventory.md
Moved to docs/internal/upstream/: UPSTREAM_2026-08-20.md
The root keeps only what belongs there: README.md, CONTRIBUTING.md, LICENSE,
CLAUDE.md, THIRD_PARTY_ATTRIBUTION.md, RELEASE_NOTES.md, the dotfiles and
psxrecomp_cli.py.
MERGES
SPLITGEN_MIGRATION.md folded into docs/BUILDING.md as "Split generated C". Its
migration instructions were stale in a way that mattered: it told every game
repo to hand-edit its CMakeLists and add a file(GLOB ...) over
<serial>_full*.c, but runtime/runtime.cmake now does that itself. GEN_FULL_GLOB
is a multi-value argument of psxrecomp_add_game_runtime(); the loop at
runtime.cmake:1985 makes each pattern absolute against CMAKE_CURRENT_SOURCE_DIR,
expands it with file(GLOB), and concatenates the hits into
GAME_GENERATED_FULL_C. So a title names the pattern and gets however many shards
a regeneration produced. The rewritten section describes that, the two-step
fallback when the globs match nothing (GEN_FULL_FALLBACK, else <serial>_full.c
derived from the dispatch marker by substituting _dispatch.c), and the one
caveat the code actually has: that file(GLOB) is plain, not CONFIGURE_DEPENDS,
so a regeneration which changes the shard COUNT needs a re-configure to be seen.
psxrecomp-toml-readme.md folded into docs/GAME_PROJECT_SETUP.md as "EXE-only
autofill (psxrecomp-toml)", placed after "Disc autofill (probe_disc.py)" and
before "Project Studio" so the two autofill paths sit together. Its documented
flags were checked against the usage text in recompiler/src/main_toml.cpp:28-42
and against the argument parser at :150-165 -- all seven options match with no
drift, so the flag list is reproduced as-is. Added a pointer that probe_disc.py
is preferable when a cue exists, since that tool does the same EXE-header work
plus disc identity and netplay gates.
FUNCTIONAL FIXES
tools/gen_tcp_commands.py wrote to REPO/"TCP_COMMANDS.md". After the move that
path does not exist, so the generator would have created a new stray root file
and --check would have failed against it forever. Retargeted to
REPO/"docs"/"TCP_COMMANDS.md", along with the seven docstring and message
strings that name the path.
Running it surfaced two further problems, both fixed here:
* The doc was genuinely stale -- pre-existing drift, not introduced by this
commit (the moved file is byte-identical to origin/master, and no
debug-server command table is touched here). Four commands registered since
the last regeneration were missing from the index -- cdrom_timing_dump,
savestate_status, ws_ui_groups, xprobe_watch -- and scanline had gained a
backend. Regenerated: 307 -> 311 commands, and the change is confined to the
AUTOGEN block (the hand-written head and tail are byte-identical to master).
tools/gen_tcp_commands.py --check now exits 0.
* DOC.write_text() has no newline argument, so Python translated every newline
to os.linesep. On Windows that rewrote all 585 lines of the file to CRLF and
turned a four-line index update into a whole-file diff -- measured: 589 CRLF
/ 0 LF after a run, against 0 CRLF / 585 LF in the repo. Now written through
an explicit newline="" handle, verified to leave the file at 0 CRLF.
runtime/include/debug_server.h:9 and runtime/src/debug_server.c:8 cited "TCP.md
and DEBUG.md". TCP.md has never existed in this repo under that name; both now
name docs/TCP_COMMANDS.md and docs/internal/DEBUG.md.
LINK AND REFERENCE FIXES
Every inbound reference to a moved file was located by grepping each basename
across the whole tracked tree, not just the markdown. Markdown hrefs in
README.md, CONTRIBUTING.md, docs/ARCHITECTURE.md, docs/COMPILING_OVERLAYS.md,
docs/AOT_OVERLAY_PLAN.md, docs/RELOCATION_MANIFEST_FORMAT.md,
docs/config_schema.md, docs/OVERLAY_XREF.md, docs/TCP_COMMANDS.md and several
docs/internal/ files now point at the new locations; where two files became
siblings under docs/internal/ the path was shortened rather than lengthened
(bios-hardening.md's reference to overlay-discovery.md, for instance).
docs/COMPILING_OVERLAYS.md's "in this folder" phrasing was wrong once two of the
three files it listed moved, so it now names internal/ explicitly.
24 source-comment mentions of ENHANCEMENTS.md sections G1.x across 19 files
(recompiler, runtime, cmake) were retargeted to docs/ENHANCEMENTS.md with the
section numbers untouched. docs/SHADOW_ENHANCEMENTS.md is a DIFFERENT file and
was deliberately excluded.
20 rationale strings citing docs/CASE_A_AOT_GAP.md across the four
recompiler/seeds/*.json files were updated. Done as a byte-level substring
replacement rather than a JSON round-trip: two of those files are stored with
CRLF endings and two with LF, and re-serializing them reformatted 5,700 lines.
The byte-level version changes exactly 20 lines and each file still parses.
References that look similar but point elsewhere were deliberately left alone,
and are worth naming so a future pass does not "fix" them:
* "recomp-template PRINCIPLES.md" / "NES recomp template PRINCIPLES.md" in
CLAUDE.md:43, docs/SHADOW_ENHANCEMENTS.md:28,
docs/internal/HLE_SCHEDULER_CARVEOUT_PLAN.md:5,
runtime/src/debug_server.c:4934 and tools/parity_diff.py:8 are a different
repository's file. Only the five that mean this repo's PRINCIPLES.md were
updated.
* Every remaining bare ISSUES.md mention is a GAME repo's tracker
(MegaManX6Recomp 2/7/8/9, TombaRecomp 6), not this repo's.
* docs/disc-speed.md:4,54,56 and docs/internal/bios-hardening.md:5 name
overlay-discovery as a BRANCH, not a file, so no path applies.
INDEXES
README.md's "New here?" table gains rows for docs/WIDESCREEN.md,
docs/ENHANCEMENTS.md and docs/TCP_COMMANDS.md. docs/internal/README.md gains
sections indexing all fourteen documents that moved in, plus an "Upstream
contributor reviews" section describing upstream/ and the new sweep file, plus a
"Removed" bullet for CYCLE_TIMING_ARCH.md (deleted in the previous commit)
pointing at FAITHFUL_TIMING_PLAN.md, CYCLE_MODEL_BEETLE.md and
PRECISE_IRQ_SLICE.md -- following the SLJIT_PERSIST_CACHE.md precedent already
in that file.
docs/ENHANCEMENTS.md:7 claimed framework bugs live in "game repos' ISSUES.md
until a framework tracker exists". A framework tracker does exist; it now says
so and names the Beads epic.
VERIFICATION
A link checker was written to scan every tracked *.md for relative links,
resolving each against the tree being scanned. Baseline at origin/master: 129
files, 137 relative links, 3 broken. After both commits: 127 files, 159 relative
links, 3 broken -- the SAME three, all pre-existing and untouched here:
docs/DATA_SHARDS.md -> INSTANT_LOADS_PARKED.md (never existed)
docs/DATA_SHARDS.md -> INSTANT_LOADS_SPIKE2.md (never existed)
docs/NETPLAY.md -> ../lib/recomp-net/README.md (inside a submodule)
Zero new broken links. The checker's own coverage was checked against a raw grep
for markdown link openers: the 3-link difference is C++ lambdas inside code
blocks, correctly not treated as links.
Also verified: py_compile over all 113 tracked tools/*.py plus psxrecomp_cli.py;
all four seed JSONs still parse; the test-registration guard still reports 123
test files all registered; recompiler/tests/test_coverage_vault.py still passes;
and no file in this commit had its line endings flipped (checked mechanically
across all 50 modified files, after two files were caught and redone).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
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> |
||
|
|
e4e27f02b5 |
runtime: optimize MDEC FMV hot paths
Reconstruct the shareable pieces from PR #58 onto current master: add contiguous MDEC DMA input bursts, reduce per-pixel/per-byte MDEC output overhead, add sparse IDCT fast paths, and keep the MDEC activity stamp sane across rematches. Also quiet the heavy debug trace recorders while MDEC video is active so debug builds can query state without starving FMV playback. Regression testing was done with non-debug OpenGL builds across multiple FMV-heavy titles. Debug-tool FMV playback was also exercised with the quiet gate enabled. Co-authored-by: Alex Vanderveen <alex@technicallycomputers.ca> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
b85f10959b |
widescreen: pillarbox 2D-only scenes in native-wide; HUD corner re-anchor for tag titles; present ring
2D-only-scene classifier (fixes room/fall/title-card stretch, Tomba): - Native-wide's 2D-backdrop stretch fires wholesale in scenes whose background phase never ends (room interiors, sky-only falls), stretching the whole frame. Such scenes now present native 4:3 from the faithful canonical buffer (gpu_ws_present_native_43). - The world signal is DEEP UNTAGGED POLYGON OVERHANG: polys whose raw SX extent crosses >=24px past the canonical window, >=4 per frame, sustained 2+ consecutive frames. Lineage of rejected signals (each defeated by a real scene, census-evidenced): shaded-prim presence (title-card letter tiles are gouraud), GTE projection volume (task-jingle projects world-scale counts; title screen idles at 1680 verts), any-poly overhang (card letters slide in from off-screen), shallow overhang (jingle sparkles poke <=20px). Outdoor terrain measures 55 deep-overhang polys/frame vs 0-1 for every observed 2D scene/effect. - Scoped to sprite-tag titles: full_2d (MMX6) and gte_game_mode (Ape) classification is unchanged. Native-wide present invariant: - A game frame that cannot present wide (compositor fallback) pillarboxes 4:3 instead of stretching the canonical read across the wide window (all backends; squash mode still stretches by design). HUD corner re-anchoring for sprite-tag titles ([widescreen] nw_hud_corners): - Poly/line prims never shift (they are the world / tagged billboards); rect-family prims shift only when UNTAGGED — the proven hud_sprt_squash discriminator — so enabling nw_hud_corners is safe without a packet arena range. Observability (always-on, institutional): - present_ring: per-present classification ring (path, present width, game_mode, native_43, wide fallback, tag age, gte_verts, ovh_prims) for every backend; TCP "present_ring". Answers "why did this frame stretch" after the fact. - gpu_state ws block gains last_3d_frame, gte_verts, last_world3d_frame, ovh_prims, last_ovh_frame; GTE vert counting is now always-on. Input injection drives the full pad model: - set_input/press now resolve pad type like real sampling: injected d-pad drops a hybrid pad to digital (movement works), optional lx/ly/rx/ry stick override (0..255), type via the coherent request channel. Previously buttons-only: menus reacted, walking never did. Savestate honesty: - savestate_request_save/load return staged/refused; the TCP handler reports ok:false instead of silently acking loads it cannot perform (LLE host-fiber runs). Torn-restore reliability audit remains open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
01b4d91e8a |
WIP: forward-port Ape Escape framework (dev/ape-escape) onto master
Comprehensive 3-way merge of the dev/ape-escape branch into master for
the isolated wt/ape-escape worktree. Brought in every complementary ape
change automatically (dma.c, memory.c interrupt byte/half lanes,
function_analysis discovery, main_bios vector seeds, iso_reader
iso_sector_count, config_loader, crash-trace fields, headers). Resolved
the 13 conflicts by rule:
- CPS dispatch / recompiler (code_generator, full_function_emitter,
dirty_ram_interp, traps, main_psx) -> KEEP MASTER (evolved system).
- CD model (cdrom.c) -> take ape (the model that booted Ape).
- interrupts.c/.h -> reverted to MASTER (ape's interrupt-delivery is
dispatch-coupled; the merged Frankenstein stormed).
- sio/debug_server/freeze_heartbeat/main.cpp -> keep master (evolved).
- crash_trace.c -> master (ape freeze-dump fns omitted to avoid the
debug-ring cascade).
STATUS: does NOT boot yet. ape-cdrom + master-interrupts derails to
PC=0 at frame ~2092 (insta-close); ape-cdrom + ape-interrupts storms
(297M exception re-entries) at frame 2077. Root finding: ape's CD
anti-storm is coupled to ape's interrupt-delivery + call-depth + EPC
model, which master replaced with CPS continuation-passing, so the CD
subsystem does not forward-port as pure hardware simulation. Preserved
as the reference state for a design consult on bridging the two models.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
aa536b899c |
debug server: total send budget + serve-stall telemetry (root cause of 'attract degradation')
The two pre-fix attract-idle 'degradations' (2026-06-10 dumps ...393 and ...707) were observer interference, not guest bugs: - both wedge dumps show 8/8 main-thread stack samples inside WS2_32!send (same call site) — the main-thread-pumped server blocked sending to a trickle-draining client, throttling the loop to ~6 fps; - the 'frame counter reset to 0' was a second process instance (no reset path exists for s_frame_count or psx_cycle_count; dump ...707 has lower cycles than ...393); - the 'kernel-only dispatch loop' signature (0xB0/0x650, restore target 0x80068024, EPC 0x80000048, dispatch_count 0) is the normal Tomba title-attract idle pattern — identical in a healthy 60-min post-fix soak. Fix the loophole and make recurrence self-evident: - send_all_blocking gains a 15 s TOTAL budget per response (the 2 s SO_SNDTIMEO only bounded zero-progress chunks; a slow-but-alive client could throttle the emulator indefinitely while heartbeating the starvation watchdog). Over budget -> client dropped, runtime unharmed. - cumulative tcp_send_stall_ms + tcp_clients_dropped exported in the freeze heartbeat (top level + per-tick ring 'tcp_ms') and in every wedge/fatal dump header, so a TCP-throttled window is attributable at a glance. Documented in TCP_COMMANDS.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
834f440161 |
WIP: ape-fw title-LOAD debugging snapshot (uncommitted session work)
Captures in-progress Ape Escape framework + Tomba title-LOAD investigation: - recompiler/src/function_analysis.cpp: hardened is_bios_dispatch_thunk pass (never gut a li/jr candidate already inside a discovered function). - runtime: cdrom/dma/dirty_ram_interp/interrupts/sio/traps/debug_server + freeze_heartbeat + main.cpp debugging deltas; SIO card-protocol test updates. Snapshot commit to consolidate loose WIP onto dev/ape-escape; not a finished change. See handoff: title-LOAD black = card op-loop never delivering SwCARD spec 0x8000 completion event. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d62d51ba2f |
Ape Escape bring-up: attract demo now loads
Framework changes that get Ape Escape (USA) booting through to its attract/demo sequence. Captures the working state at this milestone. Runtime: - cdrom: read/seek + data-path fixes for disc streaming - dma / interrupts: channel + IRQ handling needed by the boot chain - dirty_ram_interp: expanded coverage for self-modifying / RAM handlers - sio, traps, crash_trace: supporting fixes - debug_server: probe/inspection commands used during bring-up Recompiler: - code_generator / full_function_emitter / function_analysis / main_psx: codegen fixes surfaced by the Ape Escape boot path Committed as-is (no further edits) since the build is in a known-good, demo-loading state. Branch: codex/ape-escape-support. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ec7e482691 |
Ape Escape support: framework WIP snapshot (safe haven)
Uncommitted framework work on codex/ape-escape-support reaching the post-boot DualShock-required screen. Recompiler codegen (code_generator, full_function_emitter, function_analysis, config_loader) + runtime (cdrom, sio, dirty_ram_interp, dma, iso_reader, mdec, gpu, memory, traps, debug_server, fntrace, freeze_heartbeat, psx_cycles) and headers. Committed as a restore point before rebuilding Tomba against this framework. Build dirs (recompiler/build-codex*) intentionally excluded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ec4306fbb3 |
mmx6 framework: CD/DMA/MDEC + codegen fixes (Tomba builds+plays, MMX6 boots to intro)
Framework work on codex/mmx6-support that makes Tomba build and play (title screen, 0 dispatch misses) and MMX6 boot through BIOS to its intro. Touches recompiler codegen (code_generator, function_analysis) and runtime CD-ROM/DMA/MDEC/GPU/SIO timing (cdrom, dma, mdec, gpu, psx_cycles, traps, fntrace, debug_server) + headers + runtime.cmake. Milestone snapshot for collapsing onto master. Build dir excluded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6f7fcdc89b |
Remove all psxrecomp-v4 naming — rename to psxrecomp throughout
The "v4" suffix was a holdover from iterative project restarts. There is now one psxrecomp; all identifiers, include guards, cmake variables, function names, log strings, schema tags, and tool paths drop the v4 suffix. Changes: - PSXRECOMP_V4_ROOT → PSXRECOMP_ROOT (cmake) - PSXRECOMP_V4_RUNTIME_SOURCES/_INCLUDE_DIRS/_BIOS_GENERATED → no V4 - psxrecomp_v4_add_runtime_target → psxrecomp_add_runtime_target - PSXRECOMP_V4_*_H include guards → PSXRECOMP_*_H - "psxrecomp-v4" log/window strings → "psxrecomp" - Schema version strings in recompiler JSON output - Tool script hardcoded absolute paths updated Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
fdbd2b515f |
runtime: cross-fiber longjmp fix + decouple vblank-present from MMIO read
Two distinct bugs were causing OPTIONS-black hard freezes after 12K-65K frames: 1. interrupts.c + traps.c: exception_jmpbuf is a single global. setjmp captures the running fiber, but longjmp may be requested from a different fiber via psx_exception_longjmp / psx_restore_state_escape during chain-handler dispatch. Cross-fiber longjmp restores RSP to the wrong stack while Win32 still tracks the calling fiber, corrupting fiber state until SwitchToFiber eventually hangs. Fix: track g_exception_owner_fiber at setjmp time. New deferred_exception_longjmp checks the current fiber; if it's not the owner, sets a pending flag and SwitchToFiber's back to the owner. psx_change_thread_fiber's post-SwitchToFiber path observes the flag and executes the longjmp on the correct stack. 2. gpu.c: gpu_read_gpustat fired gpu_vblank_tick() after 1000 polls, which invoked sdl_vblank_present (SDL_Delay -> Sleep) from inside an MMIO read code path. That meant recompiled MIPS spent wall time in Sleep deep inside the fiber call tree -- confusing to reason about and a contributor to fiber/longjmp interactions. Fix: synthetic VBLANK from a poll-storm only updates emulation state (LCF + I_STAT). The host-side render+sleep happens only at the proper cycle-paced VBLANK trigger in psx_check_interrupts. Also adds: dirty_block ring slice to the freeze auto-dump, Win32 main- thread stack capture for wedge_kind=1 hard freezes (SuspendThread + StackWalk64 + SymFromAddr), and dbghelp link. Validated: TombaRecomp psx-runtime ran 30+ minutes / 105K+ frames at OPTIONS with no hard freeze. Previous freezes consistently hit at 11900, 20493, and 64596 frames. Diagnostic tooling under tools/_options_session/ that produced this diagnosis is included. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
cf05a0ab1f |
runtime + recompiler: Tomba boot through BIOS into Whoopee Camp FMV
Recompiler — `recompiler/src/function_analysis.cpp` now stops a function's end_addr at its mapped `jr $ra` + delay slot instead of stretching through trailing data. Fixes Tomba's 0x80076DB0, a real 136-byte function that was being emitted as a psx_unknown_dispatch stub because data after it poisoned the boundary heuristic. `code_generator.cpp` emits `func_<next>(cpu); return;` as a tail call when a mid-function seed split leaves the physical fall-through in a different C function, plus a `debug_server_log_call_entry` at every function entry. `full_function_emitter.cpp` splits dispatch into `psx_dispatch_impl(cpu, addr, stop_addr)` with public `psx_dispatch` and new `psx_dispatch_call(cpu, addr, return_addr)` so JAL/JALR into RAM stubs can return cleanly without growing the native stack. Runtime — `runtime/src/dma.c`/`include/dma.h`/`src/memory.c` now expose `dma_write_masked()`; the 16-bit and 8-bit mmio paths route DICR/DPCR/CHCR partial writes through it so a partial DICR write no longer accidentally clears unrelated channels' pending IRQ flags, and CHCR only triggers DMA when the written mask actually includes the start bit. Unified `complete_transfer(ch)` across all channels, removed `prev_master_flag` edge detection. MDEC (`runtime/src/mdec.c`, `include/mdec.h`) gains a full debug surface: `MDECDebugState` snapshot, an always-on 4096-entry `MDECDebugEvent` ring with 11 event kinds (reset, ctrl_write, cmd_begin/done, decode_done, dma_in/out start/end, output_drained, read_underflow), and `mdec_state` / `mdec_trace` / `mdec_trace_clear` debug-server commands. DMA ch0/1 emit start/end events around MDEC transfers. CDROM (`runtime/src/cdrom.c`, `include/cdrom.h`) — read stream separated from one-shot pending state (`read_cmd`, `read_delay`, `start_read_stream`, `stop_read_stream`, `deliver_read_sector`); `cdrom_state`/`cdrom_trace` report the new fields. Thread/fiber tracing — `traps.c`'s Win32-fiber TCB save/restore now emits 12 thread-event kinds; new `ThreadTraceEntry` ring (64 K) plus `thread_trace` / `thread_trace_clear` debug-server commands report both live CPU regs and the target TCB's full saved register block. wtrace / mmio rings — `WriteTraceEntry` grew (cpu_pc, sp, v0/v1/a0-a3/ t0/t1); capacity 1 M -> 4 M. `MmioTraceEntry` grew (pc, cpu_pc, sp, a0-a3, sr, epc, i_stat, i_mask). Both dump commands accept `count`/`newest=1` for reverse iteration. `restore_trace` and `dirty_block_log` emit extended register fields (a2/a3/sp). Misc — `interrupts.c` polls debug-server every 16K checks so it stays responsive without a separate thread. `psx_runtime.h`'s `call_by_address` routes through `psx_dispatch_call`. Dirty-RAM interp JAL/JALR consult `psx_dispatch_game_compiled` when the game is wired in. iso_reader gains the entry points needed by the game disc path. New `tools/_tomba_probe.py` for port-4470 health checks. Generated — regenerated `SCPH1001_dispatch.c` against the new `psx_dispatch_impl` shape. ISSUES.md — opened Issue #3 (BIOS PS-logo glyph missing on the disc-detected screen, cosmetic). .gitignore — added `recompiler/build-asan*/`, `build-checked/`, `__pycache__/`. Validated end-to-end: BIOS boots, disc detected, Whoopee Camp FMV plays with audio. Frame count advances through ~40K frames without freezes. `unknown_dispatch_log.total = 0`. Remaining FMV cluster issues (1/4-size render, FMV-2 audio missing, no skip) tracked under TombaRecomp/ISSUES.md. Co-Authored-By: Codex (OpenAI) <noreply@openai.com> |
||
|
|
122dc49f42 | Fix BIOS memory card copy writes | ||
|
|
5b3c7dd08d |
phase4: freeze_check diagnostic + accumulated overnight infra
Today's session work
- runtime/src/debug_server.c: freeze_check TCP cmd snapshots all liveness
counters (PC, exception entries, exception_reentry_blocks, dirty_ram
blocks/insns, fn_entry total + top-K histogram, SIO IRQ pending +
countdown, sio_stat/i_stat/i_mask, mc_max_state) for tight-loop
diagnosis when the runtime hangs
- runtime/src/debug_server.c: wtrace slot 12 covering [0x72F0..0x72F4]
(data-byte counter); measured peak=1 confirming setup_data_phase resets
the counter mid-cycle
- runtime/src/interrupts.c: exception_entries_total + exception_reentry_blocks
counters + psx_get_freeze_diag accessor
- runtime/src/sio.c: sio_get_freeze_diag accessor for IRQ pacing internals
- memory entries: phase4_card_gate_setup_writes_2026_04_28 (refutes the
prior \"missing [0x7568+slot] clearer\" framing — setup functions write
LSB=0 directly), phase4_72f0_one_byte_per_vblank_2026_04_28 (peak=1
measurement)
Overnight session work bundled in
- runtime/src/dirty_ram_interp.{c,h}: small MIPS interpreter for
install-at-runtime kernel RAM stubs (Rule 18; e.g., SIO data-byte
handler the BIOS writes to RAM 0xCF0)
- recompiler/src/full_function_emitter.{cpp,h}: 3057 jal/jalr continuation
return labels added to dispatch table (continuation fix); branch
fall-through fix for conditional-branch delay slots
- recompiler/src/strict_translator.cpp: matching translator updates
- generated/: regenerated SCPH1001 dispatch + full C output reflecting
the recompiler changes
- runtime/include/debug_server.h, src/memory.c: card_txn ring + SIO IRQ
ring + EvCB walk ring + per-PC dirty_ram counters + always-on wtrace
coverage for [0x755A], [0x7514], [0x7528], [0x7520], [0x74A4],
[0x75C0..C8], [0x74B8..C0]
- recompiler/tests/, runtime/tests/: SIO/card protocol unit tests
- tools/: 60+ Python diagnostic scripts (chain_trace analysis, SIO trace
diff, EvCB walker, wtrace dumpers, etc.)
- docs/: psx_bios_disasm reference + dynamic_handler_install rationale
- OVERNIGHT_2026_04_28.md, SUMMARY_20260412_2.md: session logs
Phase 4 status (still blocked, root cause better understood)
- BIOS card chain runs through R-handlers correctly (chain_trace shows
R1..R11 cycling 26x); shell IS retriggering _card_read
- Install handler at ROM 0xBFC15F1C increments [0x72F0] correctly per
SIO IRQ; gate at <0x80 / <0x7F is correct
- Bottleneck: SIO IRQ countdown is access-paced, fires ~1× per VBlank
vs ~128× needed; setup_data_phase (called from outer coord on VBlank)
zeroes [0x72F0] before counter reaches 128
- Both attempted fixes today caused freezes:
* VBlank deferral on [0x75C0]==1 — pending VBlank already in i_stat
delivered anyway; tighter dispatch gate also locked up
* Cycle-paced sio_tick at rates 50, 200 (and gated on [0x75C0]==1) —
runtime freezes once data phase activates, root cause unidentified
- delay=5 narrows the threshold (peak=2 vs peak=1, no freeze) but
doesn't get to 0x80
- Real fix likely requires deeper instrumentation of the freeze (call
stack / dispatch state at the moment of TCP starvation)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4054dc1c08 |
fix: DMA ch2 GPU→RAM now reads GPUREAD instead of writing zeros
The VRAM-to-RAM DMA path (channel 2, direction 0) was stubbed to fill the destination buffer with zeros. This broke all offscreen VRAM readback — the BIOS shell draws spiral/splash textures to an offscreen VRAM region, then DMA-transfers the rendered pixels back to RAM for later use as texture atlas entries. With the stub, all texture buffers stayed zero, producing invisible button backgrounds. Fix: call gpu_read_gpuread() for each DMA word instead of writing 0. Also includes: CDROM GetID two-phase response fix, GPU raw texture mode fix (opcode bit 0 instead of color==0x808080), debug server A0/C0 upload history commands with CPU context capture, and extended write trace ranges. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
b3833aa253 |
fix: exception handler chain walk + shell reaches Memory Card/CD-ROM screen
Root cause: the recompiler split the kernel exception handler at the jalr $s1 (chain handler dispatch) into func_00000C80 and func_00000E10. The chain-walker continuation at BFC10910 never executed — only the first handler in chain 0 was ever called. I_STAT bits 0 (VBlank) and 2 (CDROM) were never acknowledged, causing an interrupt livelock. Fixes: - Emitter jalr/jal safety-net: when the return address falls outside the current function, emit a continuation psx_dispatch call after the jalr dispatch. This bridges split functions at indirect calls. - Merged exception handler: removed BFC10910 seed so the chain walker continuation is part of func_00000C80 (C fall-through after jalr). - 0xBFC10910 dispatch special case in psx_unknown_dispatch: chain handlers return to $ra=BFC10910 via jr $ra (compiled as `return;`); the dispatch loop picks up the $ra value — handled as a no-op since the continuation already ran via C fall-through. - Post-exception adaptive cooldown: if the handler didn't clear any I_STAT bits, give main code 500 blocks before re-firing. Prevents VBlank livelock when no handler claims the interrupt. - SIO byte write handler in mmio_write8 (was missing, caused crash). - GPU→RAM DMA ch2 stub: fills target with zeros, completes transfer. - Dispatch trace (debug_server_trace_dispatch) added to emitter template so it survives regeneration. Result: shell device detection completes, StartPad dispatched, chain E014 populated, GPU actively rendering the Memory Card / CD-ROM screen. VSync counter still 0 (handler installed but not yet incrementing — next investigation). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
fba58d76b3 |
Phase 4 interrupt fixes: RFE, GPR save/restore, DMA IRQ edge-trigger
Three interrupt delivery bugs fixed that were blocking shell progression: 1. RFE after handler exit: The exception handler's normal exit path (jmpbuf longjmp at 0xBFC10944) does not execute RFE. In our model the handler returns to psx_check_interrupts, not to the WaitEvent caller. Without RFE, IEc stays 0 forever after the first interrupt. Fix: apply RFE in psx_check_interrupts if IEc is still 0 after the handler returns. 2. GPR save/restore around handler dispatch: The handler's jmpbuf exit restores callee-saved registers from the kernel jmpbuf (intended for a non-local jump to WaitEvent's caller). In our model this corrupts the interrupted code's registers. Fix: save all GPRs before handler dispatch and restore them after, matching real hardware where the interrupted code's registers are preserved via TCB save/restore. 3. VBlank tick gated on !in_exception: The handler runs thousands of block leaders, each calling psx_check_interrupts. Without gating, dispatch_count advances inside the handler, firing new VBlanks that stack up and starve the main code. Fix: only increment dispatch_count and fire VBlank/timer ticks when not in exception handling. 4. DMA IRQ edge-triggered: update_master_irq() was level-triggered, re-asserting i_stat bit 3 on every call while master_flag=1. Combined with no BIOS callback to acknowledge DMA IRQs, this caused an interrupt storm. Fix: edge-detect master_flag 0->1 transition, and suppress DMA completion IRQs entirely since transfers are synchronous. Also adds GPU debug diagnostics: GP0 command counters (nop/fill/draw/ env/copy), draw area/offset in gpu_state, vram_peek debug command. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |