Files
Joseph MattielloandClaude Fable 5 cc5b880c11 feat(cd): add CD read speed core option (1x/2x/4x/8x/instant)
New core option virtualjaguar_cd_read_speed scales the HLE streamed
CD_read delivery rate. 2x (default) is the hardware-accurate double-
speed drive rate (352,800 B/s); 1x halves it; 4x/8x multiply it;
instant delivers the whole transfer in one halfline tick but still
routes through HLEStreamFinish so status-struct writes, done flags
and the FF-pad behave identically to a paced transfer.

The multiplier is LATCHED per-read at arm time (hleStream.speedMult,
same pattern as the statusBase latch from 8c9356b) so flipping the
option while a transfer is in flight cannot change the rate a game is
already pacing itself against.

The real-BIOS path (src/cd/cdrom.c) is deliberately NOT scaled: its
FIFO half-full IRQ cadence and DSA response delay encode race-
avoidance fixes (DSA steal race, FIFO-storm LRXD corruption) that
faster delivery would re-open, and the BIOS GPU ISR + DSP slave
consumers assume I2S-rate interrupt density. The option description
says 'HLE boot mode only'.

At the default the per-tick byte budget is arithmetically identical
to the previous code (inc * 2 / 2), and a full cd_boot_matrix.sh run
(3000 frames, HLE + BIOS modes, all titles) produced stage results
bit-identical to an unmodified build of the same HEAD (the three rows
that differ from the last table committed in docs/cd-boot-matrix.md —
Battle Morph bios, IS2 hle, baldies.cdi — reproduce identically on
pristine d812093; they are base-branch drift from a542d0a/1d4a311/
the CDI loader, not this change).

Spot checks (cd_wedge_probe --frames 900 --arm 30 --freeze-frames
300, HLE):

  Title         1x     2x     4x     8x     instant
  Battle Morph  CLEAN  CLEAN  CLEAN  CLEAN  CLEAN
  Hover Strike  CLEAN  CLEAN  CLEAN  CLEAN  CLEAN
  Primal Rage   CLEAN  CLEAN  CLEAN  CLEAN  CLEAN
  Baldies       flag*  flag*  CLEAN  CLEAN  CLEAN

  * static-load-screen false positive (68K in CD_poll loop $004DAx,
    D1='FEND'); full 3000-frame matrix passes at 2x, and 1x armed
    past the load phase runs clean.

Boot-window check only: instant delivery is still expected to stomp
in-game overlay loads whose destination covers live code (the Hover
Strike mission-load class) — documented in docs/cd-read-speed.md,
not fixed, per the 2x-default design.

make TEST_EXPORTS=1 test: exit 0 (all suites pass).
c89-lint: clean on all touched files.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-26 21:23:12 -04:00

2.8 KiB

CD read speed core option

virtualjaguar_cd_read_speed — data-transfer rate for the HLE streamed CD_read path (src/cd/jagcd_hle.c::JaguarCDHLEStreamTick). Values: 1x, 2x (default, hardware-accurate: 150 double-speed sectors/s x 2352 B = 352,800 B/s), 4x, 8x, instant (whole transfer in one halfline tick, still routed through HLEStreamFinish so status-struct writes / done flags / FF-pad behave identically to a paced transfer).

Design constraints:

  • Latched per-read at arm time (hleStream.speedMult, same pattern as the statusBase latch): flipping the option mid-transfer cannot change the rate a game is already pacing itself against.
  • HLE boot mode only. The real-BIOS path (src/cd/cdrom.c) is NOT scaled: its FIFO half-full IRQ cadence (FIFO_REFILL_PERIOD_X100, the 16-deep drain model) and DSA response delay (DSA_RESPONSE_DELAY_TICKS) encode race-avoidance fixes (DSA steal race, FIFO-storm LRXD corruption) that faster delivery would re-open, and the BIOS GPU ISR + DSP slave consumers assume the I2S-rate interrupt density. BIOS mode is experimental anyway; it stays at the accurate rate.
  • The default (2x) is arithmetically identical to the pre-option behavior (inc * 2 / 2), verified by a full cd_boot_matrix.sh run (3000 frames, HLE + BIOS): stage results bit-identical to an unmodified build of the same HEAD.

Per-title survival, non-default speeds (2026-07-26, HEAD d812093)

cd_wedge_probe --frames 900 --arm 30 --freeze-frames 300, HLE mode. CLEAN = no frozen framebuffer in the boot window; flag = probe fired.

Title 1x 2x (control) 4x 8x instant
Battle Morph CLEAN CLEAN CLEAN CLEAN CLEAN
Hover Strike CLEAN CLEAN CLEAN CLEAN CLEAN
Primal Rage CLEAN CLEAN CLEAN CLEAN CLEAN
Baldies flag* flag* CLEAN CLEAN CLEAN

* Known static-load-screen false positive (see the cd_wedge_probe caveat in CLAUDE.md): at 1x/2x the boot load holds a static screen longer than the 300-frame freeze window while the 68K sits in its CD_poll loop ($004DAx, D1='FEND'). The full 3000-frame boot matrix passes at 2x, and a 1x run armed past the load phase (--arm 2000) runs clean.

Caveats: this is a boot-window check only. The failure class that motivated the 2x default — instant delivery overwriting in-flight game code (Hover Strike's mission loads span the address range of their own poll loop) — occurs on in-game loads that a 900-frame headless boot never reaches. Titles that survive instant at boot may still wedge on later loads; that is expected and documented, not a bug to fix at non-default speeds. Timing-sensitive titles (Primal Rage TOC-duration countdown, Battle Morph 917KB mid-handshake reads) should be treated as 2x-only until verified in RetroArch.