Commit Graph

742 Commits

Author SHA1 Message Date
Alex Vanderveen 4cdccf58c1 multitap enhancements 2026-08-07 10:19:12 -04:00
Alex Vanderveen 480fcad652 new build wizard 2026-08-07 01:43:04 -04:00
Alex Vanderveen 209f3e0cfb fix merge: wire mod APIs and pick_runtime_file cli flags
Include mod_plugins/mod_runtime and restore master’s four-arg file picker
so the integrate←master merge builds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 22:55:43 -04:00
Alex Vanderveen 94cb3807a9 Merge origin/master into integrate/game-codegen-hooks-into-rollback
Keep rollback/netplay multiplayer routing, dual-raster GL present, and TOC
fingerprints while taking master's CHD support, mod load acceleration,
adaptive widescreen, and geometry/perspective APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 22:50:38 -04:00
Alex Vanderveen 8e274238da fix OSD 2026-08-06 22:39:36 -04:00
Alex Vanderveen 9b72328afa SFU preferred 2026-08-06 22:08:09 -04:00
Alex Vanderveen 4073e2311c rollback + fmv + connectivity 2026-08-06 20:34:50 -04:00
Alex Vanderveen 36e0d92c8b vram FMV hack gated for rollback 2026-08-06 00:53:03 -04:00
Alex Vanderveen 652be7ba02 rollback FMV patches and overlay 2026-08-06 00:52:14 -04:00
Matthew Stanley ab87cb8ef4 autocompile: report a degraded (interpreter-only) run on a channel that exists
A misconfigured overlay_autocompile_cmd silently degrades an entire session to
the interpreter. The diagnosis machinery for this already existed and was good
— autocompile_report_broken_once() fires after 3 consecutive failures and
explains exactly what to check — but it writes to fprintf(stdout), and the
shipped runtime links -mwindows: a GUI-subsystem binary with no console. The
warning is emitted into nothing on precisely the builds people run.

Observed cost: a fresh worktree ran 100% interpreted for a whole session
(runs=8 fails=8 shard_ok=0, dispatch_native=0) because game.toml named a
recompiler path the documented build recipe does not produce. The only symptom
was "it feels slow", and it invalidated a performance A/B before anyone thought
to query the counters by hand.

Three changes:

- Validate the command's path arguments at CONFIGURE time. The existing check
  resolves only the first token (the interpreter); it never looked at
  --recompiler, which is the argument that actually breaks — it is hardcoded
  per-title and disagrees with where the recipe builds. Paths now resolve
  against the child's working directory and are checked before any compile is
  attempted, rather than the truth emerging after three failed spawns.
  Advisory, not fatal: the runtime still runs exactly as before, just not
  silently.

- Record WHY in one string, exposed as degraded/degraded_reason in
  autocompile_status over the TCP debug server. Rule 3's answer rather than
  more printing. Keeps the FIRST cause, which is the useful one.

- Stamp it into psx_last_run_report.json. This is the part that prevents a
  repeat: a field you have to query is a field nobody queries. A degraded run
  now says so in its own artifact, so "was that measurement valid?" is
  answerable after the fact instead of having to be suspected.

test_autocompile_degraded (new, registered in CTest) builds the real failure
shape and asserts it is caught at configure time, that the reason names the
offending flag, that the first cause is retained, and that the reason is
escaped so it cannot break the JSON for every consumer.

Also fixes a pre-existing %d/LONG format mismatch on last_exit that this
change's argument shuffle surfaced; warnings on autocompile.c go 2 -> 1 (the
remaining array-bounds one in watch_thread is pre-existing and untouched).

