Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@ ignore = [
# wayland-scanner moves to quick-xml >= 0.40. Full rationale in deny.toml.
"RUSTSEC-2026-0194",
"RUSTSEC-2026-0195",
# webpki-roots (RUSTSEC-2026-0381). cargo-audit can only ignore by ID, so
# this mutes it for every version (cargo-deny's is by ID too); the
# dependency_floor_audit test fails if the lock resolves webpki-roots 1.x
# below the fixed 1.0.10. Full rationale in deny.toml.
"RUSTSEC-2026-0381",
# basic-toml unmaintained (informational) — compile-time only, via
# uniffi's askama derive macro. Full rationale in deny.toml.
"RUSTSEC-2026-0374",
]
36 changes: 36 additions & 0 deletions .github/release-notes/v3.4.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# RustyNES v3.4.2 — "Countersign"

A one-fix patch release on v3.4.1 "Beacon": the RustyNES core in RetroArch loads on Apple Silicon Macs again. Nothing in the emulation core, the desktop, web and mobile apps or the MiSTer core changes. Movies, netplay sessions and save states from v3.4.1 are compatible (epoch 5, protocol 9).

## Fixed

- **The RetroArch core on Apple Silicon Macs.** Loading RustyNES from RetroArch's Online Updater froze RetroArch and dropped it back to the shell, for at least the last few releases; the RustyNES desktop app was not affected. libretro's build template strips the core after linking, which on arm64 leaves the linker's code signature no longer matching the file, and macOS kills any process that loads arm64 code with a broken signature. In the buildbot's core of 2026-10-20, 101 of its 538 signed pages did not match; natively built C cores on the same server checked clean. The arm64 build is no longer stripped, so its signature ships intact, and a test keeps that setting from being dropped. Intel Macs were not affected (an x86_64 core carries no signature).

## Security

- **TLS certificate checks** (RUSTSEC-2026-0382, RUSTSEC-2026-0381, published after v3.4.1): `rustls-webpki` 0.103.16 and `webpki-roots` 1.0.10 stop trusting distrusted emSign intermediates in the netplay signaling and RetroAchievements clients. `webpki-roots` 0.26.11 remains as a dependency of `tungstenite` 0.30.0, but it only re-exports 1.0.10's roots; a new test fails if that ever falls below 1.0.10.
- `basic-toml` (RUSTSEC-2026-0374) is unmaintained, not vulnerable, and used only at compile time inside UniFFI's template macro; it is recorded as an accepted exception.

## Getting the fixed core

RetroArch downloads cores from libretro's nightly build of RustyNES's `main` branch, not from this release page. The fixed core is on the buildbot within about a day of this release. A core you already downloaded stays installed, so **re-download RustyNES in RetroArch's Online Updater (Core Downloader)** to replace it.

## The MiSTer core

- **No new bitstreams.** This release attaches v3.4.1's two bitstreams byte for byte under v3.4.2 names, so the MiSTer menu still shows build date 261019: `RustyNES_MiSTer-v3.4.2.rbf` (off-die, the headline, md5 `474fa68f3f7888aaa6214e74aace2aa8`) and `RustyNES_MiSTer-v3.4.2-lite.rbf` (on-die, md5 `ca92523115ee9d864ce20c13a66a7eb7`).
- **Release candidate, not hardware-verified.** No hardware has run either bitstream.

## Verification

- **Tested on a Mac by the maintainer** (MacBook Pro, M5 Max, macOS 27.0.1, 2026-10-20): the buildbot's own arm64 core of 2026-10-20, with only its code signature repaired (ad-hoc, 0 of 538 pages mismatched), loads in RetroArch, where the unrepaired file had killed it. Same code, signature fixed: that isolates the signature as the cause.
- **Built by libretro's own buildbot with the fix** (pipeline 125851, this release's branch at `e70347a6`): the arm64 core, no longer stripped, carries the linker's own signature, and it verifies with 0 of 538 pages mismatched, the signed range reaching the signature, all 50 `retro_*` exports present. The maintainer loaded this buildbot-built core in RetroArch on the same Mac, and it works. The x86_64 core is built as before.
- `libretro_buildbot_audit` pins the setting in the arm64 job's own `variables`; deleting it fails the test.
- The release audits (anchors, state prose, notes rendering, the libretro `.info`) pass on the bumped tree.

