RustyN64 v0.7.0
RustyN64 v0.7.0 "Shell" — Phase 6 (the first playable release)
Phase 6 wires the egui/wasm frontend to the real machine. RustyN64 now presents
a picture, plays sound, and takes controller input — end to end through the LLE
core — and can save, load, rewind, and run-ahead. This is the first release that
is playable.
== Executive summary ==
The shell presents the REAL machine, not a test pattern:
- The window is driven by the VI scan-out (Bus::scanout, the LLE RDP/VI path).
- The audio ring is fed by the real AI drain (the libdragon mixer microcode
runs on the LLE RSP; the frontend resamples to the host device). - The pad reaches the game through the SI joybus.
New frontend capabilities, all frontend-side and off by default (ADR 0004, so
output stays byte-identical when unused):
- Save-states: the whole System is serde-serialisable; restore is bit-identical.
- Rewind: a bounded ring capturing a snapshot every N frames.
- Run-ahead: present a speculatively-advanced frame, then restore the real
timeline (speculative audio discarded). - A wasm browser entry point: a #[wasm_bindgen(start)] 2D-canvas demo that boots
a homebrew ROM and blits the VI scan-out via web-sys, built with trunk.
== Honest scope of "playable" ==
Picture, sound, and control are demonstrated NATIVELY on the committed homebrew
ROMs through the real LLE VI/AI/SI paths, and save-state restore is bit-identical
(proven on a booted COMMERCIAL ROM). A commercial title boots and executes real
code but does NOT yet reach a rendered frame — the cross-subsystem VI-vblank /
RI-register / F3DEX gap tracked as accuracy-ledger R-18, deferred to the Phase
3/7 rasteriser + microcode work (v0.8.0 "Breadth"). This ships on the
demonstrated-playable path plus an honest ledgered gap, per the plan's escalation
gate — never a faked commercial pass.
== Exit criteria (oracle results, committed runners) ==
- Native picture + sound + control on a real ROM (Phase 6 committable gate): MET
— homebrew renders a verified golden frame via the VI (real_rom_frame), plays
deterministic PCM via the AI (audio_play_rom), and reads the pad via the SI. - Save-state restore continues bit-identically (Phase 6 capstone): MET — a
two-run trace compare (tests/savestate.rs) on a homebrew ROM (committable) and
a booted commercial ROM (full RSP/RDP/AI/cart machine, local-only). - A commercial ROM playable WITH A PICTURE (VERSION-PLAN's literal criterion):
DEFERRED (ledger R-18), validated when the Phase 3/7 work closes it.
== Technical details ==
- Retail boot moved into the core (rustyn64_core::boot, ADR 0010): hle_boot,
real_pif_boot, cic_seed, BootError are core APIs; the frontend and harness both
consume them. EmuCore::load_rom now HLE-boots, so the shell runs a game. - Save-state serialisation: serde derives across every state type in
rustyn64-cpu/-rsp/-rdp/-audio/-cart/-core; a new rustyn64-snapshot leaf crate
provides #[serde(with)] helpers for the boxed-array backing stores; the
cartridge ROM is #[serde(skip)]'d and re-attached on restore. Chip crates stay
#![no_std] (serde's alloc feature). - wasm: native host deps (cpal/gilrs/rfd/directories) gated to
cfg(not(target_arch = "wasm32")); wasm-bindgen pinned =0.2.126 to match
web/Trunk.toml's CLI pin (the wasm-bindgen-pin CI gate). The load offset is
derived from the ROM entry (entry & 0x1FFF_FFFF), matching real IPL3 semantics.
== Testing evidence ==
- 712 workspace tests pass.
- Full CI matrix green: macOS, Windows, ubuntu, and the test-roms job, plus fmt,
clippy (native + wasm32 target), rustdoc (-D warnings), no_std, trunk-pin,
and no-commercial-ROMs. - trunk build --release produces a working browser demo (dist/).
== Version ==
All workspace crates bumped 0.6.0 -> 0.7.0. Docs reconciled: STATUS.md,
CHANGELOG.md, VERSION-PLAN.md, ROADMAP.md, README.md.
Next: v0.8.0 "Breadth" (Phase 7 — the accuracy battery; the commercial title
frame that R-18 defers lands there).