A simple and clean™️ cycle accurate NES emulator, written in Rust. Fast, lightweight, and with high compatibility.
nen_emu_preview.mp4
Download is avaible in the release section. A SDL2 forntend for the emulator is avaible, with very basic user functionality, such as pausing, muting, single savestate save/load, and cartridge-ram savig to disk. A (WIP) WASM frontend is also avaible here: https://comba92.github.io/nen-emulator/frontend-wasm/index.html
Game ROMs can be loaded by dragging and dropping the files into the window.
Tip
Zip files are supported.
Note
ROMS with iNes or NES2.0 headers are supported.
The terminal window shows basic informations and warnings, such as the ROM information.
Tip
Both keyboards and controllers are supported.
Tip
A save/load state feature is avaible.
Note
By default, the 8 sprite limit per scanline is disabled, but can be enabled.
Keyboard | Button |
---|---|
A | A button |
S | B button |
W | Start |
E | Select |
ArrowKeys | You know what they do! |
Space | Pause/unpause the emulator |
R | Reset current game |
M | Mute/unmute sound |
9 | Save state |
0 | Load state |
1 | Toggle 8 sprites limit per scanline |
The emulator supports mostly all the basic NES features you'd expect from a NES emulator.
-
The emulator is cycle accurate. A list of tests coverage is avaible here.
-
The 6502 CPU is emulated with most of its quirks.
-
The PPU is emulated as a pixel renderer, and emulates the LoopyRegister behaviour.
-
The pixel fethcer is emulated only for the backrounds. Object sprites are all fetched in one go, then mixed with the backround pixels one by one.
-
The APU channels are all fully emulated.
-
Both NTSC and PAL games are supported.
-
Games with tricky and obscure behaviour run correctly, except for one or two exceptions. For more information:
-
BATTLETOADS & BATTLETOADS 2 RUN!
-
All nametable mirrorings are supported.
-
Zip files are supported.
-
Saving/loading of battery RAM when the game is changed or the emulator is closed.
-
Savestates
-
Resetting works, but some games require you to hold the down the reset button a few seconds
Warning
- Headerless games are not supported.
I haven't kept track of a game compatibility list, but most of the development was driven by testing random games and beign sure they could boot, and run correctly for a minute or two. Right now, most games I've tried, popular and what not, are all running correctly. You are free to try some games and inform me about any issue!
- 01. MMC1 SxROM variants
- 04. MMC6 (used for Startropics and Startropics II)
- 05. MMC5
- Only Castlevania III and Mario Zap and Dash tested and work
- Note: PCM channel not implemented
- Note: Vertical split functionality not implemented
- 09. MMC2 (used for Punch-Out!!)
- 10. MMC4
- 11. ColorDreams
- 13. CPROM (used for Videomation, a painting program for NES)
- 16, Bandai FCG
- Note: Not usable, graphical glitches
- 19. Namco 129/163
- Note: audio chip not implemented
- 21, 22, 23, 25. VRC2 and VRC4
- Note: compatibility might not be the best. (TODO: use submappers to discriminate board)
- 24. VRC6a (used for Akumajou Densetsu, japanese version of Castlevania III with enhanced audio)
- 26. VRC6b (used for Madara and Esper Dream 2)
- 30. UNROM512
- Note: flashable board PRG not implemented
- 31. NSF
- 34. BNROM/NINA-001
- 68. Sunsoft4
- Note: Nantettatte!! Baseball (J) licensing IC not implemented
- 69. Sunsoft5 FME-7
- Note: audio chip not implemented
- 71. Codemasters
- 73. VRC3 (used for Salamander)
- 75. VRC1
- 78. Irem 74HC161 (used for Holy Diver and Cosmo Carrier)
- 85. VRC7 (used for Lagrange Point and Tiny Toon Adventures 2)
- Note: audio chip not implemented
- 87. J87
- 111. GTROM
- Note: flashable board PRG not implemented
- 180. UNROM (used for Crazy Climber)
- 206. Namco 118/Tengen MIMIC-1
The emulator is served as a stand-alone Rust library. It provides a basic API in src/nes.rs
, which can be used by any frontend. (TODO: move the Nes struct to lib.rs
)
Building requires, of course, Rust and it's development tools. To build the emulator library, simply use in the root folder:
cargo build -r
Two frontends are avaible. The SDL2 frontend, in frontend-native. To build, again, it's simply:
cargo build -r # Dynamically linked with SDL2
cargo build --features="static" # Statically linked with SDL2
The WASM frontend is still WIP, but already avaible here: https://comba92.github.io/nen-emulator/frontend-wasm/index.html It is missing audio playback, savestates, and with a lackluster UI.
The emulator is organized as a tree (sort of) of dependencies. The root is the CPU. which contains the BUS, and which in turn contains all the peripherals:
- PPU
- DMA
- APU
- Cartridge/Mapper
- Joypads
The cartridge is the only exception, as it is shared with multiple peripherals. Rust's typing system makes it hard to create circular dependencies of pointers, so the Cartride object has to be wrapped in a RefCell for interior mutability (giving us the ability to mutate it anywhere), and then in a Rc, for shared ownership.
This approach proved to be solid, safe, and reliable, but at the cost of flexibility. The architecure had to be changed from its roots multiple times, as most of the features and roadblocks weren't took into account since the beginning. This is the heart of software development though. You can never plan in advance how the system can be designed efficently.
An alternative solution would be having a global "god struct" (as the folks at emudev discord like to call), which contains a general emulation context, which is passed to every function. This increases flexibility, as there are fewer restrictions, but with a less cohesive design.
As the NES is a relatively simple machine, restricting the design to a dependency tree proved to be beneficial. Everything is tightly coupled, and the codebase is manageable. Adding more user features is a pain, tho.
-
Famicon Disk System Support
-
RAM random initializing for games which uses it to seed RNG
-
Custom keybindings
-
Custom palettes
-
Headerless ROMs support
This section contains some of the resources I've used during development. Sadly I didn't keep track of all of them. I did found a lot of interesting articles, blogs, and readings, but forgot to add them here.
- https://www.nesdev.org/wiki
- https://www.nesdev.org/NESDoc.pdf
- https://www.copetti.org/writings/consoles/nes/
- https://www.nesdev.org/6502.txt
- https://www.nesdev.org/6502_cpu.txt
- https://bugzmanov.github.io/nes_ebook/chapter_3.html
- http://www.6502.org/users/obelisk/6502
- https://www.pagetable.com/c64ref/6502
- https://www.masswerk.at/6502/6502_instruction_set.html
- http://www.ffd2.com/fridge/docs/6502-NMOS.extra.opcodes
- https://www.nesdev.org/the%20%27B%27%20flag%20&%20BRK%20instruction.txt
- https://en.wikibooks.org/wiki/NES_Programming/Memory_Map
- https://www.nesdev.org/wiki/CPU_memory_map
- https://www.nesdev.org/wiki/PPU_memory_map
- https://emudev.de/nes-emulator/cartridge-loading-pattern-tables-and-ppu-registers/
- https://bugzmanov.github.io/nes_ebook/chapter_6.html
- https://austinmorlan.com/posts/nes_rendering_overview/
- https://leeteng.com/blog/content/writing-nes-emulator
- https://emudev.de/nes-emulator/palettes-attribute-tables-and-sprites/
- https://www.youtube.com/watch?v=-THeUXqR3zY