cdrom: flow-control accelerated reads -- never outrun the guest's ack

THE BUG, measured end to end. Legend of Mana's land-creation effect
renders as hard-edged full-screen wedges because ONE sector of a
multi-sector scene load never arrives: cd_read_log shows LBA 125111 ->
0x0E1F18 followed by LBA 125113 -> 0x0E2718 -- destinations one sector
apart, LBAs two apart. Sector 125112, which the ISO shows holds the
effect's 5-colour per-vertex palette (0x0888F8 = (248,136,8), 0xB0F8F8 =
(248,248,176)), was skipped; sector 125113's raw file bytes landed at
its address and were faithfully rendered as 216 distinct vertex colours.
DuckStation places 125112 correctly and draws the clean bloom.

The skip is manufactured by accelerated pacing. At authentic cadence the
guest has a full sector period (~6.6 ms at 2x) to ack each data-ready
INT1; the one-deep pend-then-lose below is Beetle-faithful, and a loss
there means the game truly was too slow. With the speed divisor or
bounded-instant mode active, sectors arrive in a fraction of that
period, so a guest that is merely BUSY -- here, mid scene-load
decompression -- gets a sector clobbered that hardware would have
delivered. s_int1_lost counted it; the stream corrupted silently.

Fix, class-level per RULE -1: when running FASTER than hardware, never
overwrite a sector the guest has not consumed -- hold delivery, capped
at the authentic sector period, then fall through to faithful clobber
semantics. Accelerated mode is thus never slower than hardware and never
lossier than hardware; loads stay near-instant while the guest keeps up
and degrade toward guest speed when it does not. XA/streaming modes are
excluded by the same gates as apply_read_speed and keep authentic
timing. Warm routes keep their existing indefinite handshake.

New counters accel_consumer_waits/_wait_cycles in cdrom_state: nonzero
is healthy (the enhancement waited); int1_lost rising while the divisor
!= 1 is the regression tripwire.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Vanderveen
2026-08-23 23:35:26 -04:00
parent 36ba6bd950
commit 493055846d
3 changed files with 72 additions and 0 deletions
+6
View File
@@ -178,6 +178,12 @@ typedef struct CDROMDebugState {
/* One-deep pended data-ready INT1 accounting (Beetle SetAIP analog). */
uint64_t int1_pended;
uint64_t int1_lost;
/* Accelerated-read flow control: holds where a faster-than-hardware
* sector was deferred rather than allowed to clobber an unconsumed one.
* Nonzero is healthy (the guest was busy and the enhancement waited);
* int1_lost rising while the speed divisor != 1 is the regression. */
uint64_t accel_consumer_waits;
uint64_t accel_consumer_wait_cycles;
uint8_t int1_pending_now;
} CDROMDebugState;