Skip to content

Latest commit

 

History

929 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

RustyNES

RustyNES Logo Icon

Precise. Pure. Powerful.

RustyNES Banner Logo

Build Status License: GPL-3.0-or-later Version Rust: 1.96
AccuracyCoin nestest Mapper families Try in browser
Platform

RustyNES is a cycle-accurate Nintendo Entertainment System emulator written in pure Rust. It aims at the Mesen2 / higan / ares accuracy bar: one master clock, every CPU cycle a real bus access, and the PPU caught up to each half of it, so a sprite-zero hit, a mid-scanline scroll write or an MMC3 IRQ lands on the exact dot without a per-game patch. It passes AccuracyCoin 144/144 and matches the Nintendulator nestest log with zero diff.

Around that core sits a complete, modern platform: 191 mapper families, the Famicom Disk System, Vs. System and PlayChoice-10 arcade boards, rollback netplay, RetroAchievements, a TAStudio piano-roll editor, a Mesen2-class debugger, HD packs, a shader stack, and native apps for desktop, the browser, Android, iOS and RetroArch, all on one bit-deterministic core.

Play it in your browser, no install required.

Development note: AI-assisted. RustyNES is built with LLM tooling under a human-directed, test-driven workflow, with public test ROMs as the oracle. See docs/originality-and-provenance.md for what that means for originality and licensing. The accuracy claims are meant to be checked by running the public suites, not taken on faith. A comparison to another emulator is a comparison, not a claim of being better.

A grid of commercial NES titles running on RustyNES: Donkey Kong, Excitebike, Super Mario Bros., Kid Icarus, Castlevania, Contra, Mega Man, and Mike Tyson's Punch-Out!!


Contents


Highlights

Cycle-accurate CPU, PPU and APU on one master clock: AccuracyCoin 144/144, nestest 0-diff, blargg's CPU, APU and PAL suites
191 mapper families NROM through MMC5, the whole VRC line, Sunsoft FME-7, Namco 163, Taito, J.Y. Company, the MMC3 and MMC1 multicarts, Waixing and Nanjing boards, homebrew flash boards with working saves, and a UNIF (.unf) loader. Each is classified Core, Curated or BestEffort by the evidence behind it
Famicom Disk System Real-BIOS boot, writable disks, side swapping, a timed disk-head model and 2C33 wavetable audio
Vs. / PlayChoice-10 Arcade boards in true 2C03 / 2C04 / 2C05 RGB, per-game DIP presets, and Vs. DualSystem two-screen cabinets
Rollback netplay GGPO-style, up to four players over UDP or browser WebRTC, with room codes, TURN traversal and spectators
RetroAchievements Achievements, leaderboards, rich presence and hardcore mode through the rcheevos library
TAStudio A piano-roll TAS editor with a greenzone, branches and markers, plus .fm2 / .bk2 / .fcm / .fmv / .vmv import
Debugger Conditional breakpoints, watchpoints, a hex editor, RAM search, a callstack, .dbg source maps, and editable palette, nametable, CHR and OAM
Video and audio NTSC composite filtering, a CRT shader stack, HD packs with OGG audio, .pal palettes, a generated NTSC palette, and an NSF / NSFe player
Save states, rewind, run-ahead All on the deterministic snapshot path, so a replay is bit-identical
Lua scripting A sandboxed Lua 5.4 engine with memory access, callbacks, an HUD and a TAStudio API
Everywhere Linux, macOS and Windows binaries, a WebAssembly build, Android and iOS apps, and a libretro core for RetroArch

Quick start

Download

Pre-built binaries for every release are on the Releases page: Linux x86_64, macOS (Apple silicon) and Windows x86_64. From v2.9.7 they are the full native build: RetroAchievements, Lua scripting, HD packs, A/V recording (with ffmpeg on your PATH) and the debugger telemetry are all included.

# Linux / macOS
tar xf rustynes-<tag>-<target>.tar.gz && ./rustynes path/to/rom.nes
# Windows (PowerShell)
Expand-Archive rustynes-<tag>-x86_64-pc-windows-msvc.zip; .\rustynes.exe path\to\rom.nes

Launch it without a ROM and use F12, the File menu, or drag and drop a .nes / .fds onto the window.

Build from source

You need Rust 1.96 (pinned in rust-toolchain.toml; rustup installs it) and Git.

git clone https://github.com/doublegate/RustyNES.git
cd RustyNES
cargo run --release -p rustynes-frontend -- path/to/rom.nes

