The clock fix (INSTRUCTIONS_PER_MS 10_000 -> 1_000_000, commit 645feb8) moves
the worker-hub +66 ms render gate from ~660k to ~66M instructions, so the old
-n 50M anchor is now pre-render (swaps=0) and no longer guards boot rendering.
Re-anchor sylpheed_n50m -> sylpheed_n200m: at -n 200M the fixed build renders
steadily (draws=3165, swaps=895) and the stable digest is deterministic across
repeated inline lockstep runs. Renames the golden, updates the test's -n and
doc comment, and refreshes tests/golden/README.md. Per the README's re-baseline
policy (intentional digest move -> separate commit).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Investigation probes for the ADV.wmv intro-video deadlock (feeder's demux
source-read 0x825211a0 returns no-data 0x80500000 where canary returns 0).
- xenia-kernel/state.rs: extend AUDIT-DEREF (fire_audit_pc_probe_if_match) to
deep-dump the demux-state object (to +0xfc), its buffer descriptor [sub+4],
the byte-source sub-objects ([sub+0]/[+0x30]/[+0x94] and [src0+0x2c]), and
to WALK the windowed-buffer cached-block linked list (AUDIT-BLK: per-block
64-bit start/size/dataptr) exactly as mapper 0x82522118 does. Read-only,
env-gated (XENIA_AUDIT_DEREF); lockstep digest unaffected.
- xenia-app/main.rs: XENIA_DUMP_SLOTS observe-only scheduler runqueue dump.
- xenia-app/tests/sylpheed_oracles.rs: resolve ISO via SYLPHEED_ISO, then the
repo-root sylpheed.iso symlink, then default; fix path typo.
- .gitignore: exclude .claude/ (71k files / 66GB agent worktrees) and the
local investigation artifacts (audit-runs/, exit-thread-state.json, zq_*.py).
Findings (full chain in handoff notes): all ASF header metadata parses
correctly (packet size 16415, count 4728, 2 streams); cursors correct
(cur=5868, limit=77.6M); the windowed buffer works and slides (512B blocks);
no-data originates deep in the byte-read/parse chain, not from an empty buffer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sylpheed renders the splash (draws=78, iterate-2O) then plateaus: the
title's per-frame manager (sub_821741C8) only re-fires when "clock B"
([gfx+15160], swap count) changes, which only the CP swap-complete
callback sub_824CE2B8 increments. The graphics ISR sub_824BE9A0
indirect-calls that callback via [[gfx+10772]+16] on CP (source=1)
interrupts, but the slot stayed NULL so the callback never ran.
Root (runtime-verified, ours-side GPU): the guest arms the slot through
the Xenos CP scratch-register writeback path, which ours never
implemented. The arming IB (drained by ours at 0x4adf5180) contains a
Type-0 register write of the callback PC 0x824ce2b8 into SCRATCH_REG4
(0x057C). On hardware/canary, writing a SCRATCH_REG{n} mirrors the value
to SCRATCH_ADDR + n*4 in memory when the matching SCRATCH_UMSK bit is
set. Runtime values: SCRATCH_ADDR=0x0b1d5000 (the [gfx+10772]
descriptor), SCRATCH_UMSK=0x20033 (bit 4 set), so SCRATCH_REG4 ->
0x0b1d5010 = descriptor+16 = the callback slot (0x4b1d5010). Ours
decoded the Type-0 write into the register file but performed no
writeback (case a: drained-but-mishandled), so the slot stayed NULL.
Fix mirrors canary's CommandProcessor::HandleSpecialRegisterWrite
(command_processor.cc:545-552): a scratch_register_writeback() helper
called from handle_type0/handle_type1 after every register write; for
SCRATCH_REG0..7 with the UMSK bit set, it writes the value (big-endian,
as mem.write_u32 already stores) to SCRATCH_ADDR + n*4 (projected via
physical_to_backing). Deterministic given identical register state;
proven by unit test.
Cascade (verified by runtime probe): slot 0x4b1d5010 now armed with
0x824ce2b8; on the 2-3 CP interrupts that fire, the ISR reads the slot
and bcctrl's into sub_824CE2B8 (runs 2x; 0x cascade on master);
sub_824CE2B8 increments clock B ([gfx+15160]). The cascade does NOT yet
reach draws>78: there are only ~3 CP interrupts (from the initial 9825-
packet batch), and the title render loop stalls upstream (the iterate-2Q
title-respawn gate) before it submits more PM4_INTERRUPT work, so the
callback can't bootstrap a self-sustaining loop. This is the remaining
update-17/18 arming gap closed; the upstream stall is the next gate.
The default threaded GPU backend drains the ring on a separate host
thread, so with the callback now doing work the exact CP-interrupt
delivery instruction varies run to run (pre-existing GPU-thread race).
Pin the n50m oracle test to --gpu-inline (instruction-count
deterministic) and re-baseline its golden; bit-exact across repeated
runs. New unit test scratch_reg_write_mirrors_to_memory_when_umsk_enabled.
Tests: 675 pass (was 674). Golden re-baselined + determinism verified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a regression-catcher golden for Sylpheed boot at -n 50M lockstep,
covering the first VdSwap pair (the n2m oracle is swap-blind because
the first VdSwap fires at ~18M instructions). The new --stable-digest
flag emits/compares only fields that are deterministic in lockstep:
instructions, imports, unimpl, draws, swaps,
unique_render_targets, shader_blobs_live, texture_cache_entries
Excluded:
packets — empirically ±2-8% lockstep variance (GPU thread race per
audit M11)
resolves, interrupts_delivered, interrupts_dropped, texture_decodes —
scheduling-sensitive under --parallel
path — cwd-dependent
Empirical determinism: 3 consecutive lockstep -n 50M runs produce
byte-identical stable-digest output.
The n4b canonical-invocation golden the audit's recommended next sprint
also called for is deferred. Per audit memory `--parallel
--reservations-table` is pathologically slow (>32 min for -n 100M), so
-n 4B in that mode would be many hours per run, not the 5-15 min the
plan estimated. n4b will be captured one-shot post-renderer-unblock as
a manual artifact under audit-runs/post-fix/, not as a test golden. See
crates/xenia-app/tests/golden/README.md.
Test infrastructure:
- crates/xenia-app/tests/sylpheed_oracles.rs — invokes
CARGO_BIN_EXE_xenia-rs against the ISO. Path resolved via SYLPHEED_ISO
env var (skips gracefully if missing).
- #[ignore]-gated; run via:
cargo test --release -p xenia-app --test sylpheed_oracles \\
-- --ignored --nocapture
Closes ORACBUG-004 (P0). Partial: ORACBUG-006 (P1 deferred).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>