**ANESE** (**A**nother **NES** **E**mulator) is a Nintendo Entertainment System
Emulator written for fun and learning.
While accuracy and performance are long-term goals, ANESE's primary focus is to
get some of the more popular titles up and running. Most basic Mappers have
been implemented, so many popular titles should be working! :smile:
ANESE is built with _cross-platform_ in mind, and is regularly tested on all
major platforms (macOS, Windows, and Linux). ANESE doesn't use any
vendor-specific language extensions, and is compiled with strict compiler flags.
It is also linted (fairly) regularly.
Lastly, ANESE strives to keep a clean and _interesting_ C++11 codebase,
emphasizing _readability_, _maintainability_, and _approachability_. The code
is well commented, providing sources and insights for much of the logic.
## Downloads
At the moment, there are no official releases of ANESE, but there are ways to
get nightly releases. These are compiled directly from the latest ANESE commit,
so there may be bugs.
**Windows:** You can download nightly versions of ANESE from
[AppVeyor](https://ci.appveyor.com/project/daniel5151/anese)'s build artifacts
page.
**macOS:** Travis uploads nightly ANESE.app bundles to
[this GDrive folder](https://drive.google.com/drive/folders/1GWiinQ4tjDSZlhjReVMdElwK1b-Zvagf).
## Building
### Dependencies
While ANESE's emulation core (src/nes) doesn't have any major dependencies,
there are a couple of libraries the UI uses. Most of these dependencies are
bundled with ANESE (see: /thirdparty), although some do 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](https://www.libsdl.org/download-2.0.php) 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 in `CMakeLists.txt` to
point to the SDL2 dev libs
### Generating + Compiling
ANESE builds with **CMake**. Nothing too fancy here.
```bash
# in ANESE root
mkdir build
cd build
cmake ..
make
make install # on macOS: creates ANESE.app in ANESE/bin/
```
On Windows, building is very similar:
```bat
mkdir build
cd build
cmake ..
msbuild anese.sln /p:Configuration=Release
```
If you're interested in looking under the hood of the PPU, you can pass the
`-DDEBUG_PPU` flag to cmake and have ANESE display PPU debug windows.
## Running
Running ANESE with no arguments throws you into a directory-browser, from which
you can navigate to your ROM and launch it.
Alternatively, 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
There aren't too many mappers implemented at the moment, but the ones that are
cover a sizable chunk of the popular NES library.
\# | 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!!
If a game you love doesn't work in ANESE, feel free to implement it's mapper
and open a PR for it :D
## 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 awesome `nes_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.
## 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: a `const` read. As such, a debugger could easily inspect any/all memory
locations with no side effects!
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 into `src/ui/`
- [x] _Refactor_: Split `gui.cc` into more files!
- [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] 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
### 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](https://github.com/AndreaOrru/LaiNES) and
[fogleman/nes](https://github.com/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 make ANESE a lot nicer to use:
- [sdl2](https://www.libsdl.org/) - A/V and Input
- [SDL_inprint](https://github.com/driedfruit/SDL_inprint/) - SDL fonts, without SDL_ttf
- [clara](https://github.com/catchorg/Clara) - argument Parsing
- [miniz](https://github.com/richgel999/miniz) - zipped ROM support
- [cute_headers](https://github.com/RandyGaul/cute_headers/) - cross-platform directory browsing
- [cfg_path](https://github.com/Malvineous/cfgpath) - cross-platform config file
- [simpleini](https://github.com/brofield/simpleini) - ini config parsing / saving