mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
424 lines
24 KiB
Markdown
424 lines
24 KiB
Markdown
# LOAD_TIME_ZERO — proposal checklist for loads-toward-0
|
|
|
|
Branch: `spike/load-time-zero` (worktree `_wt-loadtime-zero`).
|
|
Status: **exploration only — no code changes.** This doc is the burn-down
|
|
list; each experiment gets its own future session, its own flag, and a
|
|
stated kill criterion. Written 2026-07-13/14 from a memory sweep, a code
|
|
survey of the live tree, and a ChatGPT consult (project thread
|
|
"PSXrecomp workspace", 2026-07-13 — full 8-minute Extra-High answer in
|
|
that thread; merged into §1/§4/§5 here).
|
|
|
|
---
|
|
|
|
## 1. The frame (get this right before proposing anything)
|
|
|
|
```
|
|
wall_time(load window) = guest_time(window) x host_seconds_per_guest_second
|
|
```
|
|
|
|
Under `turbo_loads` there is **no wall-clock pacing**: the window is
|
|
emulation-throughput-bound *by definition*. CD sector deadlines are
|
|
scheduled in **guest cycles** (`cdrom.c sector_delay_cycles()`), so turbo
|
|
compresses them like everything else; the measured ~2x is the **host's
|
|
achievable emulation rate** inside the window, not a CD-cadence wall.
|
|
Both we and ChatGPT independently flagged that our earlier "loads are
|
|
bounded by authentic CD cadence" phrasing conflates guest-time duration
|
|
with the wall-time ceiling. A 2MiB transfer at 2x CD speed is ~6.8s of
|
|
guest time; at a 20x turbo multiplier that is ~340ms of wall time with
|
|
every VBlank, IRQ, and sector deadline intact.
|
|
|
|
Terms our first decomposition missed (ChatGPT):
|
|
- **Pipeline overlap**: per-sector guest time ≈ max(sector interval,
|
|
guest per-sector processing) — decompression can hide under cadence,
|
|
or dominate it. At 2x the interval is ~6.67ms guest.
|
|
- **Explicit game dwell**: fade timers, minimum-display periods, audio
|
|
sync waits — guest time no CD or CPU trick removes.
|
|
- **Seek/spin/command latency** as a term separate from bulk rate
|
|
(Sony's own figures: ~250ms average seek).
|
|
- **Host device/event cost**: per-block device stepping, IRQ checks,
|
|
SPU/GPU/event machinery can bottleneck turbo even with native CPU code.
|
|
- **Residual wall-clock coupling**: audio queue pressure, SDL pumping,
|
|
present deadlines can silently cap turbo.
|
|
|
|
Three levers, in ascending order of danger:
|
|
|
|
- **Lever A — cut host cost per guest second.** Timing-invariant, safe
|
|
by construction. Data shards, overlay coverage, event-horizon
|
|
acceleration (§4 E4), device-batch advancement, renderer cost.
|
|
Any Lever-A win multiplies with turbo and is invisible without it.
|
|
- **Lever B — cut guest time of the window.** Title-sensitive, the
|
|
proven wedge zone. ChatGPT, from DuckStation/PPSSPP/Dolphin evidence:
|
|
**there is no universally safe guest-visible CD speedup** — DuckStation
|
|
ships per-game disable traits for read AND seek speedup plus
|
|
MDEC/CDDA exclusions; no public breakage denominator exists.
|
|
- **Lever C — skip guest work / synthesize state.** Twice-proven
|
|
hardlock class (yield pumps r1/r2). The only credible TRUE near-zero
|
|
is here: a validated state-transition cache (conditional savestate) —
|
|
explicitly Phase-2, never foundation.
|
|
|
|
---
|
|
|
|
## 2. Prior-attempt ledger (do not re-litigate; verbatim outcomes)
|
|
|
|
1. **turbo_loads — SHIPPED, production path.** Engage = sustained
|
|
`cdrom_load_in_progress()` + game-started, 4-frame entry debounce +
|
|
6-frame release debounce
|
|
(`main.cpp:2062-2084`); presents 1-in-30; audio deliberately NOT
|
|
muted (queue capped). ~2x wall on Tomba loads with a healthy overlay
|
|
cache. NOTE (survey 2026-07-13): the primary SDL event pump now runs
|
|
BEFORE the turbo early-return (`main.cpp:2006-2009`), so the historic
|
|
"Not Responding" starvation appears fixed in code. A 2026-07-14
|
|
MMX5 debug-tools+turbo smoke reached live gameplay with normal load,
|
|
video, and audio; recurrence/root cause of the historic intermittent
|
|
0xE10 exception storm remains a longer-soak foundation issue.
|
|
2. **disc_speed=4x/instant — PROVEN UNSAFE as a divisor.** Changes how
|
|
many VBlanks fall between guest state transitions; MMX6
|
|
VSync-callback tick counter freezes → boot wedge, even with the
|
|
response arbiter (overwrites 24→0) and fixed (non-scaled) cmd
|
|
latency. `instant` today is bounded (`instant_max_per_frame`,
|
|
default 32/frame) — an IRQ-storm cap, not a safety rule.
|
|
⚠ Tree split: the live checkout (`feat/vigilante8-widescreen`) runs
|
|
the Ape direct-delivery CD model (no arbiter); master's model differs
|
|
(debt clamp at `master:cdrom.c:1633`). Any CD experiment must first
|
|
name its canonical tree.
|
|
3. **Instant-loads round 1 (gen-time yield pump) — ABANDONED.** Tomba's
|
|
loader `FUN_80021340` is also the live world-streamer; skipping its
|
|
cooperative yields starves co-thread/IRQ progress → gameplay hardlock.
|
|
4. **Instant-loads round 2 (syscall-level yield skip) — PARKED.** By
|
|
ChangeTh-syscall time the guest wrapper has already committed
|
|
green-thread yield bookkeeping; ONE skipped switch is eventually
|
|
fatal. Kept: the `[instant_loads]` inert scaffold (load-grid
|
|
detector, window plumbing, TCP counters) and the measure-first method.
|
|
5. **Data shards — REJECTED/QUARANTINED after live Tomba test.** Memoized
|
|
pure-function replay: read-set/write-set/
|
|
reg-out/cycle-cost capture at emitter-hooked funcs, byte-verified
|
|
replay, recorded cycles credited in slices through the normal
|
|
advance+IRQ path. Purity poisons: MMIO, DMA write, thread switch,
|
|
4MiB budget, staleness. Persists per-shard `.dss`. Known v1 fidelity
|
|
deltas (documented in DATA_SHARDS.md): ISR cycles double-credited;
|
|
IRQ arriving mid-credit observes the completed write-set; GTE/COP0
|
|
not captured. Live replay of `FUN_8003EF50` corrupted title and gameplay
|
|
textures despite zero verifier failures, proving the v1 temporal verifier
|
|
unsound. Runtime default is off and derived shards were removed.
|
|
|
|
6. **Generic idle-loop skip — SHIPPED, strictly per-game opt-in.** Requires
|
|
repeated same-PC interrupt boundaries with no stores, no MMIO, and stable
|
|
registers; advances to the next device deadline in whole loop quanta.
|
|
Tomba live A/B: 4,599 skips / 765M guest cycles, warm main burst
|
|
2.19 s -> 1.73 s, zero CD overwrites. Opt in per game with
|
|
`[runtime] idle_skip=true`, per process with `PSX_IDLE_SKIP=1`, or live
|
|
through the `idle_skip` debug command. Known accepted cosmetic tradeoff:
|
|
an occasional partial texture frame may flash under aggressive load turbo
|
|
and resolves on the following complete frame.
|
|
|
|
7. **Strict warm CD routes — SHIPPED, per-game opt-in only.** The reusable
|
|
`[[runtime.warm_cd_routes]]` schema supports up to 16 exact LBA sequences.
|
|
A mismatch immediately restores normal timing. Only non-XA data-read cadence
|
|
changes; XA/CDDA, seek, motor, IRQ, DMA, callback, and decompression paths
|
|
remain authoritative. Tomba regression: three route matches, 1,944 accelerated
|
|
sectors, zero response overwrites. The legacy `[runtime.warm_cd_route]`
|
|
singular table is deprecated but remains readable with a warning.
|
|
|
|
8. **Turbo host-audio sink — SHIPPED, per-game opt-in only.** With
|
|
`[runtime] turbo_audio_sink=true`, the canonical SPU still renders every
|
|
guest-time sample during an active turbo load, preserving voice and CD state,
|
|
but the accelerated buffers stop before SDL playback. Normal playback fades
|
|
back in from the current guest state. Tomba listening QA passed with
|
|
1,100,752 sink-discarded SPU frames, two accelerated load-route matches, and
|
|
zero CD response overwrites. This does not revive the rejected mute/freeze
|
|
model, which paused voice state and produced audible cuts/restarts.
|
|
|
|
Also relevant, shipped: FMV auto-skip (unpaced + muted + game-native
|
|
teardown), HLE boot shell-skip + boot-turbo window (`bios_hle.c`),
|
|
kernel bless (byte-verify-then-trust precedent).
|
|
|
|
---
|
|
|
|
## 3. Verdicts on the session's naive musings (be honest in future sessions)
|
|
|
|
- **"o2r equivalent — see it once and shard it"** → this IS the
|
|
data-shards spike, already designed and built; the open work is
|
|
measurement and a first live run. True o2r (AOT asset transformation)
|
|
is unavailable to a recomp — no source-level asset knowledge.
|
|
ChatGPT: the transferable o2r lesson is the **cache identity +
|
|
validation model**, not the timing model; no prior art does
|
|
read-set-replay-with-cycle-credit.
|
|
- **"HLE out the decompression"** → dominated by data shards for
|
|
repeated inputs, but ChatGPT identified real niches where HLE-out
|
|
wins: inputs mostly unique (shard hit-rate poor), read-set compare
|
|
approaching decode cost, algorithm SIMD-friendly (bitstream code can
|
|
beat generated C by >>2-5x), or — notably — **the decompressor runs
|
|
from dirty RAM under the interpreter** (overlay region!). Decision
|
|
rule: profile first; shards if inputs repeat + verify cheap; HLE if
|
|
unique inputs or expensive verify; neither if decompression isn't
|
|
host-hot. HLE shares the same temporal-write-visibility flaw as
|
|
shards — it is not automatically more faithful.
|
|
- **"Skip decompression" literally (don't charge cycles)** → Lever B/C
|
|
in Lever A's clothes; the cycle credit is what keeps the scheduler,
|
|
IRQ phase, and CD interlocks sane. Any instant-shards mode is a
|
|
Phase-2 per-game enhancement.
|
|
|
|
---
|
|
|
|
## 4. The burn-down checklist (merged: ours + ChatGPT's session plan)
|
|
|
|
Rules of engagement, every experiment: (1) measure FIRST via always-on
|
|
rings; (2) behind a flag, default off; (3) one experiment per session;
|
|
(4) kill criterion stated before the first line of code; (5) corpus
|
|
gate: Tomba load+world-streaming, MMX5 dev-tools boot, MMX6 boot/VSync
|
|
progression, repeated load/save cycles, attract demos, XA/CDDA, MDEC
|
|
FMV, a seek-heavy path, and (once identified) a direct-CD-hardware
|
|
title.
|
|
|
|
Standard probe report for every load window: guest cycles; wall time;
|
|
effective multiplier; CD commands/LBAs/deadline-vs-exposure times; seek
|
|
durations + buffer depth; VBlank/IRQ sequence; scheduler switches;
|
|
top host CPU consumers; SDL pump gaps; audio queue depth; canonical
|
|
architectural state hashes at checkpoints (never raw host structs).
|
|
|
|
### E0 — `load_probe_v2`: window decomposition [GATES EVERYTHING]
|
|
The decisive question: **why does the machine advance at only ~2x
|
|
during a window whose presentation is already suppressed?**
|
|
Segment guest time (seek/start, sector intervals, per-sector
|
|
processing, explicit waits) and host time (game/BIOS native code,
|
|
decompressors, dirty-RAM interp, CD/event machinery, SPU, GPU/present,
|
|
scheduler/IRQ checks, OS/UI pump). ChatGPT decision thresholds: if
|
|
decompression ≥ ~40% of host time → shards are serious; ≤ ~8% → kill
|
|
shards immediately; if CD/event/SPU machinery dominates → do E4; if a
|
|
wall-clock limiter is still active → everything else is a distraction.
|
|
Prereq: master's LOAD GAME in-exception wedge may block the Load-Game
|
|
repro — use area transitions if so.
|
|
|
|
### E1 — Turbo hardening (Lever A hygiene; ChatGPT rank #1 with E4)
|
|
(a) `turbo_event_pump`: re-validate the pump fix live (gate: max UI
|
|
pump gap ≲50ms, input recognized <100ms, <2% load regression).
|
|
(b) `turbo_audio_sink`: fix at the HOST SINK only — keep SPU/XA/CD
|
|
audio emulation exact; consume/discard excess host samples, keep a
|
|
small tail, crossfade on turbo exit; NEVER touch guest mute registers
|
|
or skip guest audio processing (kill: any guest-state manipulation).
|
|
(c) MMX5 dev-tools+turbo 0xE10 storm: root-cause as a foundation
|
|
timing bug (kill: any proposal that masks the storm instead of
|
|
explaining the first divergence).
|
|
|
|
### E2 — `turbo_next_event`: event-horizon acceleration [NEW AXIS — ChatGPT]
|
|
Advance through *provably* side-effect-free polling/idle regions
|
|
directly to the next scheduled observable event, with exact cycle
|
|
credit and identical event ordering. NOT heuristic idle-skipping —
|
|
requires proof: no memory writes beyond stack churn, no MMIO reads
|
|
whose value changes before the event, no IRQ deliverable earlier,
|
|
exact ordering at the destination. Candidates: CD status polls, thread
|
|
idle loops, BIOS waits, GPU/SPU completion polls. Companion change:
|
|
**batch device advancement to the next deadline** instead of ticking
|
|
every device after every recompiled block. This attacks the ~2x
|
|
ceiling directly. Gate: ≥20% guest-cycle throughput gain with identical
|
|
event ordering + state checkpoints. Kill: <10% gain or ONE divergence.
|
|
|
|
### E3 — Load-path overlay coverage (Lever A, boring, possibly free)
|
|
If E0 shows dirty-RAM interp share >~10% in-window (overlay-region
|
|
decompressors are ChatGPT's own HLE-niche flag): coverage-capture the
|
|
load path, reshard, re-run E0. Interp is 10-50x native. Zero timing
|
|
risk. Kill: interp share already ≤~10% (skip).
|
|
|
|
### E4 — Data shards: verify-only shadow mode, then replay [the spike]
|
|
Phase 1 `shards_shadow` (ChatGPT's addition): execute the original,
|
|
PREDICT the replay result, compare full outputs + live-outs + event
|
|
assumptions over a large sample — falsify before trusting. Gate to
|
|
proceed: decompressor ≥~20-25% of window host CPU (Amdahl: 20% share
|
|
caps the whole-window win at 1.25x), predicted hit rate ≥~80%, verify
|
|
cost ≤~20-25% of execution.
|
|
Phase 2 `shards_replay`: cold/warm A/B on the same transition. Gate:
|
|
>10% AND >100ms load reduction, no divergence across repeated loads +
|
|
world streaming.
|
|
**Correctness bar before ANY replay (ChatGPT, sharper than our v1):**
|
|
temporal write visibility — an atomic write-set + sliced cycle credit
|
|
cannot reconstruct what a mid-window IRQ observes. Replay is only
|
|
sound when IRQs are disabled across the recorded window OR the
|
|
recorded duration is strictly below the next observable device/IRQ
|
|
event; otherwise a time-indexed write log is required. Also: function
|
|
code/content hash in the key; full relevant entry registers (not just
|
|
a0-a3); live-outs beyond v0/v1; no pending exception; no DMA overlap;
|
|
code-invalidation for written pages; no reentrancy.
|
|
Kill: E0 says <~20% host share; hit rate <80%; verify ≈ execution
|
|
cost; any event lands inside a supposedly-atomic interval.
|
|
|
|
### E5 — Authentic drive backlog / never-early catch-up [RECLASSIFIED: correctness, not acceleration]
|
|
ChatGPT's adversarial verdict on our parked "leaning fix": never-early
|
|
+ catch-up **cannot make a correct pipeline faster** — a healthy loader
|
|
already receives every sector on its authentic deadline. It only
|
|
removes *artificial lateness* if our model restarts sector timing from
|
|
guest ACK instead of the continuous physical-drive timeline (real
|
|
drives buffer sectors; a guest that services sector N late should find
|
|
N+1, N+2 already bufferable). Probe FIRST: measure deadline-vs-exposure
|
|
deltas — if baseline already exposes nearly every sector on time, this
|
|
has NO acceleration value and is pure drive-model correctness work.
|
|
Prereq: resolve the CD-model tree split (Ape direct-delivery vs master
|
|
model) — pick ONE canonical model.
|
|
|
|
**Tomba verdict (2026-07-14): KILLED as acceleration.** The passive
|
|
`cdrom_timing` ring observed 1,304 data sectors: every buffer fill landed on
|
|
its exact scheduled cycle (zero early, zero late), and every exposed INT1 used
|
|
the intentional fixed +5,000-cycle controller-presentation latency. There were
|
|
zero read holds, pending/lost INT1s, or response overwrites. The current model
|
|
already maintains the continuous physical timeline; no catch-up work can make
|
|
this load faster.
|
|
|
|
### E6 — `cd_seek_speedup` (Lever B, bounded, per-game opt-in)
|
|
Probe first: seek/pause/spin share of window guest time. Upper bound =
|
|
number_of_seeks x ~250ms — a seek-only hack cannot touch a sequential
|
|
2MiB transfer. NOT proven-safe (DuckStation carries per-game disable
|
|
traits for seek speedup too; PPSSPP precedent: UMD-delay changes fixed
|
|
some titles, broke others). `pause_complete_delay_cycles` is a known
|
|
CPU-visible ordering contract (Ape memcard wedge) — stays authentic.
|
|
Kill: seek share <10% or <~250ms, or any callback/VBlank divergence.
|
|
|
|
**Tomba verdict (2026-07-14): KILLED by the gate.** An automated, authentic
|
|
New Game sample covered 792 data sectors over 298,130,657 guest cycles and
|
|
issued zero seek commands. Seventeen read-start delays totalled 7,676,928
|
|
cycles (2.57% of the data span), below the 10% threshold. Seventeen pause
|
|
delays totalled 24,167,597 cycles (8.11%), but pause completion is the
|
|
CPU-visible ordering contract explicitly excluded above. The combined
|
|
31,844,525-cycle figure is only a theoretical upper bound: it includes that
|
|
unsafe pause term and assumes impossible zero-cost, non-overlapping removal.
|
|
No seek-speedup implementation is justified for this path.
|
|
|
|
### E7 — `cd_read_speedup_exp` (Lever B, Phase-2 only)
|
|
Per-title, with explicit XA/CDDA/MDEC and timing-sensitive exclusions
|
|
(the DuckStation trait architecture). First unexplained wedge ⇒
|
|
permanently non-default. Never foundation.
|
|
|
|
**Implemented scope (2026-07-14):** strict, config-declared warm routes only.
|
|
This is not automatic global read acceleration and remains absent unless a game
|
|
opts in. Multiple routes share the same fail-closed matcher and consumer-paced
|
|
delivery path; XA/CDDA and non-read drive timing are excluded.
|
|
|
|
### E8 — Decompressor HLE (only via E4's failure)
|
|
Entered only if E0 shows decompression host-hot AND shards fail for an
|
|
identifiable reason (low reuse, expensive verify, interp-resident).
|
|
Kill: no material advantage over generated C or replay.
|
|
|
|
### E9 — BIOS CD-subsystem HLE — REJECTED (documented)
|
|
A faithful CdRead HLE must still preserve command submission, IRQ
|
|
ordering, callbacks, thread wakes, sector cadence, DMA-visible data,
|
|
retry behavior — and games bypass the BIOS anyway. The BIOS is already
|
|
native code; no host win unless E0 names BIOS CD bookkeeping as hot
|
|
(nothing suggests it). Its only credible payoff would be a centralized
|
|
validated CD state machine — that's an architecture question, not a
|
|
load-time one.
|
|
|
|
### E10 — Load-transition state cache (Lever C — the only TRUE near-zero; Phase-2)
|
|
known pre-load state → cached post-load state (conditional savestate
|
|
transition). Skips all intermediate observables by design ⇒ outside
|
|
the faithful foundation tier, per-game, opt-in. Validation bar
|
|
(ChatGPT): differential execution for THOUSANDS of frames after
|
|
restore, through at least one further load/scene transition — matching
|
|
the first rendered frame is not enough. Kill: any input, streaming
|
|
audio, memcard, or pending CD transaction inside the skipped interval.
|
|
|
|
**Burn-down order (= ChatGPT's session plan, merged):**
|
|
E0 → E1(a,b,c) → E2 → (E3 if E0 says so) → E4-shadow → E4-replay →
|
|
E5-probe → E6-probe → {E7, E8, E10 as Phase-2/conditional} — E9 stays
|
|
rejected on paper.
|
|
|
|
---
|
|
|
|
## 5. ChatGPT consult — key verdicts (2026-07-13 thread)
|
|
|
|
- **Decomposition check:** our three paths hold with one refinement —
|
|
the foundation-compatible set is (1) advance authentic guest time
|
|
faster, (2) remove host costs at identical guest cycles, (3)
|
|
eliminate *accidental lateness* in the CD pipeline. Only these
|
|
preserve the complete timeline. Everything else changes it.
|
|
- **Data shards presumed non-dominant until profiled.** Amdahl table:
|
|
decompressor at 10/20/40/50/70% of window host CPU caps the
|
|
whole-window replay ceiling at 1.11/1.25/1.67/2.0/3.33x. Feelable
|
|
only if ~8 conditions hold simultaneously (§4 E4 gates).
|
|
- **Temporal write visibility is the spike's major correctness flaw**
|
|
(§4 E4). Run verify-only shadow mode before any real replay.
|
|
- **No universally safe guest-visible CD acceleration exists.** Risk
|
|
ladder: host preload/readahead (safest, host-only) → authentic
|
|
buffering/backlog (safe if accurate) → seek-only (lower risk, NOT
|
|
proven safe) → faster data rate → instant (highest). No public
|
|
breakage denominator; claims like "seek speedup is 99% safe" would
|
|
be invented numbers.
|
|
- **Never-early+catch-up is correctness work**, not acceleration (§4 E5).
|
|
- **New axis: event-horizon acceleration + device-batch advancement**
|
|
(§4 E2) — the best unexplored host-side candidate; attacks the ~2x
|
|
ceiling cause directly.
|
|
- **Turbo audio: fix at the host sink** (§4 E1b); never in guest state.
|
|
- **Prior art:** o2r/OTR → take the cache-identity/validation model;
|
|
DuckStation preload = host-side robustness, not guest timing; Dolphin
|
|
warns disabling disc-speed emulation crashes titles; PPSSPP UMD-delay
|
|
history = storage latency is observable behavior. Closest true-zero
|
|
analog = validated deterministic state-transition cache (§4 E10).
|
|
- **Plan of record (its words):** fix and profile turbo → prove/reject
|
|
event-horizon acceleration → falsify data shards with verify-only
|
|
instrumentation → treat authentic backlog as correctness work → keep
|
|
seek/read acceleration per-game and non-foundational → reserve true
|
|
near-zero for an explicitly classified load-transition cache.
|
|
|
|
---
|
|
|
|
## 6. Facts a future session will want (survey 2026-07-13)
|
|
|
|
- Live checkout = `feat/vigilante8-widescreen` (05fb36e); master =
|
|
dde268d. CD models differ between them (§2 item 2).
|
|
- turbo detection/engage: `main.cpp:2062-2084`; burst present cadence
|
|
`:2174-2180`; event pump `:2006-2009` (before early-returns); second
|
|
pump `:2210` skipped in burst (input freshness only).
|
|
- CD scaling: `apply_speed` `cdrom.c:301-309` (XA exempt; divisor 0 =
|
|
bounded instant via `instant_period()`); sector cadence base 451584
|
|
cyc single-speed; `CDROM_IRQ_PRESENT_DELAY=5000` (ISR-teardown
|
|
contract); pause completion deliberately NOT speed-scaled;
|
|
seek-complete ≈ 4x sector period far / 0x800 near.
|
|
- Data shards wiring: emitter hook `code_generator.cpp:2211-2216` +
|
|
`jr $ra` finalize `:1706`; chokepoints `memory.c:1135,1241,1363,1399`,
|
|
`traps.c:540`; store `data_shards.c` (494 LOC, no TODOs); config
|
|
`[data_shards] funcs` `config_loader.cpp:716-723`. `.dss` per shard,
|
|
no manifest (doc/impl drift).
|
|
- bios_hle: B0 events 0x07-0x0D only; boot = one-shot shell-skip at the
|
|
image's `shell_entry_phys` + boot-turbo until game start. A0/C0 observed,
|
|
fall through. The boot-skip and the B0 tier are independent axes
|
|
(`bios_hle_plan.h`): the skip needs only `shell_entry_phys` and so lands
|
|
the same load-time win under OpenBIOS as under retail, even though
|
|
OpenBIOS refuses the B0 tier for want of `deliver_event_ret`.
|
|
- `_wt-tomba-loadshards-fw` worktree dir is EMPTY/unregistered — the
|
|
spike lives only as branch `spike/tomba-load-shards` (fw) +
|
|
`spike/load-shards` (TombaRecomp). Recreate worktrees before E4.
|
|
- `cdrom_bursts` ring (`cdrom.c:311-360`) already measures load
|
|
durations — E0's window boundary source.
|
|
|
|
|
|
## Incremental resident sectors
|
|
|
|
`psx_mod_resident_cd_sector(lba, user_data)` admits exactly one verified data
|
|
sector through the actual controller FIFO and IRQ path. It keeps ReadN active,
|
|
advances the drive cursor by one sector, and restores ordinary timing for the
|
|
next sector. The original guest Ready callback, header/payload DMA, resource
|
|
consumers and final Pause acknowledgement still run. It never writes guest
|
|
RAM, calls a guest callback or retains a host pointer/transfer cursor.
|
|
|
|
The title must prove its stock file/span, original code and live callback,
|
|
and that the next destination is free of pending consumers. A zero ring
|
|
occupancy byte alone is insufficient when an SDK queue retains its source
|
|
pointer. Check both the software GPU queue and active GPU/SPU DMA before each
|
|
admission. The shared helper checks CD ownership only; it does not know the
|
|
title's upload queues or grant a whole-file transfer.
|
|
|
|
Admission requires the original ReadN ACK and response to be fully consumed,
|
|
mode 0x80 or 0xA0, the exact next drive LBA, and no pending command, IRQ, CD DMA
|
|
or unread payload. Mode 0xA0 may retain only the already-consumed sector's ECC
|
|
tail. The helper witnesses the real raw sector's mode, submode, duplicate
|
|
subheader and BCD address and compares every user byte with resident data.
|
|
XA, FMV, Form2, realtime, changed bytes and busy ownership decline without
|
|
controller mutation. This first version still reads raw sector metadata from
|
|
the mounted image for verification; it does not claim removal of all host I/O.
|
|
|
|
No extra snapshot fields are needed: every accepted effect lives in the
|
|
ordinary controller buffers, cursor, status and IRQ state. The real-controller
|
|
`cdrom_resident_sector_test` covers both modes, repeated one-sector admission,
|
|
24 current-format snapshot restores, subsequent original-stream delivery and
|
|
real Pause completion, plus 33 byte-for-byte atomic decline cases. Existing
|
|
FIFO and IRQ-mask tests also pass. These tests qualify the helper's controller
|
|
contract, not a title adapter or load-time improvement. Tron consumer integration
|
|
and measured runtime outcomes remain pending under beads-eio.3.412/eio.27.3.
|