RustyNES v2.9.2 — "Candidate" (the full audit acted on, and the release-candidate pair)
RustyNES v2.9.2 — "Candidate"
The third release of the v2.9.x line that ADR 0041 put before the SuperStation One core (v3.0.0). It does two things: it acts on a fifth audit, and it cuts the bitstream pair the board session runs.
No hardware has run any bitstream. These are the bitstreams the SuperStation One session will run; what it finds becomes v2.9.4 and later.
A fifth audit, finding by finding
The maintainer added an AI-written audit of both repositories: 32 findings, kept exactly as supplied in docs/audits/v2.9.2-full-audit-report.md. Every one has a verdict and its evidence in the ledger. A fix counts only when a test failed on it first and a deliberate revert of the fix is caught.
16 of the 32 are fixed, and two more are changed but can only be verified on a device. The report read the Rust well and the hardware description poorly: 16 of its 20 Rust findings are real, but only 3 of its 12 RTL and build findings. Its framing was often wrong even when the defect was real. For example, a "memory exhaustion" was a 32-bit-only overflow, and a "garbage-collector churn" was a native allocation.
The fixes that matter to players:
- Save states keep your cartridge RAM on twelve board families. The save-state format carries cartridge RAM only inside each mapper's own section. Konami VRC2/4/6/7 left out their work RAM and CHR-RAM; MMC4 (Fire Emblem) left out its battery RAM. Eight more boards, BNROM (Deadly Towers) among them, left out their CHR-RAM. A state load, a rewind step, a run-ahead frame or a netplay rollback kept the running game's RAM instead of the saved one. A test now round-trips the RAM of every mapper the emulator supports (all 174, each submapper, with and without CHR-ROM), so a board cannot regress unnoticed. Save states from earlier releases still load.
- A netplay peer can no longer make your session allocate memory it names. One datagram claiming frame 4,294,967,295 asked for about four billion entries in six tables. Frames too far ahead are now dropped; real play runs at most 14 frames ahead.
- Unplugging a gamepad releases its buttons and frees its port.
- Opposing directions cancel on desktop and Android (and iOS, in code not yet built on a device): Up+Down or Left+Right reads as neither, as on a real D-pad. Movies, TAStudio, Lua and netplay peers' input are never altered. On desktop it can be turned off in Settings → Input; Android and iOS have no switch yet. It is on by default by the maintainer's decision, an explicit exception to the project's rule that new behaviour starts off: a real D-pad cannot report both directions, so the cleaned input is the faithful one.
- A crafted FDS save state can no longer crash the 32-bit builds (web, 32-bit Android, i686).
- In RetroArch, the core withdraws its memory maps even when a frontend skips unloading the game. The first run-ahead frame no longer allocates, and a two-screen Vs. frame is no longer zero-filled before it is drawn.
One change touches emulation output: a read of an unmapped cartridge address now updates the CPU's internal data bus, which $4015 bit 5 reads. This follows nesdev's open-bus documentation. AccuracyCoin stays 144/144 and nestest 0-diff.
The MiSTer core
- The CPU no longer loses an NMI raised inside a DMA. The NMI edge detector ran on the clock enable that a DMA stalls. On the real chip it keeps sampling while the CPU is halted. A new gate,
dmanmi074, differed from the emulator in 156,031 of 357,820 cycles before the fix, and in none after. make build-fastno longer leaves the project file modified, which had made the next release build refuse to run.make cleanremoves the off-die build and the sweep logs too. The release script attaches the off-die bitstream itself.- Gates for two claims the audit got wrong: the SDRAM arbiter's overrun report, and a monitor that fails the run if a refresh interval is ever lost. The longest wait measured is 10 cycles of a 654-cycle interval.
- A board kit.
tools/stage_board_kit.shstages the test corpus, the launchers, both bitstreams and the checksums the session compares against, and the bring-up log has rows for the off-die build. - The core's reference pin moves to v2.9.1; all 117 golden traces regenerate byte for byte.
- Both builds re-swept, eight seeds each at one build date, all sixteen closing timing. The pin stays at seed 2, which again has the most on-die margin on both measures.
Verification
| Check | Result |
|---|---|
cargo test --workspace --features test-roms |
2,867 passed, 0 failed, 20 ignored |
| AccuracyCoin / nestest | 144/144 / 0-diff |
| fmt, clippy (every feature set, wasm), rustdoc, no_std build | clean |
| Co-simulation, on-die | 173 passed, 0 failed, 1 expected failure (one frozen-worktree run, nothing skipped) |
Co-simulation, off-die (USE_SDRAM=1) |
174 passed, 0 failed, 1 expected failure (one frozen-worktree run, nothing skipped) |
| Quartus 17.0.2, seed 2, on-die | setup +0.510 ns, hold +0.108 ns; 22,546 ALMs, 468 RAM blocks, 33 DSP; two clean compiles byte-identical |
| Quartus 17.0.2, seed 2, off-die | setup +0.390 ns, hold +0.081 ns (SDRAM read +0.447 / +1.184 ns); 22,614 ALMs, 84 RAM blocks, 33 DSP; two clean compiles byte-identical |
Not verified here: the Swift changes (the iOS D-pad and turbo pacing) are uncompiled, and they join the device checklist at v2.9.3. The Android NTSC-filter buffer change has no host test.
Next: the SuperStation One session on these bitstreams, then v2.9.3's mobile device checklist.
Install
- Download the pre-built binaries for Linux, macOS, and Windows below.
- The MiSTer core bitstreams are attached below:
RustyNES_MiSTer-v2.9.2.rbf(on-die) andRustyNES_MiSTer-v2.9.2-offdie.rbf(cartridge in SDRAM; its name is provisional until v3.0.0). Neither has run on hardware. - The WebAssembly build is live at doublegate.github.io/RustyNES.
- The RetroArch core is in RetroArch's Online Updater on the platforms the libretro buildbot publishes to.
- Licensed under GPL-3.0-or-later.