## Install

- Download the pre-built binaries for Linux, macOS, and Windows below.
- The MiSTer bitstreams are attached below as a release candidate, not hardware-verified: `RustyNES_MiSTer-v3.4.2.rbf` (off-die, needs SDRAM) and `RustyNES_MiSTer-v3.4.2-lite.rbf` (on-die).
- The WebAssembly build is live at [doublegate.github.io/RustyNES](https://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.
14 changes: 14 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,26 @@ libretro-build-osx-x64:
- rustup toolchain install ${RUSTUP_TOOLCHAIN} --profile minimal --target ${RUST_TARGET}

# macOS ARM 64-bit
#
# `STRIP_CORE_LIB: "0"` keeps the template from running `$STRIP -S` on the
# linked dylib (v3.4.2). On arm64 the linker ad-hoc signs the library, and
# macOS on Apple Silicon refuses to load arm64 code whose signature does not
# match its bytes: RetroArch is killed outright (SIGKILL) the moment it loads
# the core. The image's strip (osxcross, run on Linux) rewrites the file and
# does not re-sign it. Measured on the buildbot's 2026-10-20 core: 101 of 538
# CodeDirectory page hashes no longer matched, and the signed range ended 32
# bytes short of where the signature had moved to, while two C cores built
# natively on libretro's Mac runner (gambatte, snes9x) verified with 0
# mismatches. The release profile carries no debug info, so `-S` removed
# little; the x86_64 job keeps stripping because an x86_64 dylib carries no
# signature and loads either way. `libretro_buildbot_audit` pins this.
libretro-build-osx-arm64:
extends:
- .libretro-rust-osx-arm64-default
- .core-defs
variables:
RUST_TARGET: aarch64-apple-darwin
STRIP_CORE_LIB: "0"
before_script:
- !reference [.libretro-rust-osx-arm64-default, before_script]
- export SDKROOT=$OSX_SDKROOT
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Enforcement lives alongside the prose: `/ref-proj/` is gitignored/`.dockerignore

RustyNES is a cycle-accurate Nintendo Entertainment System emulator written in pure Rust. The accuracy bar is Mesen2 / higan / ares: tight lockstep scheduling at PPU-dot resolution on a master-clock-precise timebase, sub-instruction PPU events visible to subsequent CPU code, and a lookup-table non-linear audio mixer with band-limited synthesis. The frontend is pure Rust (`winit` + `wgpu` + `cpal` + `egui`).

**Current release: v3.4.1 "Beacon"** (2026-10-19) — the hosted netplay lobby live with the browser and mobile builds pointing at it (the TURN relay deployed but held off: Cloudflare kept honouring expired and revoked credentials), the browser RetroAchievements build fixed (web RA held until RetroAchievements answers the integration request), version-named MiSTer release assets, and the MiSTer save engine's cartridge-change defects and v3.4.0's two build findings fixed. Built on **v3.4.0 "Waypoint"** (2026-10-18) — netplay authenticated and three and four players on the desktop, RetroAchievements hardcore held to RA's full block list, the hosted services shipped as code (deployed in v3.4.1), the window thread's CPU halved, and the MiSTer core's headline build made the off-die one, with save states, rewind and Phase F3a's boards. Built on **v3.3.0 "Plumbline"** (2026-10-16) — v3.2.0's leftovers settled and its claims re-measured: CHR-RAM writes go through the bank registers on seven boards, mapper 71 decodes its bank select as documented, v3.1.x Bandai states load again, a v3.2.0 performance figure is withdrawn, the IRQ trace goldens became a test, and, in simulation, the MiSTer core's off-die build reads CHR-RAM back and loads CHR correctly. Built on **v3.2.0 "Confluence"** (2026-10-15) — every v3.2.0 branch in both repositories brought into one release: 17 mapper families (208 in all), the VRC4 IRQ fix, an AI remediation branch audited change by change, netplay protocol 8, slim libretro states, and sixteen more boards on the MiSTer core. Built on **v3.1.0 "Bellwether"** (2026-10-08) — the AccuracyCoin re-sync and an honest 146/146, the CPU overclock and the sprite-limit option in movies and netplay, PAL emphasis, the alternate MMC3, rewind and run-ahead on the Vs. cabinet, and the MiSTer core matched to all of it. Built on **v3.0.1 "Mortar"** (2026-10-07) — a maintenance release: one game's graphics fixed, the MiSTer core's last MMC3 rule exception tested, Rust 1.99 everywhere, every unanswered bot review answered, and the plan to v4.0.0. Built on **v3.0.0 "Cornerstone"** (2026-10-06) — the API major: every break since v2.x in one place, a core timing epoch for movies and netplay, the last MMC3 timing gap closed in both cores, and a release-candidate MiSTer core ([ADR 0043](docs/adr/0043-v3-is-the-api-major-and-a-release-candidate-core.md)). **No hardware has run any MiSTer bitstream**: hardware verification moves to a later v3.x release (ADR 0043 supersedes [ADR 0041](docs/adr/0041-hardware-release-is-v3.0.0.md)'s hardware-verified v3.0.0), and the SDRAM pin constraints stay provisional until the SuperStation One's memory is read. Suite counts, mapper matrix and per-release detail live in `docs/STATUS.md`, `CHANGELOG.md` and the GitHub releases; they are deliberately not duplicated here. The earlier release-by-release narrative and other condensed paragraphs are archived verbatim in `docs/history/AGENTS-archive.md`.
**Current release: v3.4.2 "Countersign"** (2026-10-20) — the RetroArch core loads on Apple Silicon Macs again. Built on **v3.4.1 "Beacon"** (2026-10-19) — the hosted netplay lobby live with the browser and mobile builds pointing at it (the TURN relay deployed but held off: Cloudflare kept honouring expired and revoked credentials), the browser RetroAchievements build fixed (web RA held until RetroAchievements answers the integration request), version-named MiSTer release assets, and the MiSTer save engine's cartridge-change defects and v3.4.0's two build findings fixed. Built on **v3.4.0 "Waypoint"** (2026-10-18) — netplay authenticated and three and four players on the desktop, RetroAchievements hardcore held to RA's full block list, the hosted services shipped as code (deployed in v3.4.1), the window thread's CPU halved, and the MiSTer core's headline build made the off-die one, with save states, rewind and Phase F3a's boards. Built on **v3.3.0 "Plumbline"** (2026-10-16) — v3.2.0's leftovers settled and its claims re-measured: CHR-RAM writes go through the bank registers on seven boards, mapper 71 decodes its bank select as documented, v3.1.x Bandai states load again, a v3.2.0 performance figure is withdrawn, the IRQ trace goldens became a test, and, in simulation, the MiSTer core's off-die build reads CHR-RAM back and loads CHR correctly. Built on **v3.2.0 "Confluence"** (2026-10-15) — every v3.2.0 branch in both repositories brought into one release: 17 mapper families (208 in all), the VRC4 IRQ fix, an AI remediation branch audited change by change, netplay protocol 8, slim libretro states, and sixteen more boards on the MiSTer core. Built on **v3.1.0 "Bellwether"** (2026-10-08) — the AccuracyCoin re-sync and an honest 146/146, the CPU overclock and the sprite-limit option in movies and netplay, PAL emphasis, the alternate MMC3, rewind and run-ahead on the Vs. cabinet, and the MiSTer core matched to all of it. Built on **v3.0.1 "Mortar"** (2026-10-07) — a maintenance release: one game's graphics fixed, the MiSTer core's last MMC3 rule exception tested, Rust 1.99 everywhere, every unanswered bot review answered, and the plan to v4.0.0. Built on **v3.0.0 "Cornerstone"** (2026-10-06) — the API major: every break since v2.x in one place, a core timing epoch for movies and netplay, the last MMC3 timing gap closed in both cores, and a release-candidate MiSTer core ([ADR 0043](docs/adr/0043-v3-is-the-api-major-and-a-release-candidate-core.md)). **No hardware has run any MiSTer bitstream**: hardware verification moves to a later v3.x release (ADR 0043 supersedes [ADR 0041](docs/adr/0041-hardware-release-is-v3.0.0.md)'s hardware-verified v3.0.0), and the SDRAM pin constraints stay provisional until the SuperStation One's memory is read. Suite counts, mapper matrix and per-release detail live in `docs/STATUS.md`, `CHANGELOG.md` and the GitHub releases; they are deliberately not duplicated here. The earlier release-by-release narrative and other condensed paragraphs are archived verbatim in `docs/history/AGENTS-archive.md`.

- **Native Android app** — the **v1.8.0 → v1.8.9 "Android"** train (`crates/rustynes-mobile` UniFFI bridge + `crates/rustynes-android` JNI/NDK host + a Jetpack Compose app, ADR 0024): full on-device emulation, multi-touch + P1–P4 hardware controllers, wgpu `SurfaceView` rendering + the shared WGSL shader stack, save-states / battery SRAM, Lua, RetroAchievements, direct-IP + CGNAT/TURN room-code netplay, a box-art ROM library, and platform polish (adaptive / foldable / TV, Material You, capture / PiP / home-screen widget). Distributed as **GitHub-Releases sideload**; a free store listing is an unversioned later step with no monetization (ADR 0035, which superseded ADR 0025's v2.3.0 date; the `foss`/`play` flavour split remains).
- **Native iOS / iPadOS app** — the **v1.9.0 → v1.9.9 "iOS" TestFlight train** (`crates/rustynes-ios` Metal + CoreAudio shim reusing `rustynes-mobile` verbatim → UniFFI-generated Swift, ADR 0026): a native SwiftUI shell over wgpu→Metal, multi-touch + GameController, the shader stack, TAS / HD-pack / palettes / per-game DB, Lua + RetroAchievements, LAN + room-code netplay, CloudKit save-state sync, accessibility + EN/ES i18n + ReplayKit + Game Center, and the v1.9.9 creator tools (Cheats, a FOSS-gated read-only debugger, a touch TAStudio piano-roll, foreign movie import, a host audio-depth DSP). Ships to **TestFlight**; a free App Store listing is an unversioned later step with no monetization (ADR 0035, which superseded ADR 0027's v2.3.0 date). Mobile ROM loading was iNES / NES 2.0 only until v2.9.7, which adds FDS (host-supplied BIOS), NSF and the Vs. DualSystem cabinet to the bridge (the Swift half uncompiled; run-sheet rows T1-T12). Readiness record: `docs/ios-v1.9.9-readiness.md`.
Expand Down Expand Up @@ -236,7 +236,7 @@ that is a reason to add a tenth — not a reason to grow this section back.
- `ref-docs/` is immutable. Research updates go in dated supplemental files.
- ADRs go in `docs/adr/` (Michael Nygard format).
- `rustynes-core` re-exports the public types from the chip crates; downstream consumers (`rustynes-frontend`, `rustynes-test-harness`) should depend on `rustynes-core` rather than the chip crates directly.
- When relabeling old engine "v2.x" narrative for users, present it as upstream lineage/history — **never as a current RustyNES release version.** The current release is **v3.4.1 "Beacon"** (2026-10-19). **Never claim any version *later* than v3.4.1 is released.** Two distinct "v2.0"s exist and must not be conflated: the **engine-lineage v2.0** master-clock work shipped as the **v1.0.0** production core (2026-06-13) and was the only scheduler through v1.10.0; RustyNES's own **v2.0.0 "Timebase"** (2026-07-03) is a different milestone that REPLACES that dot-lockstep scheduler with the one-clock, every-cycle-bus-access model (ADR 0002 / 0028 / 0029) and broke byte-identity and save-state compatibility, by design (v2.9.8 later broke save, movie and API compatibility again, ahead of v3.0.0). The per-release narrative that used to be inlined here is in `CHANGELOG.md`, the per-release notes under `.github/release-notes/`, and the published GitHub releases — three places that are maintained, against one copy here that was not.
- When relabeling old engine "v2.x" narrative for users, present it as upstream lineage/history — **never as a current RustyNES release version.** The current release is **v3.4.2 "Countersign"** (2026-10-20). **Never claim any version *later* than v3.4.2 is released.** Two distinct "v2.0"s exist and must not be conflated: the **engine-lineage v2.0** master-clock work shipped as the **v1.0.0** production core (2026-06-13) and was the only scheduler through v1.10.0; RustyNES's own **v2.0.0 "Timebase"** (2026-07-03) is a different milestone that REPLACES that dot-lockstep scheduler with the one-clock, every-cycle-bus-access model (ADR 0002 / 0028 / 0029) and broke byte-identity and save-state compatibility, by design (v2.9.8 later broke save, movie and API compatibility again, ahead of v3.0.0). The per-release narrative that used to be inlined here is in `CHANGELOG.md`, the per-release notes under `.github/release-notes/`, and the published GitHub releases — three places that are maintained, against one copy here that was not.
- **Forward plans + roadmap live in `to-dos/`.** `to-dos/ROADMAP.md` (updated in #129) is the planning entry point and frames the release line + "the path to v2.0.0 and beyond"; `to-dos/plans/` holds the per-release plan docs (through `v1.7.0-forge-plan.md` on `main`, plus the staged-forward `v1.8.0-android-plan.md` / `v1.9.0-ios-plan.md` / `v2.0.0-master-clock-plan.md`) + the `to-dos/plans/engine-lineage/` history archive + a `to-dos/plans/research/` reference-mining archive.
- The v1.0.0 release + GitHub Pages/CI + post-release record is in `docs/v1.0.0-synthesis-handoff-2026-06-13.md` — read it before touching CI, Pages, or release tooling. Full per-release history is in `CHANGELOG.md`.
- **Markdownlint is a CI gate** (pre-commit, pinned `markdownlint-cli v0.49.1`). The pin was v0.39.0 until the v2.6.3 dependency refresh, held because the newer local binary reported rules the pin lacked — chiefly **MD060** (`table-column-style`), which was therefore NOT gated. That is now measured and resolved: MD060's inferred default reads this corpus as style `compact` and reports **1,936 findings across 122 files** and nothing else, so `.markdownlint.json` pins `MD060` to the style actually in use (`leading_and_trailing`), which measures **zero** and rewrites no document. It IS a gate now. Still verify with `pre-commit run markdownlint --all-files` rather than the bare binary — the pin and the local build can drift apart again. `.markdownlint.json` also keeps `MD013`/`MD033`/`MD041` disabled by design (long technical tables, the README HTML banner/`<img>`, the HTML-led README). `.markdownlintignore` exempts `ref-docs/`, `ref-proj/` (the reference-emulator clone, now removed from disk but kept in the ignore lists as a firewall guard so it can never re-enter the tree — see the MOST IMPORTANT RULE section above), the vendored `tricnes/` + upstream READMEs, and the frozen `docs/archive/` + `to-dos/archive/` trees — don't lint or reformat those.
Expand Down
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Document Version:** 2.1.0
**Last Updated:** 2026-10-07
**Applies to:** RustyNES v3.4.1 (the scheduling model is v2.0.0 "Timebase" onward)
**Applies to:** RustyNES v3.4.2 (the scheduling model is v2.0.0 "Timebase" onward)

This document fixes the high-level architecture of RustyNES. The per-subsystem specs under `docs/` (`cpu-6502.md`, `ppu-2c02.md`, `apu-2a03.md`, `mappers.md`, `scheduler.md`) take these decisions as given and elaborate one chip each. After reading this you should know the workspace shape, the scheduling model, the public boundary, and the load-bearing invariants. The canonical, always-current architecture spec is [`docs/architecture.md`](docs/architecture.md); this file is the top-level companion.

Expand Down
Loading
Loading