NOT done here, deliberately: the underlying cause is that every title's
game.toml hardcodes a build-directory path (Tomba 2 names a worktree-relative
dir the recipe never creates; MMX6 hardcodes an absolute path into one
checkout). Fixing that means having CMake record the real recompiler location
and touching six title repos — its own change. This one makes the failure
impossible to miss.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 19:37:45 -07:00
Alex Vanderveen c8f668cc9e Fix lobby relay rewrite via WS peer IP and harden rollback netplay.
Resolve stash conflict in psx_lobby_client by keeping getpeername-based
relay rewrite with the RFC1918-aware path, and land pending rollback
hookup/runtime changes.
2026-08-05 22:23:30 -04:00
Matthew Stanley 6e6a0b3ed8 spu: implement reverb, noise, sweeps and SPU IRQ; make CAUSE.IP2 combinational
Closes the four gaps named in issue #103 and lands the separable, verified
parts of PR #102. See docs/internal/SPU_FIDELITY_103.md for the per-piece
disposition and the oracle-verification queue.

SPU DSP (issue #103), clean-room from hardware documentation:

- Reverb: the documented 22050 Hz engine — vLIN/vRIN input, same-side and
  crossed different-side IIR reflections, 4-tap comb early echo, both
  all-pass filters, vLOUT/vROUT output, and the work-area address advance.
  Gated on SPUCNT bit 7 for WRITES only; reads, IRQ checks, address advance
  and output always run, as on hardware. Addressing is confined to
  [mBASE, 0x80000). Per-voice sends from EON, CD send from SPUCNT bits 0+2.
- Noise: 16-bit LFSR with the documented parity feedback, clocked at the
  SPUCNT bits 8-13 rate; NON voices substitute it for their ADPCM sample.
- Volume sweeps: all 24 voice L/R plus main L/R. Bit 15 selects sweep vs
  direct; sweep is a live envelope on the same rate machinery as ADSR, and a
  guest read of a sweeping register returns the live level.
- Capture buffers: CD L/R and voice 1/3 output written to SPU RAM, so a game
  that parks the IRQ address there still gets its interrupt.
- SPU IRQ (I_STAT bit 9): checked at every SPU RAM access class — FIFO, DMA
  both directions, ADPCM block fetch, capture writes, reverb work-area
  accesses — gated on SPUCNT bit 6, mirrored in SPUSTAT bit 6, acked by
  clearing SPUCNT bit 6.

The CD-only fast path in spu_render was removed rather than extended: the
SPU now has per-frame work that must run in every path, and an FMV (XA audio
with zero active voices) is exactly the CD-with-reverb case.

This is a clean-room implementation from the psx-spx/nocash register map and
documented algorithm. Beetle's source was deliberately not consulted: it is
GPL-2.0-or-later and this project is PolyForm Noncommercial. PR #16 was
parked for exactly that reason and PR #13's reverb was separately wrong (it
gated on bit 15 of dAPF1, an address offset, instead of SPUCNT bit 7). The
one place this knowingly deviates from hardware is the 22.05 -> 44.1 kHz
reconstruction filter, which the documentation does not specify; it is
isolated in a single function and flagged for oracle comparison.

