Nov 12, 2024

Building an NES Emulator: Part 1—Overview

In this post, I introduce the basics of the NES architecture and cover fundamental emulation concepts in an accessible way.

Article hero image

The Nintendo Entertainment System (NES) needs no introduction. Lately, I’ve become captivated by computer architecture and the inner workings of emulators, so I’ve set out to build an NES emulator in C++. This post kicks off a series where I’ll document my progress. Actually, I’m building two NES emulators: one solo and one with my university capstone group. Since I’m slightly ahead of my team, I’ll focus on my solo project in this series.

Here’s an Introduction Anyway

Emulation is fascinating. You’re creating a software version of hardware that can run almost anywhere. But from the outside—even for someone who’s been programming for a while—an emulator can seem like a black box. Sure, an NES emulator can play NES games, but how does it actually work? Is it a game engine? How does it take a game originally stored on a cartridge and run it as software on a modern computer? My goal with this project is to uncover these mysteries. I chose the NES because I used to own one, and it’s often recommended as a good entry point into emulation by more experienced developers in the scene.

Basic Terminology

Can we get technical for a moment? I’m assuming that you, my dear reader, are a programmer or a computer enthusiast who isn’t intimidated by a little technical jargon. If you’re not an expert, don’t worry; I’m new to most of these concepts too. I’m going to do my best to explain the technical specs of the NES, but hopefully in a more engaging way than just listing out a bunch of numbers

It’s pretty accurate to call the NES an 8-bit computer. At its core, a computer takes in data, does something with it, and outputs new data. The “8-bit” part refers to the size of its data bus. You can think of the data bus like an actual bus that transports people between cities—except in this case, the bus can only hold 8 passengers (bits) at a time, and the “cities” are locations in memory, some close, some far.

Bits and Bytes

I’ll talk about bits quite a bit in this series. I’ll admit, it wasn’t until my senior year of college that I could reliably remember how many bits are in a byte (it’s 8). Here’s a break down for reference:

  • 1 bit: 0 or 1
  • 1 byte: 8 bits
  • 1 Kilobyte (KB): 1,000 bytes (decimal system, used in most contexts we’re familiar with)
  • 1 Kibibyte (KiB): 1,024 bytes (binary system, used to describe memory architecture)
  • 1 Megabyte (MB): 1,000 KB or 1,000,000 bytes
  • 1 Mebibyte (MiB): 1,024 KiB or 1,048,576 bytes

There are higher units, but they’re not relevant to the NES.

Units can be confusing because computers use two systems. For storage devices and internet speeds, we typically use the decimal system (1 MB = 1,000 KB). But when describing memory architecture—like saying the NES CPU has 2 KiB of RAM (it does)—we use the binary system, where 2 KiB = 2,048 bytes (not 2,000). Memory addresses work in powers of 2, so kibibytes (KiB) and other 2-based units are more appropriate when describing memory architecture

So for example, there are 8,000,000 bits in a 1 Megabyte file. How long would it take the NES to read this into memory? Like all computers, the NES has an internal clock that controls its processing speed. Reading 8 bits of data takes two ticks of its clock, and the NES clock runs at 1.79 Megahertz (MHz)—or 1.79 million ticks per second. This means the NES can handle around 895,000 reads per second, and at 8 bits per read, that’s 7,160,000 bits per second. So, it would take just over a second for the NES to read that 1 Megabyte file, roughly speaking.

Memory and Cartridges

Of course, the NES doesn’t handle files like modern computers, and 1 Megabyte of data is far too large for its architecture. Instead, the NES reads data directly from cartridges, which averaged around 256 KB in size. Cartridge sizes range from as small as 8 KB (e.g., Donkey Kong) to 768 KB for the largest titles, like Kirby’s Adventure. Each cartridge contains all the game assets and programming logic needed to run the game.

As the system clock ticks, the NES makes “bus trips” between the cartridge and different parts of the system, delivering instructions on how to render graphics, play sounds, and respond to input. The cartridge acts as a read-only source, where the NES can pick up the data it needs in real-time to keep the game running smoothly. Because it’s read-only, game files are often referred to as ROMs (Read-Only Memory).

CPU, Instruction Flow, and the Program Counter

If data travels by a bus, then the Central Processing Unit (CPU) is the driver.

The CPU can read a byte (8 bits) of data and immediately understand:

  • What to do with the data (instruction)
  • Where to find or place data (memory address)
  • What other data is necessary to complete the instruction (operands)

This information is encoded in a single byte, but some operations require multiple bytes, so the CPU has to process them in sequence. Does every byte carry extra information to tell the CPU it’s mid-operation? No. Think of it like jumping into a book partway through—you’d lack context. Similarly, if the CPU reads random bytes without context, it won’t understand them. But when starting from the program’s first byte, the CPU knows each instruction’s length and when to move to the next.

The Program Counter is the component that keeps track of where each instruction byte starts. This instruction byte is known as the opcode, and it informs the CPU of what’s coming. The CPU reads the opcode and increments the Program Counter as needed to complete the operation. Once done, the Program Counter points to the next opcode. In the NES, the CPU uses 56 different opcodes to perform tasks like addition, data movement, and branching. This design isn’t unique to the NES; it’s fundamental to how most CPUs operate.

What Comes Next?

The NES has other components, and all rely on the CPU to work correctly. These components are:

  • The Picture Processing Unit (PPU), which renders graphics
  • The Audio Processing Unit (APU), which generates sound
  • Input Registers, which handle controller input

In most cases, the CPU reads instruction data from the ROM, processes it, and directs these components on what to do. However, there’s an exception: the PPU can access graphics data directly from the cartridge without going through the CPU. This is mainly to quickly retrieve graphical assets. It’s a complex process that I haven’t explored fully yet, but it’s worth mentioning. The PPU also operates on its own clock, which is something I’m currently studying.

Conclusion

The NES is a pretty cool system, and learning about its architecture has given me a deeper appreciation for computers. In this post, I aimed to cover the surface basics of the system without regurgitating the system specs, because we can just look to Wikipedia for that. There’s much more left to say in terms of describing how each component works and how they interact.

Join me in Part 2, where I take a closer look at CPU memory.

Emulation

Back to Blog