/nez

An emulator for the NES. For fun and profit and all that.

Primary LanguageZig

Nez

An emulator for the Nintendo Entertainment System made using zig and raylib. The emulation is cycle accurate (as accurate as I could make it), and the code well commented. A secondary goal of this project is to be a learning resource for anyone wanting to write their own emulator.

NOTE: This repo is compatible with Zig v0.12.1. Should also work with Zig <= 0.14.0, but I haven't tested it.

Megaman gameplay Tetris gameplay

Usage

Make sure you have a ROM file in the iNES format. Some people download ROMs from piracy websites such as this one. Of course, I would never recommend that!

To launch a ROM from the command line:

nez path/to/rom.nes 

To see debug info while playing the games:

nez --debug path/to/rom.nes

Controls:

Controller Keyboard
A Q
B E
Start Enter
Select X
Up/Down/Left/Right Arrow keys

Components

The CPU: Ricoh-2A03

An 8-bit CPU used in a wide variety of computers, the most prominent of them being the NES. It is a derivative of the MOS-6502 (almost an identical clone), without support for decimal mode.

Resources:

Things to watch out for:

  • Zero page wrap around for instructions that use the zero page addressing mode.
  • RMW (Read-modify-write) instructions like ROR will first write the unmodified byte to the memory location, and then write the modified byte. This can make a difference with some mappers.
  • The CPU and PPU must run in sync. For a single CPU cycle, the PPU executes (roughly) three clock cycles. A good way to emulate this is to use the delta time between two frames, and then figure out how many cycles each chip should execute based on their respective clockspeeds.

If you're feeling adventurous, and want to write a cycle stepped emulator, then this datasheet can prove to be useful.

The PPU: The Ricoh-2C02

Resources:

Bus, Cartridge, Mapper, and other miscellany

Every game comes in a cartridge that contains the game code, assets, and sometimes extra hardware and battery.

A mapper is a blanket term that describes all kinds of extra hardware present in the circuit that extend the capabilities of the game console.

The Bus connects the CPU, PPU, and the Cart, allowing separate components to communicate with each other.

Building and testing

Clone the repository, then:

zig build run

This will open a custom ROM I wrote to debug the emulator. To play games, make sure you have a .nes file somewhere, and use:

zig build run -- <path-to-rom>

The CPU has about ~10k test cases for each instruction, coming from this awesome test repository. To run the CPU tests, use zig test src/cpu.zig.

TODO

  • Support vertical scrolling
  • Sprite zero hit
  • Support horizontal scrolling
  • Support split scrolling
  • Add support for the controller
  • Support more mappers
    • CNROM
    • UxROM
    • MMC1 (Some minor bugs remain, many games playable)
    • MMC3
    • MMC5
  • Add support for the APU.
  • Sprite overflow detection (very few games use this feature so not that high priority)

Motivation

I started out wanting to write a fantasy console, but didn't want to invent another programming language, compiler, assembler, and then write ROMs in those. Emulating an existing console sounded like an equally challenging, but more fruitful venture.