CAUSE.IP2 (from PR #102):

IP2 is combinational on R3000A — it mirrors the interrupt line and falls the
instant the guest acks I_STAT or masks the source. It was being OR'd in at
delivery and never cleared, in TWO places (the compiled path and
psx_interpreter.c, the latter missed by PR #102), leaving a phantom pending
interrupt that can spin a kernel dispatcher looping on CAUSE.IP & SR.IM.
psx_irq_refresh_cause_ip2() is now the sole writer of bit 10, refreshed at
raise, I_STAT ack, I_MASK write, HLE context restore and power-on. Verified
against the Beetle oracle's irq.cpp/cpu.cpp rather than asserted, and
covered by test_cause_ip2_combinational.

Mid-dispatch audio pump (from PR #102), with a fix: routed through a gate
that mirrors sdl_audio_update's mute/sink decision. Pumping unconditionally
from the VBlank edge, as submitted, would have pushed real audio during every
turbo-load hard mute and defeated the freeze-in-place mute model.

SPU RAM DMA readback (from PR #102): DMA4 in the SPU->RAM direction wrote
literal zeros; SPU RAM is readable memory and titles carry state through it
across an Exec boundary.

Also fixes an unrelated build race found on the way: tools/embed_spirv.py
wrote its intermediate SPIR-V to <source>.spv, so the two runtime targets
that embed the same shaders raced on one path and one deleted the file the
other was reading.

Co-Authored-By: Alexandros Mandravillis <Alexbeav@live.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 18:16:16 -07:00
Alex Vanderveen ff0e934712 recomp-net and new connectivity 2026-08-05 19:32:03 -04:00
Matthew Stanley 9217ae203a feat(video): expose geometry precision through the launcher
Wires the two [video] settings into the recomp-ui Display page: seeds ls.* from
settings.toml, writes the player's choice back, and sets the new
has_geometry_precision capability. Geometry precision is a property of the PS1
pipeline rather than of any particular disc, so every PSX title exposes it.

Pairs with recomp-ui feat/psx-geometry-precision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:48:08 -07:00
Matthew Stanley af6dff5132 feat(debug): screenshot_hires — capture the surface the player actually sees
screenshot/screenshot_file read native 15-bit VRAM via gpu_display_pixel_rgb.
That is correct for faithfulness work but BLIND to any enhancement that only
exists in the supersampled mirror: at supersampling >= 2 the geometry-correction
sub-pixel vertices, SSAA edges and perspective UVs are resolved in the hi-res
surface and gone once pixels are packed back to native.

This bit hard. Native captures of Ape Escape looked clean while the user was
looking at a visibly cracked frame, so a real regression got reported as fixed
and the argument moved to counters. An instrument that cannot show the defect
is worse than no instrument.

screenshot_hires routes gr_render_display_hires — the same present path the
window uses — and falls back to the native resolve (reporting scale 1) when
there is no hi-res surface, so it always answers truthfully about real output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:36:27 -07:00
Matthew Stanley b35892fc16 fix(gte): exact direct-indexed vertex table + ambiguity gate, with a miss census
The geometry side cache was an 8192-entry HASHED table with no ambiguity check.
Unrelated screen positions shared a slot, so a vertex could be handed a
different vertex's sub-pixel fraction, and eviction changed which triangles got
corrected from frame to frame — moving seams across every mesh.

Both references index this table exactly, one slot per reachable SXY
(beetle-psx vertexCache[0x800*2][0x800*2]; DuckStation 2048x2048), and gate it
on an ambiguity flag so a pixel that two DIFFERENT projections rounded to is
never used. Do the same: direct index, first writer wins, flag on a conflicting
value, allocate lazily on enable so the faithful default costs nothing, and
fail closed to the faithful path if the allocation fails.

Adds a lookup census (attempted / hit / miss_unrecorded / miss_ambiguous) on
geom_correction. With an exact table a miss_unrecorded is a genuine tracking
coverage gap rather than a cache artifact, which is what distinguishes 'the
cache was lossy' from 'the vertex path never reaches us in a matchable form'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:18:29 -07:00
Matthew Stanley 5a64a98440 feat(debug): geom_correction TCP command — is the correction engaging?
Both [video] enhancements are silent no-ops on anything they cannot prove is
projected geometry: a vertex whose sub-pixel fraction was never cached, or a
packet whose position words lack full GTE projection provenance, just draws the
faithful way. So the enable flag alone says nothing about whether a given title
benefits, and the existing hit counters had no reader.

geom_correction reports the flag plus the free-running geometry_vertex_hits and
perspective_triangles totals, so per-title bring-up can tell an engaged
correction from an inert one before anyone argues about screenshots. Sample
twice and diff for a per-window rate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:42:37 -07:00
Matthew Stanley 2bdaff3244 fix(gl): floor/ceil the wide-mirror centre-only test for sub-pixel vertices
The native-wide centre-only fast path read batch x extents with a truncating
(int) cast. With geometry_correction those are fractional, and truncation
rounds a negative x TOWARD the centre — so a batch just touching the left
margin could be misclassified as fully inside the 4:3 frame and have its
wide-mirror draw skipped, leaving a one-pixel sliver unmirrored. Take floor
for the low edge and ceil for the high edge instead; whole-valued positions
(the faithful path, and every prim with the feature off) are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:04:56 -07:00
Matthew Stanley c8b692eda2 feat(video): opt-in sub-pixel vertex precision + perspective-correct textures
Makes the parked projection/perspective work reachable and gets it into the
renderers people actually use. Addresses issue #92 (PGXP-style geometry and
texture correction).

The GTE side cache, SWC2 RAM provenance, GP0 triangle preparation and the
software-renderer consumption path already landed in 2ceaf5a ("park projection
and perspective correction", from kem0x PR #14), but were unreachable: the
generic setters gte_geometry_correction_set() / gpu_texture_correction_set()
had no production caller, and the corrected vertices went straight to
sw_set_precise_triangle(), bypassing the renderer vtable — while the default
renderer is OpenGL.

This adds:

- [video] geometry_correction and [video] perspective_texturing, in game.toml
  and settings.toml, both defaulting false. Independent knobs; the launcher
  seed marks them present so a save round-trips a hand-edited key instead of
  dropping it. Startup names the active pair, and notes when geometry
  correction is on below supersampling 2 (where it cannot be seen).
- gr_set_precise_triangle() / gr_set_perspective_triangle() on the
  GpuRenderBackend vtable, so gpu.c hands the correction to whichever backend
  is live rather than to the software rasterizer directly. NULL entries no-op.
- OpenGL and Vulkan consumption. Positions are already float end-to-end, so
  sub-pixel vertices drop in; the readback dirty rect widens by one pixel to
  cover them. Perspective UVs use a per-vertex a_q weight and clip coordinates
  pre-multiplied by w = 1/q, letting the hardware's own perspective divide
  interpolate a smooth UV varying beside the affine noperspective one. a_q == 0
  — the default, and what every prim gets with the feature off — makes w
  exactly 1.0 and selects the affine varying, so the faithful path is the
  pre-feature pipeline unchanged.

The PS1-visible GTE SXY FIFO stays integer either way: guest-side screen-bounds
culling and SXY readback are untouched, and this remains visual-only.

Also fixes a pre-existing concurrent-build race found while validating: every
runtime target runs embed_spirv.py over the same shaders, and each wrote
"<shader>.spv" next to the source, so under -j N one process deleted the file
another had just written (FileNotFoundError on a shader that compiled fine).
The intermediates now go to a per-invocation temp dir.

Parked-work provenance retained; see ENHANCEMENTS.md G1.

Co-authored-by: Kareem Olim <kareemolim@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:02:58 -07:00
Matthew Stanley 7f7fbc8e1a feat(mods): expose linked package attribution 2026-08-05 11:17:30 -07:00
Matthew Stanley f3d60331a7 autocompile: name the resolved interpreter at configure, warn on Cygwin builds
Root-caused on Tomba 1: overlay_autocompile_cmd's bare 'python' resolved
through PATH to the devkitPro MSYS2/Cygwin python (usr/bin precedes the
Windows install), which segfaults (exit 0x0B00, signal 11) under the
kill-on-close job spawn BEFORE writing a byte — so every compile failed
with '(no output captured)' and nothing pointed at the cause; the title
silently ran interpreted.

At configure time, resolve the command's first token exactly as
cmd.exe /C will (SearchPathA with .exe), print the binding once, and
warn loudly when msys-2.0.dll/cygwin1.dll sits beside the resolved
interpreter, recommending the Windows launcher form 'py -3 ...'.
Also fail loudly up front when the token doesn't resolve at all.

Doc'd in ASYNC_OVERLAY_COMPILE.md. Title game.toml fixes (python ->
py -3) ship separately in each game repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
Matthew Stanley e629d622fa dma: implement channel 5 (PIO / expansion port) transfers
Salvaged from PR #13 (feat/launcher-stb-revamp, commit 2ba52e97) by
NyperYuhgard. Master fatal-halts on any DMA start for channel 5; this
moves words to/from RAM directly (device side unemulated: RAM-to-device
reads-and-discards, device-to-RAM zero-fills) and completes the
transfer with the normal IRQ path.

Note: zero-filling from an unemulated expansion device is weaker than
the fail-closed psx_fatal_halt default the other channels follow; kept
as submitted because the contributor exercised it on a real title.
Trimmed from the original hunk: unused DMA_PIO_CYCLES_PER_WORD macro
and mdec_finish_async_{in,out}_transfer wrappers nothing references.

Co-Authored-By: NyperYuhgard <noreply@github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
NyperYuhgard 95669105de interp: deliver alignment exceptions, protect Cause read-only bits, add CFC0
Salvaged from PR #13 (feat/launcher-stb-revamp, commit 9fd2876c) by
NyperYuhgard. Adds to the dirty-RAM interpreter:

- LoadAddressError/StoreAddressError delivery for misaligned LH/LW/LHU/
  SH/SW and misaligned JR/JALR targets, via a new interp_exception()
  that performs the architectural COP0 sequence (BadVAddr, Cause ExcCode,
  SR mode-stack push, EPC, BEV-selected vector).
- COP0 Cause write protection on MTC0/CTC0.
- CFC0/CTC0 aliases (identical to MFC0/MTC0 on R3000A).

Two deviations from the original:
- The original masked Cause writes to bits [15:10] (backwards vs
  hardware); corrected to the writable software-interrupt bits [9:8]
  per psx-spx / PCSX-Redux, which also un-deadens the psxTestSWInts
  recheck below it.
- The original's post-RFE immediate psx_check_interrupts recheck is
  dropped: master already delivers post-RFE interrupts through
  psx_rfe_mark_escape() and re-checking inside the handler window is
  the documented dbg-build boot-wedge livelock.

Co-Authored-By: NyperYuhgard <noreply@github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:55:00 -07:00
Matthew Stanley 25d2798037 mods: ship loading-speed mods with the framework, for every game
Loading acceleration is a property of the emulated hardware, not of any
particular disc, so having each title carry its own copy of the same two
manifests and plugins was duplication waiting to drift.

- target game_id "*" now matches every game. An empty target list still
  matches nothing, so a malformed manifest fails loudly as before.
- mods/builtin/packages ships psx.enhancement.fast-loading and
  psx.enhancement.cd-speed: independent host-pacing and CD-timing mods,
  each a free integer multiplier (1..1024) plus a tickbox that uses
  disabled_by to grey out the field it overrides.
- runtime/src/mod_builtin_speed.c registers both activation plugins.
- runtime.cmake stages mods/builtin into every game's output beside its own
  catalog, before the game's own copy, so a title can still override an id.

Titles adopting these should delete their per-game copies; keeping both
would show two of each mod.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 10:40:07 -07:00
Matthew Stanley f44f56bfdc mods: let games expose loading speed as a free integer, plus disabled_by
Players asked for CD speeds beyond the curated 2x/4x list and for the two
loading accelerators to stop being one control (GH TombaRecomp#5: a
speedrunner wants shorter loads but NOT the host speed-up, which runs past
the loading screen and breaks a skip).

Three changes, all general:

- psx_mod_set_disc_speed accepted only divisor 2 or 4. That was policy,
  not safety: cdrom.c divides the sector delay and floors the result at
  CDROM_MIN_DELAY, and apply_speed leaves XA streaming at authentic
  timing, so no positive divisor can produce a zero-delay storm or
  pitch-shift FMV audio. Accept 1..PSX_MOD_DISC_SPEED_MAX and let the
  mod's description carry the risk warning.

- psx_mod_set_load_acceleration accepted 2..16. Host pacing cannot desync
  the guest at all (every frame, CD deadline, interrupt and callback still
  happens), so the ceiling was arbitrary. Accept 1..PSX_MOD_LOAD_ACCEL_MAX,
  with 1 meaning authentic and 0 still meaning uncapped.

- New option key disabled_by: an option names a BOOLEAN sibling that
  overrides it, so "tick Instant and the speed box stops mattering" needs
  no second widget type. The parser rejects a dangling, self-referential
  or non-boolean reference rather than leaving a control silently always
  enabled, and the provider resolves the link against the live selection
  so the launcher and the plugins can never disagree about whether a
  control counts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 23:55:25 -07:00
Matthew Stanley 5abdb7d0a1 runtime: accept Steam .car disc images 2026-08-04 19:32:16 -07:00
Matthew Stanley 1bc84f38c6 mods: support save-safe damage override and deadzone rounding 2026-08-04 18:50:31 -07:00
Matthew Stanley 1dcab6a2ff Merge remote-tracking branch 'origin/master' into codex/debug-input-route-20260803 2026-08-03 23:31:59 -07:00
Matthew Stanley 3e89dbc6c2 widescreen: support MMX4 background refill layout 2026-08-03 23:31:52 -07:00
Matthew Stanley 33c96c567d debug: capture presented widescreen surface in screenshot 2026-08-03 23:00:44 -07:00
Matthew Stanley 67757efac4 feat(runtime): add CHD discs and mod-owned loading modes 2026-08-03 22:32:17 -07:00
Matthew Stanley ceb4919bb2 debug: add exact VBlank input route queue 2026-08-03 22:24:44 -07:00
Matthew Stanley bc6b277c94 feat(mods): add GPU DMA enhancement memory 2026-08-03 15:55:47 -07:00
Alex Vanderveen a6519e00cc Merge branch 'integrate/game-codegen-hooks-into-rollback' of https://github.com/mstan/psxrecomp into integrate/game-codegen-hooks-into-rollback 2026-08-03 18:18:19 -04:00
Alex Vanderveen c82c6deb35 rollback SFU using recomp-net-server 2026-08-03 18:18:18 -04:00
Matthew Stanley b2af4e89c9 feat(mods): add trusted game enhancement hooks 2026-08-03 15:17:39 -07:00
Alex Vanderveen 910b998485 mingw build for toolchain to compile netplay 2026-08-03 15:39:52 -04:00
Alex Vanderveen c19618adc6 BIOS handling 2026-08-03 14:44:17 -04:00
Alex Vanderveen 2889550f50 bios path bump 2026-08-03 08:36:14 -04:00
Alex Vanderveen a0ef88887d bump wizard 2026-08-03 08:20:30 -04:00
Alex Vanderveen f1f892049e fix: persist absolute BIOS paths across generate/relaunch.
Relative bios.cfg / settings picks like bios/SCPH1001.BIN broke after
rebuild when cwd was build/; launcher verify also ignored exe-anchored
resolve. Absolutize sidecars, hydrate from bios.cfg, and resolve in
ae_bios_verify.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 08:07:02 -04:00
Alex Vanderveen ba276624b9 patch bad merge 2026-08-03 05:26:37 -04:00
Alex Vanderveen 804d3094c0 Merge feat/game-codegen-hooks into feat/rollback-netplay.
Keep rollback netplay/runtime authority (dual-raster, snaps, lobby) while
taking local codegen host/CLI/toolchain packaging from game-codegen-hooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 05:13:45 -04:00
Alex Vanderveen 0feb7709f6 rollback opengl render path, ICE patches, resim optimizations 2026-08-03 05:04:48 -04:00
Alex Vanderveen 7234d347ea Merge upstream/master into feat/game-codegen-hooks.
Keep local codegen/FMV cutover/zlib host work while taking upstream
tests, FPS telemetry, and mod-provider wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 03:29:32 -04:00
Alex Vanderveen 90266d4eaa resim optimizations 2026-08-02 19:11:04 -04:00
Alex Vanderveen bc99f95fff optimize scheduler and button edge case 2026-08-02 18:12:17 -04:00
Alex Vanderveen 6917d4a620 scheduler optimization on WAN 2026-08-02 17:49:36 -04:00
Alex Vanderveen fb252728a5 optimize scheduler WAN performance 2026-08-02 16:12:01 -04:00
Alex Vanderveen 2828f3fbbe fix deadlock mispredict after fmv 2026-08-02 14:22:10 -04:00