NES emulator written in Rust

Overview

sprocketnes is an emulator for the Nintendo Entertainment System written in the Rust programming language.

Its purpose is to serve as a technology demonstration to show how the Rust programming language is suitable for systems software such as emulators. It has many shortcomings and is not intended to be a production-quality emulator. sprocketnes is also designed to be a relatively clean example codebase, showing off various Rust idioms.

The NES was chosen for this project because:

  • It's familiar to most hackers.

  • It's a reasonably simple system to emulate.

  • Because of its popularity, its workings are relatively well-documented.

  • It's CPU-bound, so it can serve as a benchmark to help optimize Rust code.

  • The audio requires some measure of real-time operation, which tests Rust's real-time capabilities.

The main controls are as follows:

  • A: Z

  • B: X

  • Start: Enter

  • Select: Right shift

  • D-Pad: Arrows

Other keys:

  • Save state: S

  • Load state: L

  • Quit: Escape

If you want to build sprocketnes, you will first need the Speex codec library installed; on the Mac you can install it with brew install speex.

To build (add --release if you actually want playable speed):

cargo build

There are numerous demos and games available for free for use with this emulator at http://nesdev.com/.

Enjoy!

Comments
  • Update to modern Rust

    Update to modern Rust

    This kind of got out of hand, but SprocketNES now compiles with the newest Rust nightly, beta and stable.

    I've also updated the directory structure (following the Cargo guide), and split the project into a library and a binary (which I'm not sure makes much sense now, but if someone crazy wants to use this in something like a multi-emulator, this will make it like 1% easier).

    Oh, and I've enabled V-Sync, which made a massive difference for me (games were massively stuttering before).

    opened by jonas-schievink 6
  • Build with latest nightly (mostly)

    Build with latest nightly (mostly)

    I wanted to steal some code for my gameboy emulator but I realized that this code hadn't been updated in a while so I decided to give it a try.

    Most of the breakage was due to changes in rust syntax (nampespaced enums, no automatic Copy etc...) however the audio interface to SDL2 seems to have changed quite a lot which means that the current code is completely broken.

    In particular rust won't let me declare a static AudioDevice anymore because it implements Drop. I'm not sure how to fix that particular issue without rewriting a big chunk of code so I left it commented for now. If you have any clue what to do I can look into it some more.

    But besides that it builds correctly with only one warning left that I can't quite figure out (it looks bogus to me but I might be missing something).

    When I tried to run it with mario bros the game seemed very slow even though it wouldn't take all of my CPU, maybe there's a timing issue, I'm not sure (and since I never ran this emulator before I'm not sure how it's supposed to look like).

    So, it's not finished but hopefully it'll be useful.

    opened by simias 6
  • Update dependencies

    Update dependencies

    This PR does a few things:

    • Update dependencies
    • Resolve all warnings
    • Fix integer overflows in CPU
    • Run rustfmt over the entire codebase

    This makes it compile and run again (at least Super Mario Bros.).

    opened by iluuu1994 3
  • Can't run anything on ARM

    Can't run anything on ARM

    Tried twice with some random ROMS:

    target/release/nes   MunchieAttack.nes 
    Loaded ROM: PRG-ROM: 16 KB, CHR-ROM: 0 KB, Mapper: 0 (0), Trainer: false
    thread '<main>' panicked at 'index out of bounds: the len is 0 but the index is 1', src/libcollections/vec.rs:1106
    stack backtrace:
       1: 0xb6f837bb - sys::backtrace::tracing::imp::write::h86e39446169e67d0Wnt
       2: 0xb6f860cb - panicking::log_panic::_<closure>::closure.39676
       3: 0xb6f85aef - panicking::log_panic::h7e0ce1e7485944fbUpx
       4: 0xb6f7ae5f - sys_common::unwind::begin_unwind_inner::h1d39a3f983dfda740gs
       5: 0xb6f7b013 - sys_common::unwind::begin_unwind_fmt::h2f77b9962e7023ac6fs
       6: 0xb6f82d97 - rust_begin_unwind
       7: 0xb6f8c79f - panicking::panic_fmt::h48301c5acd531c5bZEK
       8: 0xb6f8c75b - panicking::panic_bounds_check::h8d31f567a438d4e15DK
       9: 0xb6f6bfc7 - mapper::_<impl>::chr_loadb::hb17d08e4fddb2e93FXd
      10: 0xb6f6d5e3 - ppu::_<impl>::step::h122e120144b10602frf
      11: 0xb6f6eb23 - start_emulator::ha09827b57096d9acNGf
      12: 0xb6f66437 - main::h4c1a5b6fa5311b62Qda
    

    and

    target/release/nes   SolarWars2001.NES
    Loaded ROM: PRG-ROM: 32 KB, CHR-ROM: 32 KB, Mapper: 3 (3), Trainer: false
    thread '<main>' panicked at 'unsupported mapper', src/mapper.rs:35
    stack backtrace:
       1: 0xb6f9b7bb - sys::backtrace::tracing::imp::write::h86e39446169e67d0Wnt
       2: 0xb6f9e0cb - panicking::log_panic::_<closure>::closure.39676
       3: 0xb6f9daef - panicking::log_panic::h7e0ce1e7485944fbUpx
       4: 0xb6f92e5f - sys_common::unwind::begin_unwind_inner::h1d39a3f983dfda740gs
       5: 0xb6f803df - sys_common::unwind::begin_unwind::begin_unwind::h3512061288630715681
       6: 0xb6f83d63 - mapper::create_mapper::he15687723fbb39d4uVd
       7: 0xb6f86717 - start_emulator::ha09827b57096d9acNGf
       8: 0xb6f7e437 - main::h4c1a5b6fa5311b62Qda
    

    Compiled with 1.5, run at 16bpp colour depth. I think README.md might need more info on requirements :)

    opened by MagaTailor 2
  • Problem compiling decode_op!:

    Problem compiling decode_op!: "No rules expected the token: op"

    Error compiling cpu.rs:

    $ make
    rustc --cfg ndebug --cfg ncpuspew -O -L . nes.rc -o nes || echo ""If this build failed due to missing SDL bindings, please install them from https://github.com/brson/rust-sdl and copy the .dll/.dylib/.so into this directory or use RUSTLDFLAGS.""
    cpu.rs:709:19: 709:21 error: No rules expected the token: op
    cpu.rs:709         decode_op!(op: op, this: self);
                                  ^~
    

    My rustc was compiled from mozilla/rust@917d3c28b6aab7de454087236173122616a6f9b6.

    opened by jsanders 2
  • Updated the syntax for rustc version 0.13.0-nightly and added a .gitignore

    Updated the syntax for rustc version 0.13.0-nightly and added a .gitignore

    It's a syntax update (replaced static with const for global constants, .. with ... for ranges in match, etc.). Also updated the calls to the rust-sdl2 library to bring it inline with the newest version. Finally, I added a .gitignore to ignore the target directory and Cargo.lock when add files to the staging area.

    opened by ghost 1
  • Sync with rust master

    Sync with rust master

    Now builds and runs, probably slower than before, but playable with -O compile flag.

    Only testing was an enjoyable run through 1-1 to 1-3 and playing with save states.

    opened by Ryman 1
  • mem.rs:104 error: cannot borrow immutable dereference of & pointer as mutable

    mem.rs:104 error: cannot borrow immutable dereference of & pointer as mutable

    Trying to learn Rust by studying this codebase. It doesn't compile with the latest rustc, and I'm a so new to the language that I don't know how to fix this:

    /rust/sprocketnes$ make rustc --cfg ndebug --cfg ncpuspew -O -L . nes.rc -o nes || echo ""If this build failed due to missing SDL bindings, please install the
    m from https://github.com/brson/rust-sdl and copy the .dll/.dylib/.so into this directory or use RUSTLDFLAGS."" mem.rs:104:16: 104:22 error: cannot borrow immutable dereference of & pointer as mutable mem.rs:104 mapper.prg_loadb(addr) ^~~~~~ mem.rs:122:16: 122:22 error: cannot borrow immutable dereference of & pointer as mutable mem.rs:122 mapper.prg_storeb(addr, val) ^~~~~~ ppu.rs:181:16: 181:22 error: cannot borrow immutable dereference of & pointer as mutable ppu.rs:181 mapper.chr_loadb(addr) ^~~~~~ ppu.rs:195:16: 195:22 error: cannot borrow immutable dereference of & pointer as mutable ppu.rs:195 mapper.chr_storeb(addr, val) ^~~~~~ ppu.rs:773:19: 773:25 error: cannot borrow immutable dereference of & pointer as mutable ppu.rs:773 if mapper.next_scanline() == Irq { ^~~~~~ error: aborting due to 5 previous errors If this build failed due to missing SDL bindings, please install them from https://github.com/brson/rust-sdl and copy the .dll/.dylib/
    .so into this directory or use RUSTLDFLAGS.

    /rust/sprocketnes$ rustc --version rustc 0.8-pre (bb35e23 2013-08-30 21:40:32 -0700) host: x86_64-unknown-linux-gnu

    I did fix a one earlier compile error as follows:

    /rust/sprocketnes$ git branch -v

    • master 8b6fcfa Update for language changes and go runtimeless!

    /rust/sprocketnes$ git diff diff --git a/util.rs b/util.rs^[[m index ac46941..dece364 100644^[[m --- a/util.rs^[[m +++ b/util.rs^[[m @@ -10,6 +10,7 @@ use std::libc::time_t;^[[m use std::libc;^[[m use std::ptr::null;^[[m use std::uint;^[[m +use std::c_str::ToCStr;^[[m ^[[m //^[[m // Standard library I/O replacements^[[m @@ -37,7 +38,7 @@ impl Fd {^[[m ForReading => O_RDONLY,^[[m ForWriting => O_WRONLY | O_CREAT | O_TRUNC^[[m } as c_int;^[[m

    •        do path.as_c_str |c_path| {^[[m
      
    •        do path.to_c_str().with_ref |c_path| {^[[m
               Fd {^[[m
                   contents: libc::open(c_path, fd_mode, 493),^[[m
               }^[[m
      
    opened by glycerine 1
  • Compile error on OSX

    Compile error on OSX

    Trying to compile (using make) on osx lion 10.8.2 gives

        rustc --cfg ndebug --cfg ncpuspew -O -L . nes.rc -o nes || echo ""If this build failed due to missing SDL bindings, please install them from https://github.com/brson/rust-sdl and copy the .dll/.dylib/.so into this directory or use RUSTLDFLAGS.""
        cpu.rs:338:16: 338:19 error: expected `{` but found `for`
        cpu.rs:338 impl<M:Mem> Mem for Cpu<M> {
                                   ^~~
        If this build failed due to missing SDL bindings, please install them from https://github.com/brson/rust-sdl and copy the .dll/.dylib/.so into this directory or use RUSTLDFLAGS.
    

    There is an error about needing the sdl dylib, but I have it in the directory.

    invalid 
    opened by DylanSale 1
  • Fix some arithmetic overflow errors

    Fix some arithmetic overflow errors

    So far I've been finding these by playing a game until it crashes. To find all of them, I'd probably need to do a thorough line-by-line audit or run a fuzzer.

    I might try using afl-fuzz to catch the rest of these, sometime.

    opened by cassiebeckley 0
  • Update for rust-0.13-nightly and latest rust-sdl2.

    Update for rust-0.13-nightly and latest rust-sdl2.

    * Rename fail! to panic!
    * Remove occurrences of "use std::owned::Box".
    * Renderer<T> is now just Renderer in rust-sdl2.
    * Rename lint from "ctypes" to "improper_ctypes".
    
    opened by bfabio 0
  • Use of .to_string() is redundant

    Use of .to_string() is redundant

    https://github.com/pcwalton/sprocketnes/blob/163e5da03c6c1db2f78898a001f13d4dd739f0ff/src/disasm.rs#L93

    format!() will already return a String therefore the call to .to_string() is meaningless.

    opened by Dunklheit 0
  • Make the audio module less unsafe

    Make the audio module less unsafe

    This is achieved by eliminating two global variables and making the code work nicely with ownership analysis.

    This is possible because AudioDevice has a lock method that returns an object that dereferences to NesCallback we can store the output buffer directly in NesCallback and then safely access it to update the raw sound data.

    The resulting code is easier to follow and contains fewer unsafe blocks.

    opened by jstasiak 0
  • APU is very slow

    APU is very slow

    Apparently the APU is the bottleneck. Because when you disable it the emulator is blazingly fast (way too fast in fact). I'll see if I can optimize it.

    opened by iluuu1994 3
  • Installation Error - unspecified

    Installation Error - unspecified

        Updating registry `https://github.com/rust-lang/crates.io-index`
     Downloading libc v0.2.4
     Downloading lazy_static v0.1.15
     Downloading sdl2 v0.6.1
     Downloading time v0.1.34
     Downloading bitflags v0.2.1
     Downloading rand v0.3.12
     Downloading num v0.1.29
     Downloading libc v0.1.12
     Downloading sdl2-sys v0.6.2
     Downloading advapi32-sys v0.1.2
     Downloading winapi v0.2.5
     Downloading winapi-build v0.1.1
     Downloading rustc-serialize v0.3.16
     Downloading kernel32-sys v0.2.1
       Compiling winapi-build v0.1.1
       Compiling winapi v0.2.5
       Compiling libc v0.2.4
       Compiling sdl2-sys v0.6.2
       Compiling rustc-serialize v0.3.16
       Compiling libc v0.1.12
       Compiling bitflags v0.2.1
       Compiling lazy_static v0.1.15
    error[E0642]: patterns aren't allowed in methods without bodies
       --> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc-serialize-0.3.16/src/serialize.rs:145:45
        |
    145 |                                             &f_name: &str,
        |                                             ^^^^^^^
    
       Compiling advapi32-sys v0.1.2
       Compiling kernel32-sys v0.2.1
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0642`.
    error: Could not compile `rustc-serialize`.
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    
    
    ➜  sprocketnes git:(master) ✗ rustc --explain E0642
    error: no extended information for E0642```
    opened by RealLukeMartin 4
  • How does this emulator handle overflow?

    How does this emulator handle overflow?

    For example, here's how "inc" is implemented:

    // Increments and decrements
    fn inc<AM:AddressingMode<M>>(&mut self, am: AM) {
        let val = am.load(self);
        let val = self.set_zn(val + 1);
        am.store(self, val)
    }
    

    This is "set_zn":

     fn set_zn(&mut self, val: u8) -> u8 {
        self.set_flag(ZERO_FLAG, val == 0);
        self.set_flag(NEGATIVE_FLAG, (val & 0x80) != 0);
        val
    }
    

    I can't see how this would handle a increment of value 255 without panicking? Seeing that there's been no commits in 3 years, perhaps Rust handled overflows differently back then? (Just getting started, writing an emulator in Rust to get to know the language)

    opened by jm-above 0
Owner
Patrick Walton
Patrick Walton
An NES emulator written in Rust

Pinky Pinky is an NES emulator written in Rust completely from scratch based only on publicly available documentation. You can run it in your Web brow

Koute 709 Dec 23, 2022
NES emulator written in Rust

sprocketnes is an emulator for the Nintendo Entertainment System written in the Rust programming language. Its purpose is to serve as a technology dem

Patrick Walton 725 Dec 27, 2022
a work-in-progress NES emulator written in rust.

sayaka-rs a work-in-progress NES emulator, written in Rust. the project image is an edit of a frame from the Mahou Shoujo Madoka Magica manga. the Mik

Lumine 1 Jan 16, 2022
A NES emulator written in Rust, with a focus on expandability and accuracy

A NES emulator written in Rust, with a focus on expandability and accuracy

Benjamin Mordaunt 4 Sep 19, 2022
NES emulator in rust

NES emulator in Rust plastic is a NES emulator built from scratch using Rust. This is a personal project for fun and to experience emulating hardware

Amjad Alsharafi 27 Dec 15, 2022
A simple NES emulator implemented in Rust. (WIP)

remu A ?? ?? BLAZINGLY FAST* ?? ?? NES emulator implemented in Rust. Status: Work in progress. About This emulator is mainly meant to be more of a lea

luna 10 Aug 25, 2022
🥔 MOS-6502 and NES emulator in Rust (SDL/WebAssembly)

?? Potatis /mos6502 - Generic CPU emulator. Passes all tests, including illegal ops. (No BCD mode). /nes - A very incomplete NES emulator. /nes-sdl -

Henrik Persson 28 Jan 9, 2023
A **BLAZINGLY FAST** rust emulator for the NES.

rust-nes A BLAZINGLY FAST rust emulator for the NES. Install / Usage Clone the repository and navigate to it git clone https://github.com/imagine-huss

null 7 Jan 20, 2023
Learn emulator and programming languages, target chip8, nes, gbc, gba ...

[WIP]learn emulator go-chip8 go run main.go source https://en.wikipedia.org/wiki/CHIP-8 http://devernay.free.fr/hacks/chip8/C8TECH10.HTM https://githu

早晨海风 4 Apr 30, 2021
Chip8 emulator written in pure rust, using rust-sdl2 for graphics

Rust-8 chip8 emulator written in rust, using rust-sdl2 for graphics. Features Fully implemented all 35 original chip8 opcodes. This emulator does NOT

Chris Hinson 7 Dec 28, 2022
Commodore 64 emulator written in Rust

Rust64 - a C64 emulator written in Rust This is my attempt to study the Rust programming language and have fun at the same time. The goal is to presen

Krzysztof Kondrak 214 Dec 27, 2022
A Flash Player emulator written in Rust

website | demo | nightly builds | wiki Ruffle Ruffle is an Adobe Flash Player emulator written in the Rust programming language. Ruffle targets both t

Ruffle 11.2k Jan 8, 2023
A Game Boy research project and emulator written in Rust

Mooneye GB Mooneye GB is a Game Boy research project and emulator written in Rust. The main goals of this project are accuracy and documentation. Some

Joonas Javanainen 802 Dec 28, 2022
RustBoyAdvance-NG is a Nintendo™ Game Boy Advance emulator and debugger, written in the rust programming language.

RustBoyAdvance-NG Nintendo GameBoy Advance ™ emulator and debugger, written in rust. WebAssembly Demo: https://michelhe.github.io/rustboyadvance-ng/ P

MishMish 510 Dec 30, 2022
ZX Spectrum emulator written in Rust

rustzx ZX Spectrum emulator which I writing in rust. I develop this project just for fun and for learning the basics of computer architecture. License

Vladislav Nikonov 162 Dec 27, 2022
CHIP-8 emulator written in Rust

CHIP-8 emulator written in Rust. This is intended to be a project for gaining experience writing emulators and practice Rust.

Pedro Rodrigues 4 May 21, 2021
A 6502 emulator written in Rust.

v6502 This package contains an emulator for the 6502 microprocessor. It doesn't support binary decimal (BCD) mode yet. To run the debug version: cargo

Andrew Young 4 Nov 14, 2021
Spaghetti Chip8 Emulator Written In Rust

How to run? Command is simple: cargo run FILENAME. files are stored in the /c8games folder, use one of them. Example: cargo run INVADERS Keymap use 1

Can 5 Apr 15, 2022
Non cycle-accurate emulator of the 6502 cpu, written in pure rust

CPU 6502 A non cycle-accurate emulator implementing all legal 6502 opcodes. What does non cycle-accurate mean? Every instruction on the 6502 takes a n

Pietro 10 Jul 15, 2022