# Everything native at once: RetroAchievements, Lua, host IPC, HD packs,
# debugger telemetry and A/V recording.
cargo full-run path/to/rom.nes

On Linux, the window, GPU and audio stack need a few system libraries:

# Ubuntu / Debian
sudo apt-get install -y libxkbcommon-dev libwayland-dev libxkbcommon-x11-dev libasound2-dev libudev-dev
# Arch / CachyOS
sudo pacman -S --needed libxkbcommon wayland alsa-lib systemd-libs

macOS and Windows need nothing extra; the optional retroachievements feature needs a C compiler on every platform.

rustynes --help lists the command-line options, and rustynes help opens an interactive guide to the controls, hotkeys, mappers, configuration, scripting and netplay.

In the browser

The hosted build is at doublegate.github.io/RustyNES. To build it yourself, install trunk and run trunk serve in crates/rustynes-frontend/web.


Features

Emulation core

  • One master clock. A single cycle counter drives the CPU, PPU and APU at the region-exact ratios (3:1 NTSC and Dendy, 3.2:1 PAL). Every CPU cycle is clocked in two halves with the PPU caught up to each, so events inside an instruction are visible to the next access.
  • 6502. All 256 opcodes including the unstable ones, per-cycle bus access, exact interrupt polling, and OAM and DMC DMA through one unified model.
  • 2C02. A per-dot pipeline, the cycle-resolution sprite-evaluation state machine with its hardware overflow bug, and the rendering-time $2007 behaviour.
  • 2A03. The non-linear mixer, band-limited synthesis, the analog filter chain, and expansion audio for VRC6, VRC7, MMC5, Namco 163, Sunsoft 5B and the FDS.
  • Determinism. The same seed, ROM and input give a bit-identical framebuffer and audio, which is what makes save states, replays, regression tests and rollback netplay correct by construction.

Cartridges

  • 191 mapper families, written from the NESdev wiki and pinned by test ROMs, unit tests and a commercial-ROM oracle. docs/mappers.md lists every family, its tier and its evidence.
  • Self-flashing homebrew boards (GTROM, UNROM 512) emulate their SST39SF040 flash chip, so games that save by rewriting their own ROM keep those saves.
  • Battery saves persist on desktop, Android and iOS, and in the browser (IndexedDB, from v2.9.7).
  • Famicom Disk System with a user-supplied disksys.rom, and UNIF boards mapped to their iNES numbers.

Playing

  • Netplay: GGPO-style rollback for two to four players over UDP or browser WebRTC, with a deployable signaling bundle in deploy/.
  • RetroAchievements on desktop, Android, iOS and the libretro core.
  • Speed and pacing: 25-300% speed, fast-forward, frame advance, rewind, run-ahead, and display-synced, VRR or wall-clock pacing.
  • Input: USB gamepads with hot-plug and remapping, turbo, the Four Score, Zapper, Arkanoid paddle, Power Pad, keyboards and mouse.
  • Cheats: a Game Genie encoder with a ~10,800-code database, and raw RAM cheats.

Creating and debugging (opt-in features)

  • TAStudio: a piano-roll editor with a save-state greenzone, lag log, markers and branches, and movie import from FCEUX, BizHawk and others.
  • Debugger: breakpoints on expressions and conditions, R/W/X watchpoints, a trace logger, an event viewer, a hex editor, RAM search, a callstack, and ca65 / cc65 source maps. The inspectors become editors on request.
  • Lua 5.4 scripting: memory and state access, per-frame and per-access callbacks, an HUD, and host IPC for automation. See docs/scripting.md.
  • HD packs: a Mesen-format loader with OGG audio, and a builder that authors packs from the running game.
  • A/V recording to .mp4 / .mkv through ffmpeg.

Display and audio

  • An NES-NTSC composite / S-video filter, a CRT and scanline shader stack, hqNx and xBRZ upscalers, and a constrained RetroArch .slangp importer.
  • Custom .pal palettes, a generated NTSC palette, and a choice of analog filter models.
  • An NSF / NSFe player through the real APU and expansion synths.
  • Every display option is off the core's path, so the emulated framebuffer is unchanged by it.

Mobile

  • Android: a Jetpack Compose app with touch and hardware controllers, the shared shader stack, save states, netplay, RetroAchievements and Lua. Distributed through GitHub Releases. See docs/android.md.
  • iOS / iPadOS: a SwiftUI app on Metal with GameController support, iCloud save sync and ReplayKit. Distributed through TestFlight. See docs/ios.md.

