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]>
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 thestatusBaselatch): 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 fullcd_boot_matrix.shrun (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.