Note: This emulator has been largely obsoleted by the NES core in my multi-system emulator, but this emulator does still support a few features that one does not:
- A configurable Gaussian blur filter, which is not accurate to any TV but does smooth out the image with some "fancy" blur
- The entirety of the web frontend; jgenesis has a web frontend, but it doesn't support NES and there's no support for input configuration
A cross-platform NES emulator. Has a native frontend built using SDL2 as well as a web frontend that compiles to WASM and runs in the browser.
Implemented:
- Cycle-based 6502 CPU emulation, PPU emulation (graphics), and APU emulation (audio)
- The most commonly used cartridge boards (aka mappers)
- NROM
- The most common NROM variants (UxROM / CNROM / AxROM)
- MMC1
- MMC3/MMC6
- Some less commonly used cartridge boards
- MMC2/MMC4
- MMC5 including expansion audio
- Konami VRC2 / VRC4 / VRC6 / VRC7, including VRC6 expansion audio and VRC7 expansion audio
- Sunsoft 5A / 5B / FME-7, including 5B expansion audio
- Codemasters unlicensed board
- Color Dreams unlicensed board
- Bandai FCG-1 / FCG-2 / LZ93D50
- The LZ93D50 variant that uses the Datach Joint ROM system is not implemented (iNES mapper 157)
- Namco 108 / 129 / 163 / 175 / 340, including 163 expansion audio
- NAMCOT-3425 / NAMCOT-3446 / NAMCOT-3453
- Jaleco JF-11 / JF-14
- GxROM
- BNROM
- NINA-001
- P1 & P2 input with support for keyboard input and DirectInput gamepad input
- Support for 3 different forced aspect ratios (NTSC, 1:1 pixel aspect ratio, 4:3 screen aspect ratio), plus an option for stretched/none
- Overscan customization
- A GPU-backed renderer based on
wgpu
with an option for integer upscaling + linear interpolation, producing a sharp but clean image even at higher resolutions and non-8:7 aspect ratios - Save & load state
- Fast forward with a configurable speed multiplier (very CPU-intensive at higher multipliers; my i5-1240P laptop maxes out between 5x and 6x speed)
- Rewind
- Support for both NTSC and PAL releases
Not Implemented:
- A handful of unofficial CPU opcodes that are buggy/unstable and do not do anything useful (specifically $93, $9B, and $9F)
- Cycle-accurate rendering effects of enabling rendering mid-scanline
- DMC DMA cycle stealing and dummy reads, an obscure hardware quirk that affects very very few if any games
- Color palette customization; the NES hardware directly outputs an NTSC video signal rather than RGB pixel grids, so any mapping from NES colors to RGB colors is an approximation at best
- Lots of more obscure cartridge boards
- Support for any controller port peripherals (e.g. the Zapper)
jgnes-proc-macros
: Custom derive macros used injgnes-core
.jgnes-core
: The emulation core. Has few dependencies and requires external code to drive it. Uses callbacks for rendering frames, playing audio, polling for input, and writing save files.jgnes-renderer
: Code for the GPU-backed renderer, as well as some common configuration code that is shared by both renderers.jgnes-native-driver
: Emulator driver that uses SDL2 to handle everything related to video/audio/input, with an option to use either the GPU renderer or an SDL2 software renderer for rendering emulator output into the window.jgnes-cli
: A command-line interface that invokesjgnes-native-driver
.jgnes-gui
: A graphical user interface that invokesjgnes-native-driver
.jgnes-web
: An experimental WASM+WebGL2 frontend forjgnes-core
that runs in the browser. Useswinit
to create the frame andjgnes-renderer
to render emulator output.
This project requires the latest stable version of the Rust toolchain to build. See link for installation instructions.
This project requires SDL2 core headers to build.
Linux (Debian-based):
sudo apt install libsdl2-dev
Windows:
On Linux only, the GUI requires GTK3 headers to build.
Linux (Debian-based):
sudo apt install libgtk-3-dev
To build the CLI and run for a given NES ROM file:
cargo run --release --bin jgnes-cli -- -f /path/to/file.nes
To view all CLI args:
cargo run --release --bin jgnes-cli -- -h
To build and run the GUI:
cargo run --release --bin jgnes-gui
Test | Result | Failure Reason |
---|---|---|
blargg_nes_cpu_test5/cpu.nes | ✅ | |
blargg_nes_cpu_test5/official.nes | ✅ | |
branch_timing_tests/1.Branch_Basics.nes | ✅ | |
branch_timing_tests/2.Backward_Branch.nes | ✅ | |
branch_timing_tests/3.Forward_Branch.nes | ✅ | |
cpu_dummy_reads/cpu_dummy_reads.nes | ✅ | |
cpu_dummy_writes/cpu_dummy_writes_oam.nes | ✅ | |
cpu_dummy_writes/cpu_dummy_writes_ppumem.nes | ✅ | |
cpu_exec_space/test_cpu_exec_space_apu.nes | ✅ | |
cpu_exec_space/test_cpu_exec_space_ppuio.nes | ✅ | |
cpu_interrupts_v2/cpu_interrupts.nes | ✅ | |
cpu_timing_test6/cpu_timing_test.nes | ✅ | |
instr_test-v5/all_instrs.nes | ✅ | |
instr_test-v5/official_only.nes | ✅ | |
instr_timing/instr_timing.nes | ✅ |
Test | Result | Failure Reason |
---|---|---|
apu_test/apu_test.nes | ✅ | |
blargg_apu_2005.07.30/01.len_ctr.nes | ✅ | |
blargg_apu_2005.07.30/02.len_table.nes | ✅ | |
blargg_apu_2005.07.30/03.irq_flag.nes | ✅ | |
blargg_apu_2005.07.30/04.clock_jitter.nes | ✅ | |
blargg_apu_2005.07.30/05.len_timing_mode0.nes | ✅ | |
blargg_apu_2005.07.30/06.len_timing_mode1.nes | ✅ | |
blargg_apu_2005.07.30/07.irq_flag_timing.nes | ✅ | |
blargg_apu_2005.07.30/08.irq_timing.nes | ✅ | |
blargg_apu_2005.07.30/09.reset_timing.nes | ✅ | |
blargg_apu_2005.07.30/10.len_halt_timing.nes | ✅ | |
blargg_apu_2005.07.30/11.len_reload_timing.nes | ❌ | #5: Reload during length clock when ctr > 0 should be ignored |
dmc_dma_during_read4/dma_2007_read.nes | ❌ | DMC DMA dummy reads not implemented |
dmc_dma_during_read4/dma_2007_write.nes | ✅ | |
dmc_dma_during_read4/dma_4016_read.nes | ❌ | DMC DMA dummy reads not implemented |
dmc_dma_during_read4/double_2007_read.nes | ❌ | DMC DMA dummy reads not implemented |
dmc_dma_during_read4/read_write_2007.nes | ✅ | |
sprdma_and_dmc_dma/sprdma_and_dmc_dma.nes | ❌ | DMC DMA cycle stealing not implemented |
sprdma_and_dmc_dma/sprdma_and_dmc_dma_512.nes | ❌ | DMC DMA cycle stealing not implemented |
Test | Result | Failure Reason |
---|---|---|
blargg_ppu_tests_2005.09.15b/palette_ram.nes | ✅ | |
blargg_ppu_tests_2005.09.15b/power_up_palette.nes | ❌ | #2: Palette differs from table |
blargg_ppu_tests_2005.09.15b/sprite_ram.nes | ✅ | |
blargg_ppu_tests_2005.09.15b/vbl_clear_time.nes | ✅ | |
blargg_ppu_tests_2005.09.15b/vram_access.nes | ✅ | |
oam_read/oam_read.nes | ✅ | |
ppu_open_bus/ppu_open_bus.nes | ❌ | #3: Decay value should become zero by one second |
ppu_read_buffer/test_ppu_read_buffer.nes | ✅ | |
ppu_vbl_nmi/ppu_vbl_nmi.nes | ✅ | |
sprite_hit_tests_2005.10.05/01.basics.nes | ✅ | |
sprite_hit_tests_2005.10.05/02.alignment.nes | ✅ | |
sprite_hit_tests_2005.10.05/03.corners.nes | ✅ | |
sprite_hit_tests_2005.10.05/04.flip.nes | ✅ | |
sprite_hit_tests_2005.10.05/05.left_clip.nes | ✅ | |
sprite_hit_tests_2005.10.05/06.right_edge.nes | ✅ | |
sprite_hit_tests_2005.10.05/07.screen_bottom.nes | ✅ | |
sprite_hit_tests_2005.10.05/08.double_height.nes | ✅ | |
sprite_hit_tests_2005.10.05/09.timing_basics.nes | ✅ | |
sprite_hit_tests_2005.10.05/10.timing_order.nes | ✅ | |
sprite_hit_tests_2005.10.05/11.edge_timing.nes | ✅ | |
sprite_overflow_tests/1.Basics.nes | ✅ | |
sprite_overflow_tests/2.Details.nes | ✅ | |
sprite_overflow_tests/3.Timing.nes | ✅ | |
sprite_overflow_tests/4.Obscure.nes | ✅ | |
sprite_overflow_tests/5.Emulator.nes | ✅ | |
vbl_nmi_timing/1.frame_basics.nes | ✅ | |
vbl_nmi_timing/2.vbl_timing.nes | ✅ | |
vbl_nmi_timing/3.even_odd_frames.nes | ✅ | |
vbl_nmi_timing/4.vbl_clear_timing.nes | ✅ | |
vbl_nmi_timing/5.nmi_suppression.nes | ✅ | |
vbl_nmi_timing/6.nmi_disable.nes | ✅ | |
vbl_nmi_timing/7.nmi_timing.nes | ✅ |
Test | Result | Failure Reason |
---|---|---|
mmc3_test_2/1-clocking.nes | ✅ | |
mmc3_test_2/2-details.nes | ✅ | |
mmc3_test_2/3-A12_clocking.nes | ✅ | |
mmc3_test_2/4-scanline_timing.nes | ✅ | |
mmc3_test_2/5-MMC3.nes | ✅ | |
mmc3_test_2/6-MMC3_alt.nes | ❌ | #2: IRQ shouldn't be set when reloading to 0 due to counter naturally reaching 0 previously |
Test | Result | Failure Reason |
---|---|---|
apu_reset/4015_cleared.nes | ✅ | |
apu_reset/4017_timing.nes | ✅ | |
apu_reset/4017_written.nes | ✅ | |
apu_reset/irq_flag_cleared.nes | ✅ | |
apu_reset/len_ctrs_enabled.nes | ✅ | |
apu_reset/works_immediately.nes | ✅ | |
cpu_reset/ram_after_reset.nes | ✅ | |
cpu_reset/registers.nes | ✅ |