In this series I will try to create a N64 emulator. Heavily inspired by Jake Taylor’s Ferris Makes Emulators (@ferristweetsnow on “the Twitter”) I will try to do my own version adding my own touches to the product as well as learning about emulators and low-level programming. Also, I’m not that comfortable in front of a camera so I’ll document the process through my blog instead.
Because I haven’t done anything like this before (either documenting the development process on my personal projects or write an emulator) I don’t have a clear path for how this will go. We’ll just have to see what the theme for each part will be as we move along. This first post will simply be an introduction to the project and I hope to get down to some coding as soon as in the next part, though I have set up a very bare bone repository over at GitLab to get started.
The source code and documentation along with some nice-to-have links and information will be available at the GitLab repository.
Please don’t do piracy. I will not link or promote any piracy related content.
Tools and Language
For the language of choice I have gone for Rust, just as Jake. I was thinking about doing this series in some other language like Go, D or modern C++ (C++14 or even 17), as I have done some C++ development in the past. Professionally I work mainly with Java full time though. But it came down to a few key features that I appreciated with Rust:
- Speed. Rust is very fast because it does compile to down to machine level code. It doesn’t run on a virtual machine like Java or Ruby. It’s even on par with C! The downside with this though is that it isn’t as portable as the VM hosted languages.
- It has proper module system. For me it really helps with the structure of the project and where stuff should go in terms of common functionality
- Pattern Matching. This actually helps alot when dealing with tokens of data, such as CPU instruction sets in this case. Writing a parser is also a great use case for this
- Testing is a first class citizen. No framework to set up in order to write and execute tests
- C integration. We might have to resort to some low level performance tuning. Also, there are libraries which have C interfaces that we might be able to reuse, such as OpenGL for graphics rendering
Note that I haven’t previously done any Rust development so it will also be a learning experience.
I come from a very Object-Oriented background so the structure of the project and how I’ll model the problem space is going to reflect this.
One nice thing about Rust is that the same package can be both a library and an executable. This means that there doesn’t need to be two packages where one is a library of reusable functionality and one is the executable that depends on the library. So
src/main.rs will contain the entry point for the executable while
src/lib.rs will contain the entry point for the library with reusable functionality.
So what are we trying to do really? Well, the N64 consists of a number of components and peripherals that makes up the console. Instead of they being physical components we’ll create software counterparts that behave like components, i.e. we’ll emulate the components. Ideally the games wouldn’t know the difference between our emulator and the original console.
On Tom Plaskon’s Blog there is a great overview of the N64 main components that we’ll begin to concentrate on.
- The Reality Co-Processor. Basically a graphics card in the form of a chip
- RAM - the main memory
- Audio and video analog/digital converter
- PIF ROM which contains the boot sequence
These components will have to be modelled as code (well, maybe not the AV converter) and we will come back to them in detail in future parts.
In the next part we’ll get down to some coding which will be really basic stuff. We’ll focus on parsing the command line and loading the cartridge ROM from file.