Both apps run the same core as desktop, and both are free: RustyNES is permanently non-commercial (ADR 0035).


Controls

Every binding can be changed in Settings or in the TOML config; the controls guide has the full list. USB gamepads bind to player 1 automatically.

Action Player 1 Player 2
D-pad Arrow keys W / A / S / D
A / B Z / X Q / E
Start / Select Enter / Right Shift P / R
Action Key Action Key
Pause Space Save / load state F1 / F4
Fast-forward (hold) Tab Rewind (hold) F5
Frame advance \ Reset / power cycle F2 / F3
Speed up / down / reset = / - / 0 Open ROM F12
TAS record / play / branch F6 / F7 / F8 FDS disk side F9
Menu bar M Vs. coin F10
Debugger ` Fullscreen F11
Quit Esc Famicom microphone N (hold)

Accuracy

Suite Result
AccuracyCoin 144/144 (100.00%), read from RAM rather than the screen
nestest 0-diff against the Nintendulator log
blargg cpu_interrupts_v2 5/5, and the unstable-store tests 6/6
blargg APU (NTSC and PAL) 11/11 and 10/10
blargg apu_test frame-counter probes 10/10
region_timing 4/4, including PAL's 3.2:1 ratio
Holy Mapperel every committed variant reports detail code 0000
Commercial-ROM oracle 99 titles, SHA-256-pinned, byte-identical frames

The one known residual in the battery is mmc3_test_2/4-scanline_timing sub-test 3, a one-PPU-clock MMC3 reload timing that affects no AccuracyCoin entry and no commercial game. Every other known approximation is listed, with its evidence, in docs/accuracy-ledger.md, and the per-suite detail is in docs/STATUS.md.

When a document and a passing test ROM disagree, the ROM wins: that is this project's definition of cycle-accurate.

Mapper tiers. Of the 191 families, 160 are accuracy-gated: 51 Core and 109 Curated, each backed by a test ROM, a commercial dump, or a precise register description with a synthetic fixture. The other 31 are BestEffort: their documentation is thin, and a CI gate keeps them out of every accuracy claim.


Platforms

Platform Status
Linux x86_64, Windows x86_64, macOS (Apple silicon) Release binaries
macOS (Intel), Linux ARM64 Build from source
WebAssembly Hosted and buildable
Android (arm64) GitHub Releases (sideload)
iOS / iPadOS TestFlight
RetroArch rustynes_libretro core, published by the libretro buildbot

A GPU with a wgpu backend is required: Vulkan, Metal, DX12, or WebGPU / WebGL2 in the browser. The headless core runs a frame in about 4 ms on an Intel i9-10850K, about four times faster than real time; docs/performance.md has the measurements.


Architecture

RustyNES is a Cargo workspace of focused crates. Three decisions carry the design, detailed in docs/architecture.md and docs/scheduler.md:

  1. One master clock. Each CPU cycle runs in two halves around its bus access, and the PPU, APU and DMA are caught up to each half.
  2. The bus owns everything mutable. It holds the PPU, APU, cartridge, work RAM and controllers, and the CPU borrows it one instruction at a time. That single choice avoids the borrow-checker fight of the alternative.
  3. A one-directional dependency graph. The chip crates are no_std and do not depend on each other, so each can be fuzzed and benchmarked alone.

RustyNES Component Architecture Blueprint

Crate Role
rustynes-cpu, rustynes-ppu, rustynes-apu The 6502, 2C02 and 2A03
rustynes-mappers 191 mapper families, expansion audio, the UNIF loader
rustynes-core The bus, scheduler, console and save states
rustynes-frontend The winit + wgpu + cpal + egui application (rustynes)
rustynes-netplay Rollback netcode over UDP and WebRTC
rustynes-script Sandboxed Lua 5.4
rustynes-cheevos, rustynes-ra RetroAchievements
rustynes-hdpack, rustynes-gfx-shaders HD packs and the shared WGSL shaders
rustynes-mobile, rustynes-android, rustynes-ios The mobile bridge and platform glue
rustynes-libretro The RetroArch core
rustynes-test-harness Integration tests and the accuracy oracles

Documentation

User guide Installing, controls, save states, the debugger, configuration, FAQ
Documentation handbook The subsystem specs and user guide as a website
API documentation Rustdoc for the whole workspace
Status Current state: per-suite results, the mapper matrix, feature flags
Changelog Every release, newest first
Hardware specs CPU, PPU, APU, mappers, testing, netplay
Decisions Architecture Decision Records
Libretro core The RetroArch core and how to set it up
Accuracy ledger Every known approximation, with its evidence

Current release

RustyNES's current release is v2.9.7 "Tandem" (2026-09-30) — the desktop's features on the web and on phones, the release binaries built with every native feature, and a PPU A12 fix found by real games: Acclaim's MC-ACC games, the J.Y. ASIC and mapper 91 now count at their documented rates. Built on v2.9.6 "Roster" (2026-09-30) — seventeen mapper families written from their NESdev pages (174 → 191), GTROM promoted to Curated with a modelled flash chip whose saves persist, mapper 4's NES 2.0 submappers corrected (MMC6, NEC, MC-ACC, T9552), and the local commercial suites re-baselined after drifting unread since about v2.0.0.

The per-release detail, back to v0.1.0, is in CHANGELOG.md and on the Releases page.


Roadmap

The line runs to v3.0.0, the API major with a release-candidate MiSTer core (ADR 0043). Before it: more mapper families, platform features that are already designed, performance work, and a final re-audit. v3.0.0 removes the APIs deprecated since v2.7.5 (ADR 0042). Verifying the MiSTer core on hardware comes after it, in v3.x.

The full plan is to-dos/ROADMAP.md, with one plan per release in to-dos/plans/. A free mobile store listing may follow later, with no monetization of any kind.


The MiSTer core

A sibling project writes a new NES core in SystemVerilog for the MiSTer FPGA platform, from public hardware documentation, and uses this emulator as its verification oracle through crates/rustynes-cosim. RustyNES itself is not being ported to an FPGA: what can be built is a new implementation checked against this one, cycle by cycle.

Its co-simulation ladder covers the 6502, the bus and interrupts, the 2C02, the 2A03, AccuracyCoin parity and six mapper boards. Each release attaches a timing-closed bitstream. No hardware has run any bitstream yet, so a booting core, a synced display, audible sound and a working pad are not claimed. The details, and what each rung can and cannot verify, are in docs/mister.md.

Six commercial titles rendered by the MiSTer core's RTL under Verilator, each byte-identical to this emulator
Six commercial cartridges, one per supported board, rendered by the MiSTer core's RTL under Verilator, each byte-identical to this emulator over all 61,440 pixels. No hardware has run it.


Contributing

Contributions of every kind are welcome. CONTRIBUTING.md explains the quality gates, the Conventional Commit format, and the rule that a change to chip behaviour updates its docs/<subsystem>.md in the same pull request.

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

Questions are welcome in GitHub Discussions.


License

RustyNES is licensed GPL-3.0-or-later.

It is a derivative work of GPL-licensed NES emulators: it incorporates code derived from Mesen2 (GPL-3.0-or-later) and, for a few subsystems, from puNES, FCEUX and Nestopia UE (GPL-2.0-or-later). An earlier version described that code as "oracle cross-checks" and licensed it MIT/Apache-2.0, which was wrong; after a NESdev community review the project was relicensed and every derivation credited in docs/originality-and-provenance.md and NOTICE (ADR 0036).

How that happened, and the rules that keep it from recurring, are public: docs/provenance-failure-postmortem.md and docs/ai-emulator-provenance-guardrails.md. Reference emulators are black-box oracles: their output may be compared, and their source is never read.

Permissive components (emu2413, TriCNES, rcheevos, blip_buf and the bundled fonts) are credited in NOTICE. The test ROMs under tests/roms/ are CC0, MIT or zlib. No commercial ROMs are included: dumps for the commercial-ROM oracle must come from cartridges you own.


Acknowledgments

Full attribution is in NOTICE.

Citation

@software{rustynes2026,
  author  = {RustyNES Contributors},
  title   = {RustyNES: A Cycle-Accurate NES Emulator in Rust},
  year    = {2026},
  url     = {https://github.com/doublegate/RustyNES},
  note    = {Cycle-accurate NES emulator; AccuracyCoin 144/144, nestest 0-diff}
}

Get started · Play in the browser · Contribute · Discuss

About

[RustyNES] Cycle-accurate Nintendo Entertainment System NES emulator built in pure Rust — 191+ mappers, WebAssembly-ready, GGPO netplay, TAS tools, and RetroAchievements integration for game preservation. "Precise. Pure. Powerful."

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages