ANESE
ANESE copied to clipboard
Another NES Emulator - written for fun & learning - first implementation of wideNES
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:
- [x] Implement: My own APU (don't use Blarrg's)
- [x] Refactor: Modularize
main.cc
- push everything intosrc/ui/
- [x] Refactor: Split
gui.cc
into more files!
- [x] Refactor: Split
- [x] 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
- [x] Parse iNES files
- [x] Create Cartridges (iNES + Mapper interface)
- [x] CPU
- [x] Set Up Memory Map
- [x] Hardware Structures (registers)
- [x] Core Loop / Basic Functionality
- [x] Read / Write RAM
- [x] Addressing Modes
- [x] Fetch - Decode - Execute
- [x] Official Opcodes Implemented
- [x] Handle Interrupts
- [x] PPU
- [x] Set Up Basic Rendering Context (SDL)
- [x] Implement Registers + Memory Map them
- [x] Implement DMA
- [x] Generate NMI -> CPU
- [x] Core rendering loop
- [x] Background Rendering
- [x] Sprite Rendering - currently not hardware accurate
- [x] Proper Background / Foreground blending
- [x] Sprite Zero Hit
- [ ] Misc PPU flags (emphasize RGB, Greyscale, etc...)
- [x] APU
- [x] Implement Registers + Memory Map them
- [ ] Frame Timer IRQ - kinda
- [x] Set Up Basic Sound Output Context (SDL)
- [x] Channels
- [x] Pulse 1
- [x] Pulse 2
- [x] Triangle
- [x] Noise
- [x] DMC
- [x] DMC DMA
- [ ] Joypads
- [x] Basic Controller
- [ ] Zapper - still needs work
- [ ] NES Four Score
Secondary Milestones
- [x] Loading Files with picker
- [x] Reset / Power-cycle
- [x] Fast Forward
- [x] Run / Pause
- Saving
- [x] Battery Backed RAM - Saves to
.sav
- [x] Save-states
- [ ] Dump to file
- [x] Battery Backed RAM - Saves to
- [x] Config File
- [x] Preserve ROM path
- [x] Window size
- [ ] Controls
- [x] Running NESTEST (behind a flag)
- [x] Controller support - currently very basic
- [x] A SDL GUI
- [x] SDL-based ROM picker
- [ ] Options menu
Tertiary Milestones (Fun Features!)
- [x] Zipped ROM support
- [ ] Rewind
- [ ] Game Genie
- [x] Movie recording and playback
- [ ] More ROM formats (not just iNES)
- [ ] Proper PAL handling?
- [ ] Proper NTSC artifacting?
- Multiple Front-ends
- [x] SDL Standalone
- [ ] LibRetro
- [ ] Debugger!
- [ ] CPU
- [ ] Step through instructions
- [x] PPU Views
- [x] Static Palette
- [x] Palette Memory
- [x] Pattern Tables
- [x] 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
- [x] 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