Git Product home page Git Product logo

nes-emulator-rust's Introduction

Build Status

Rust Nes Emulator

This project is a learning project to attempt writing a cycle accurate NES emulator in rust. It is not intended to be used to play games or to debug other emulators and has no features beyond "run this rom".

Key Missing Features

  • APU is only partially complete (no DMC) and does not yet output audio (no mixer and no provision for sending the samples anywhere)
  • ~600 ROMs without mapper support out of the ~4000 total
  • No support for peripherals beyond a standard NES controller
  • Support only provided for NTSC timings
  • No optimisation. It runs at >60fps on my development machine so no rush to optimise.

Architecture

There are many rust NES emulators, this one differs slightly in that it is entirely compile time checked code, it contains no unsafe blocks (except those in dependencies) and no Rc<RefCell<>> for runtime checking. This is achieved through the following architecture:

Architecture

The two key architectural decisions here are that the CPU owns all other components and is responsible for the top level "step" function to move a single cycle (note here that a single cycle is one PPU cycle, not one CPU cycle) and that the cartridge is broken into two parts, the PRG ROM/RAM that is attached to the CPU address bus and the CHR ROM/RAM which is attached to the PPU address bus. In order for register writes that update mappers to be reflected the CPU must therefore write each value mapped to 0x4020..=0xFFFF through to both cartridge components.

Development

Pre-requisites

I developed the emulator on Windows using the stable rust toolchain at version 1.47.0, tests run on Mac/Windows/Linux against stable and nightly on each push.

Running Tests

The tests are full integration tests of the entire emulator using the test roms collated here roms/test. The original source of these tests is the nesdev wiki.

cargo test  

The tests can take a few minutes to complete but should all pass on all machines. If a test fails it will print, in ascii art, the screenshot at the time of the failure.

Benchmarks

At present there's only a single benchmark, it runs the "spritecans" test rom for 100 frames and the reports are not presently checked into the code base.

Benchmarking spritecans 100 frames: Collecting 100 samples in estimated 16.503 s (100 iterations)
Benchmarking spritecans 100 frames: Analyzing
spritecans 100 frames   time:   [148.33 ms 150.97 ms 153.92 ms]
                        change: [+2.1495% +4.7664% +7.4174%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 10 outliers among 100 measurements (10.00%)
  6 (6.00%) high mild
  4 (4.00%) high severe

is the most recent execution. It's not yet clear how useful that benchmark is, I haven't spent time optimising yet.

nes-emulator-rust's People

Contributors

davetcode avatar dependabot-preview[bot] avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

johnbatty

nes-emulator-rust's Issues

Interrupt polling isn't quite correct

I currently poll for interrupts before retrieving the opcode of instruction n+1. Technically this is incorrect, interrupt polling happens during the previous operation (perhaps cycle 2? perhaps penultimate cycle?). This will break some test roms (cpu_interrupts_v2 at least) and makes my cycle counts slightly offset to other accurate emulators.

Fixing perhaps requires better knowledge about which cycle I'm in during an operation. Maybe already have that via the addressing mode + instruction type?

Fix implementation of 8*16 size sprites

Legend of Zelda uses 16 pixel high sprites and on the name selection screen Links sprites are reversed and upside down. That could be that the attribute byte is wrong but could equally be a misinterprtation of how to find the 16 pixel high bytes. Not confident by that code either

Handle default background color changing depending on vram address

https://wiki.nesdev.com/w/index.php/PPU_palettes#The_background_palette_hack

"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color. (Looking at the relevant circuitry in Visual 2C02, this is an intentional feature of the PPU and not merely a side effect of how rendering works.) This can be used to display colors from the normally unused $3F04/$3F08/$3F0C palette locations. A loop that fills the palette will cause each color in turn to be shown on the screen, so to avoid horizontal rainbow bar glitches while loading the palette, wait for a real vertical blank first using an NMI technique."

I think this might be why the full_palette test doesn't display anything at the moment, I always use black as the background color

Sprite overflow timing test fails

image

Given that this is the first of those tests which suggests that the 9th sprite is way after the 8th perhaps I'm missing something timing related with how the sprite eval machine works with sprites that are not getting copied to secondary OAM. Doesn't seem likely given the code though :/

Fix BRK command

Instr Test v3 includes a BRK test which is failing, don't think I've tested that anywhere else so it's likely just egregiously bad

Fix 10.len_halt_timing APU test

Result is #3 at the moment which the readme says means:
"3) Length should be clocked when halted at 14915"

Specifically the test is testing "Changes to length counter halt occur after clocking length, not before."

Fix holy mapperel tests

Lots of the mapper tests are failing, likely because I'm not sure what to return for unmapped addresses

Fix sprite rendering pipeline

There's loads of potential issues with sprite rendering, various sprites will pick up the wrong colors, jump about the screen and generally just not appear correctly.

It's hard to find a single sprite that does render properly in fact. So most likely culprit is the sprite fetch pipeline looking at the wrong bytes for attribute/y/x

About the only thing that does mostly work is that the right tiles are being drawn (generally)

Implement MMC3 mapper

This covers a couple of test roms that do more thorough testing as well as a significant number of games

Various games hang during their opening sequence

Zelda hangs after pressing start or as it scrolls to the sprites

Probably something relating to interrupts since that's what I've changed most recently. Just need a cpu dump at the time to see what loop it's stuck waiting on

Fix cpu to completely pass blargg cpu instr tests

nestest log matches exactly to the one online but:

cargo run --release .\roms\test\blargg_nes_cpu_test5\official.nes

seems to error on basically all tests so presumably something is badly wrong

Support decay for OAM ram

OAM RAM is supposed to decay when it's not being refreshed. Possibly just whilst rendering is off entirely?

Fix 11.len_reload_timing

Failing with result #4

Test is checking "Write to length counter reload should be ignored when made during length
counter clocking and the length counter is not zero."

And #4 means 4) Reload during length clock when ctr = 0 should work normally

Back to the future status window isn't placed correctly

image

To me that looks like I'm starting to render the status window way too high up the screen, unclear what could cause that though. Question is how it decides when to start rendering it. Sprite zero hit? Sprite overflow? Cycle counting?

Game is mapper 3 so nothing interesting there

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.