Another NES Emulator - written for fun & learning - first implementation of wideNES
Find a file
Daniel Prilik 8423bd9a30 cleanup
I'd like to think this commit marks the end of the first phase
of ANESE's development. It's been a long road, but ANESE is
finally at a point where I'm mostly happy with it.

ANESE sure as hell isn't perfect, but hey, it's pretty good!
The core code is pretty clean, the UI code is... acceptable, but
most importantly, ANESE actually plays my favorite NES games!

There is still some work to be done before I'd be comfortable
giving ANESE a v1.0.0 release, but what I have here is still
pretty great.

Let's call this ANESE v0.9.0 :)

-------

So, what next?

Well, contrary to what I said in some earlier commits, I think i'll
continue to work on ANESE a little bit more!
Specifically, i'd like to rewrite the 6502 emulation.

My current implementation is... okay.
It's instruction-level cycle accurate, but I don't think that's
good enough. It really should be sub-instruction level accurate.
Odds are the added accuracy will fix _a lot_ of bugs.

Aside from accuracy though, I have another reason to do a rewrite...

As a Waterloo student, I have to do a Work Term Report on some
technical project i've worked on recently. ANESE is one such project.
Since the report isn't designed to be very long, I'd limit my scope
to just a small aspect of ANESE: the 6502 emulator.

Yes, I could just write the report on how I arrived at my current
implementation, but I think it would be cool to attempt a cleaner
rewrite, and compare and contrast the two versions.

So yeah, stay tuned! I might also post the writeup (once I get
around to it)
2018-07-03 22:42:18 -07:00
cmake building on MSVC 2017-10-26 10:29:37 -07:00
research move docs to research 2017-11-12 12:48:01 -08:00
resources upload macOS bundles to GDrive 2018-06-08 10:47:29 -07:00
roms cleanup 2018-07-03 22:42:18 -07:00
scripts cleanup 2018-07-03 22:42:18 -07:00
src cleanup 2018-07-03 22:42:18 -07:00
thirdparty "fixed" config saving on Windows 2018-06-29 22:54:05 -07:00
.gitattributes move docs to research 2017-11-12 12:48:01 -08:00
.gitignore begin work on custom APU 2018-06-25 10:40:39 -07:00
.travis.yml fix travis 2018-06-28 10:00:20 -07:00
_config.yml Set theme jekyll-theme-minimal 2017-11-12 12:58:40 -08:00
appveyor.yml added demo rom (2048) to releases 2018-06-12 11:39:31 -07:00
CMakeLists.txt basic persistent config 2018-06-29 12:20:59 -07:00
LICENSE *initial commit 2017-10-13 20:18:31 -07:00
README.md cleanup 2018-07-03 22:42:18 -07:00

ANESE Logo

Build Status Windows Build Status macOS/Linux

ANESE (Another NES Emulator) 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! 😄

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's build artifacts page.

macOS: Travis uploads nightly ANESE.app bundles to this GDrive folder.

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 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.

# 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:

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:

  • 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 make ANESE a lot nicer to use: