ANESE (Another NES Emulator) is a Nintendo Entertainment System Emulator written for fun and learning.
Accuracy and performance are long-term goals, but the primary focus is getting popular titles up and running. There are still a lot of bugs, but many games are working quite well already.
ANESE is cross-platform, and is regularly tested on macOS, Windows, and Linux.
ANESE core uses clean and interesting C++11, emphasizing readability, maintainability, and approachability. It is well commented, providing in-line sources and insights for much of the implementation. It is also dependency free (aside from stdlib), making it easy to embed in other projects.
WideNES
wideNES is a novel technique that can automatically "map-out" levels and worlds in NES games. Check out the wideNES Readme for details.
A GIF is worth a 1000 words:
Pretty cool huh? Here's another one:
Downloads
Official releases of ANESE can be found on the Releases tab on GitHub.
Alternatively, for the most up-to-date version of ANESE, nightly builds are available. These are compiled directly from the latest ANESE commit, so there may/will be bugs.
Windows: You can download builds of ANESE from AppVeyor's build artifacts page.
macOS: Travis uploads ANESE.app bundles to this GDrive folder.
Building
Dependencies
ANESE's emulation core (src/nes) doesn't have any major dependencies, but the UI does use a couple. Most of these dependencies are bundled with ANESE (see: /thirdparty), although some require additional installation:
- SDL2 (video/audio/controls)
- Linux:
apt-get install libsdl2-dev
(on Ubuntu) - MacOS:
brew install SDL2
- Windows:
- Download dev libs from here and unzip them somewhere.
- EITHER: Set the
SDL
environment variable to point to the dev libs - OR: Unzip them to
C:\sdl2\
(Where I put them) - OR: Modify the
SDL2_MORE_INCLUDE_DIR
variable inCMakeLists.txt
to point to the SDL2 dev libs
- Linux:
Generating + Compiling
ANESE builds with CMake
On macOS / Linux
# in ANESE root
mkdir build
cd build
cmake ..
make
make install # on macOS: creates ANESE.app in ANESE/bin/
On Windows:
mkdir build
cd build
cmake ..
msbuild anese.sln /p:Configuration=Release
Running
ANESE opens to a directory-browser, from which ROMs can be launched.
ANESE can run from the shell using anese [rom.nes]
syntax. Certain features
are only accessible from the command-line at the moment (e.g: movie recording
/ playback, PPU timing hacks). For a full list of switches, run anese -h
Windows Users: make sure the executable can find SDL2.dll
! Download the
runtime DLLs from the SDL website, and plop them in the same directory as
anese.exe
Mappers
Most popular Mappers are implemented:
# | Name | Some Games |
---|---|---|
000 | NROM | Super Mario Bros. 1, Donkey Kong, Duck Hunt |
001 | MMC1 | Legend of Zelda, Dr. Mario, Metroid |
002 | UxROM | Megaman, Contra, Castlevania |
003 | CNROM | Arkanoid, Cybernoid, Solomon's Key |
004 | MMC3 | Super Mario Bros 2 & 3, Kirby's Adventure |
007 | AxROM | Marble Madness, Battletoads |
009 | MMC2 | Punch Out!! |
Feel free to open a PR for any mappers you implement :)
Controls
Currently hard-coded to the following:
Button | Key | Controller |
---|---|---|
A | Z | X |
B | X | A |
Start | Enter | Start |
Select | Right Shift | Select |
Up | Up arrow | D-Pad |
Down | Down arrow | D-Pad |
Left | Left arrow | D-Pad |
Right | Right arrow | D-Pad |
Any xbox-compatible controller should work.
There are also a couple of emulator actions:
Action | Key | Controller |
---|---|---|
Pause / Open Menu | Esc | Left Thumbstick Button |
Reset | Ctrl - R | |
Power Cycle | Ctrl - P | |
Toggle CPU logging | Ctrl - C | |
Speed +25% | Ctrl - = | |
Speed -25% | Ctrl - - | |
Fast-Forward | Space | Right Thumbstick Button |
Make Save-State | Ctrl - (1-4) | |
Load Save-State | Ctrl - Shift - (1-4) |
(there are 4 save-state slots)
DISCLAIMERS
- ANESE is not the best emulator out there, far from it! Expect bugs!
- My APU uses a naive sampling algorithm with a basic lookup table grafted from
the nesdev wiki. The
blargg-apu
branch has an older version of ANESE that uses Blargg's awesomenes_snd_emu
library for the APU, and while my integration was a bit unstable at times, it did sound a lot better when it did work. - The CPU is instruction-cycle accurate, but not sub-instruction cycle
accurate. While this inaccuracy doesn't affect most games, there are some that
that rely on sub-instruction level timings (eg: Solomon's Key).
- The
--alt-nmi-timing
flag might fix some of these games.
- The
TODO
These are features that will add major value to ANESE:
- Implement: Cycle accurate CPU (will probably fix many bugs)
- Implement: Better menu (not just fs, also config)
- CMake: more robust macOS bundles (good way to get SDL2.0 packaged?)
- Implement: LibRetro Core
- Implement: Get the Light-gun working
- Debugging: Add debug GUI
- All objects implementing the Memory interface must also implement
peek
, i.e: aconst
read. As such, a debugger could easily inspect any/all memory locations with no side effects!
- All objects implementing the Memory interface must also implement
Here's a couple that have been crossed off already:
- Implement: My own APU (don't use Blarrg's)
- Refactor: Modularize
main.cc
- push everything intosrc/ui/
- Refactor: Split
gui.cc
into more files!
- Refactor: Split
- Refactor: Push common mapper behavior to Base Mapper (eg: bank chunking)
And here are some ongoing low-priority goals:
- Refactor: Roll-my-own Sound_Queue (SDL_QueueAudio?)
- Cleanup: Unify naming conventions (either camelCase or snake_case)
- Cleanup: Comment the codebase even more
- Security: Actually bounds-check files lol
- Cleanup: Conform to the
.fm2
movie format better - Cleanup: Remove fatal asserts (?)
- Cleanup: Switch to a better logging system (*cough* not fprintf *cough*)
Roadmap
Key Milestones
- Parse iNES files
- Create Cartridges (iNES + Mapper interface)
- CPU
- Set Up Memory Map
- Hardware Structures (registers)
- Core Loop / Basic Functionality
- Read / Write RAM
- Addressing Modes
- Fetch - Decode - Execute
- Official Opcodes Implemented
- Handle Interrupts
- PPU
- Set Up Basic Rendering Context (SDL)
- Implement Registers + Memory Map them
- Implement DMA
- Generate NMI -> CPU
- Core rendering loop
- Background Rendering
- Sprite Rendering - currently not hardware accurate
- Proper Background / Foreground blending
- Sprite Zero Hit
- Misc PPU flags (emphasize RGB, Greyscale, etc...)
- APU
- Implement Registers + Memory Map them
- Frame Timer IRQ - kinda
- Set Up Basic Sound Output Context (SDL)
- Channels
- Pulse 1
- Pulse 2
- Triangle
- Noise
- DMC
- DMC DMA
- Joypads
- Basic Controller
- Zapper - still needs work
- NES Four Score
Secondary Milestones
- Loading Files with picker
- Reset / Power-cycle
- Fast Forward
- Run / Pause
- Saving
- Battery Backed RAM - Saves to
.sav
- Save-states
- Dump to file
- Battery Backed RAM - Saves to
- Config File
- Preserve ROM path
- Window size
- Controls
- Running NESTEST (behind a flag)
- Controller support - currently very basic
- A SDL GUI
- SDL-based ROM picker
- Options menu
Tertiary Milestones (Fun Features!)
- Zipped ROM support
- Rewind
- Game Genie
- Movie recording and playback
- More ROM formats (not just iNES)
- Proper PAL handling?
- Proper NTSC artifacting?
- Multiple Front-ends
- SDL Standalone
- LibRetro
- Debugger!
- CPU
- Step through instructions
- PPU Views
- Static Palette
- Palette Memory
- Pattern Tables
- Nametables
- OAM memory
- CPU
Accuracy & Compatibility
- More Mappers! Always more mappers!
- Add automatic testing
- Screenshots: compare power-on with 30 seconds of button mashing
- Test ROMs: Parse debug outputs
- CPU
- Implement Unofficial Opcodes
- Pass More Tests
- (Stretch) Switch to sub-instruction level cycle-based emulation (vs instruction level)
- PPU
- Make the sprite rendering pipeline more accurate (fetch-timings)
- Pass More Tests
- Make value in PPU <-> CPU bus decay?
Attributions
- A big shout-out to LaiNES and fogleman/nes, two solid NES emulators that I referenced while implementing some particularly tricky parts of the PPU). While I actively avoided looking at the source codes of other NES emulators while writing my initial implementations of the CPU and PPU, I did sneak a peek at how others solved some problems once I got stuck.
- These awesome libraries are used throughout ANESE's UI and in WideNES:
- cfg_path - cross-platform config file
- clara - argument Parsing
- cute_headers - cross-platform directory browsing
- miniz - zipped ROM support
- sdl2 - A/V and Input
- SDL_inprint - SDL fonts, without SDL_ttf
- simpleini - ini config parsing / saving
- stb - image loading / writing