README.md

August 23, 2020 ยท View on GitHub

ANESE Logo

Build Status GitHub Actions Build Status Windows Build Status macOS/Linux

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:

wideNES on Metroid

Pretty cool huh? Here's another one:

wideNES on SMB1

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 in CMakeLists.txt to point to the SDL2 dev libs

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:

#NameSome Games
000NROMSuper Mario Bros. 1, Donkey Kong, Duck Hunt
001MMC1Legend of Zelda, Dr. Mario, Metroid
002UxROMMegaman, Contra, Castlevania
003CNROMArkanoid, Cybernoid, Solomon's Key
004MMC3Super Mario Bros 2 & 3, Kirby's Adventure
007AxROMMarble Madness, Battletoads
009MMC2Punch Out!!

Feel free to open a PR for any mappers you implement :)

Controls

Currently hard-coded to the following:

ButtonKeyController
AZX
BXA
StartEnterStart
SelectRight ShiftSelect
UpUp arrowD-Pad
DownDown arrowD-Pad
LeftLeft arrowD-Pad
RightRight arrowD-Pad

Any xbox-compatible controller should work.

There are also a couple of emulator actions:

ActionKeyController
Pause / Open MenuEscLeft Thumbstick Button
ResetCtrl - R
Power CycleCtrl - P
Toggle CPU loggingCtrl - C
Speed +25%Ctrl - =
Speed -25%Ctrl - -
Fast-ForwardSpaceRight Thumbstick Button
Make Save-StateCtrl - (1-4)
Load Save-StateCtrl - 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:

  • Implement: My own APU (don't use Blarrg's)
  • Refactor: Modularize main.cc - push everything into src/ui/
    • Refactor: Split gui.cc into more files!
  • 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
  • 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

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: