A computer screen on a desk with keyboard and mouse showing the title screen of the game “Balloon Fight” in black and white.

Why I Wrote A Nintendo Emulator

Himal Mandalia
10 min readMay 1, 2024

--

Back in 2008 I wrote an emulator for the Nintendo Entertainment System (NES) game console.

Came across some old photos recently. Reflected a bit and then decided to write this.

I’ll keep this fairly high-level but will dive into some technical detail here and there. There’s one code segment for illustrative purposes. This post is more about the journey I went on rather than the specifics of what I did.

So what’s an emulator? From dictionary.com:

Hardware or software designed to imitate a different piece of hardware or a different software system, in order to do the same work or run the same programs.

In this case being able to play NES games on a PC or Mac. There are many emulators out there for various game consoles and computer systems (same thing in principle).

I’d been fascinated with emulators for about as long as I’d been interested in computers. Running computers within computers. Emulators within emulators. Turtles all the way down.

Emulators were fun. I wanted to write one.

I’d been coding on and off since the age of 11. Starting with QBASIC then later moving onto C and tinkering with Linux kernel internals. Just out of curiosity and enjoyment. Only reason to ever do anything.

After a foray into photography and some retail jobs I’d decided to go to university to do Computer Science. Reluctantly. A sort of “why not?” I was dubious about the workplace emphasis of all the courses I’d looked at. “Professional” wasn’t in my vocabulary. I was there for the pure computer science.

Fast forward, the final year project was approaching. That was a good enough excuse. Time to write my emulator. What better way to demonstrate my understanding of the fundamentals of computer science than to emulate an entire computer system in code?

The popularity and simplicity of the NES made it a good choice. It was well documented too. Well trod territory but still a challenge.

It was possibly the biggest thing I’d done up till then. I was used to going big.

The year before I’d delivered an airline ticket management system as part of a year long team project. On my own, which went against the spirit of a “team project” but that’s how it went. No complaints from the randomly assigned members of the team. We were all awarded 100%. A member of the faculty remarked this was the only deliverable out of 30 or so teams they could see being used in the real world. Nice. I built things. They worked.

In the first year I’d gone beyond the brief of delivering a static adventure game and delivered a fantasy roleplaying with full sprite animation, rules system, combat mechanics, inventory management, map screen and more.

Circa 2006, still runs.

Four horizontal panels. Screenshots from a sprite based RPG game showing the game screen in the first two. Inventory and character profile pages in the last two.

Anyway, BIG. I was also used to burning out. Testing limits.

With this I wasn’t entirely sure I could do it. Which made it all the more exciting.

I started research and prep before the academic year started. Reading all available documentation I could find on the NES. Experimenting and prototyping. Learning by doing is the only way.

These were the areas I’d need to cover to produce a working emulator:

  • CPU and memory
  • ROM support, i.e. loading game data
  • Graphics processing and rendering
  • Input handling

I decided to leave out audio. I could come back to that if there was time later. The graphics work was looking very tricky. Scary even. I was struggling to make any sense of it. I’d figure it out as I went along.

I also decided to only support the initial Nintendo games, e.g. Donkey Kong, Mario Bros. etc. Later games relied on advanced features provided by custom chips in the game cartridge to extend the console’s capabilities. These various “mappers” could also be emulated, and other more “complete” emulators did just that. I wasn’t going to go that far. Supporting the initial core games would suffice.

Getting to a point where those original NES games could be played (without sound) smoothly, replicating as much of the original experience as possible, was achievement enough. I wasn’t producing this to compete with any existing NES emulators. This was about learning, challenge, growth and a mega dopamine hit.

I got started with the CPU. The NES was powered by the MOS Technology 6502, a popular 8-bit processor used across a number of computer systems and game consoles of the era. Well documented, easy to understand. I had to learn 6502 assembly in order to debug my emulator. I was working in C++. Coding and testing addressing modes and instructions. Registers, flags, opcodes, clock timings.

It was just one big continuous loop with a switch statement to handle the instructions. Read opcode. Determine which instruction. Determine which addressing mode. Fetch data from location in memory. Perform appropriate operation. Write back to memory. Fiddling registers and flags here and there.

I could visualise the inner workings. It’s one thing to know the theory behind the operation of a processor and another to be simulating one in code and running through it step by step.

It was simple. Elegant.

Even more straightforward was loading game data. Game data is extracted from cartridges and made available online as a “ROM.” Licensing and copyright means it’s not legal to simply download ROMs. Unless you happen to own the original games. Which I did.

The ROM format was sensible. Configuration flags, game logic, background tiles, character sprites. I’d parse all that and load it into my emultator’s memory (a simple array).

Then there was the Picture Processing Unit. The graphics hardware of the NES. Yikes. This was hard.

262 “scanlines.” 240 of which make up what’s displayed on the screen. Horizontal lines. Rows of 256 pixels. Composited from background tiles and character sprites. All making up a 256 x 240 frame to be displayed.

My first pass at this was to try to render some background tiles in ASCII to a text file. Just to see if I was able to parse and assemble those rows of pixels correctly.

A text file showing a very rough rendering of a game’s title screen in ASCII characters was my first moment of validation. The first visible sign of success. About two months in. I was on the right track.

Alt text: ASCII output showing barely visible “Balloon Fight” title screen.

I concentrated on getting full background rendering working. First in black and white. Colour palettes were tricky (had them hard coded as lookup tables).

Donkey Kong below at the black and white stage. The Donkey Kong character in the top left is actually a set of background tiles and not a sprite. Not visible is Mario who would be a foreground sprite, as would the barrels and other obstacles thrown down. That was to be done next.

A computer monitor displaying the Nintendo game Donkey Kong in black and white, with the platforms and titular character in the top left but no other characters/sprites.

To handle input/output I used the SDL library (provides display output, device input etc). Simple to take my assembled framebuffer of 256 x 240 pixels and chuck them on the screen.

Next up, the foreground sprites, i.e. moving elements. Rendering these and mixing them into what I’d already added to the framebuffer. Line by line. Many many bitshift operations, trying to work out how to compute sprites by position and orientation (can be flipped horizontally or vertically) almost broke me.

A good few weeks of trying to make sense of some of that on paper. Sometimes like a crazed man on the train surrounded by notepads and scraps of paper, scribbling code and weird symbols in order to work out how to render the sprites correctly. Fun times.

Eventually I cracked it. Or it cracked me. Rendering the sprites at the correct position, with the correct horizontal and vertical orientation and setting a “hit” flag if any part of the sprite has touched another “non-transparent” sprite or background element. Collision detection, i.e. “Has a barrel bonked Mario on the head?”

This is the function used to render the sprite frame.

inline void PPU::render_sprite_frame() {
for(int i = 252; i >= 0; i -= 4) {
Byte* sprite = &SPR_RAM[i];

int y_pos = sprite[0] + 1;
int h_pos = sprite[3];

int tile_index = sprite[1] << 4;

Byte* tile = &sprite_pattern_table[tile_index];

int palette_index = (((sprite[2] >> 1) & 1) << 1)
| (sprite[2] & 1);

bool h_flip = (sprite[2] >> 6) & 1;
bool v_flip = (sprite[2] >> 7) & 1;

//bool bg_priority = (sprite[2] >> 5) & 1;

int pixels[8][8];

for(int j = 0; j < 8; j++) {
int k = 0;
for(int bit = 7; bit >= 0; bit--) {
int colour_index = (((tile[j + 8] >> bit) & 1) << 1) |
((tile[j] >> bit) & 1);

// If NOT a transparent colour...
if(colour_index > 0)
pixels[j][k]
= VRAM[SPRITE_PALETTE + (palette_index << 2) + colour_index];
// Otherwise flag pixel as transparent (-1)
else
pixels[j][k] = -1;

k++;
}
}

// Copy tile pixels into framebuffer
for(int v = 0; v < 8; v++)

for(int h = 0; h < 8; h++)

if(y_pos + v < 240 && pixels[v][h] != -1) {
int y = y_pos + (v_flip ? 7 - v : v);
int x = h_pos + (h_flip ? 7 - h : h);
Byte bg_pixel = framebuffer[y][x];

// Only for sprite 0
if(i == 0 && (bg_pixel != VRAM[IMAGE_PALETTE] && pixels[v][h]
!= VRAM[SPRITE_PALETTE])) {
// If bg pixel and sprite 0 pixel are non-transparent set hit flag
PPU_Status_Reg |= 0x40;
}

framebuffer[y][x] = pixels[v][h];
}
}
}

So that was that. Background and foreground scanlines. Assembled, composited in the frame buffer and then displayed. Over and over again in a loop.

Then all output with a simple SDL library function. 256x240 pixels. Scaled as necessary. I provided fullscreen mode too.

SDL library also used for keyboard input. Key detection handled by setting “button up” or “button down” states in memory at fixed locations, read by the CPU, generating an interrupt.

Timing handled by working out the number of CPU cycles per scanline along with preset “cycles per instruction” data. Meaning I could keep emulation running at a consistent speed.

And that was it. Finally, I had a working emulator! It was playable. It ran smoothly.

Mario Bros game screenshot.

I wasn’t done. There would be a demo and a bit of flourish was needed. Why play with the keyboard when the games were designed to be played with a controller?

I would add support for controllers. Which controllers? The original ones.

I got two original NES controllers. I got some USB microcontroller chips. Opened up the controllers. Snipped off existing cables and soldered onto the USB microcontroller.

Voila! USB NES controllers!

An original Nintendo controller with the back taken off. Showing circuit board and snipped cable bundle.
A USB cable with microcontroller chip soldered onto NES controller circuit board.
A NES controller with a USB cable and connector.

That was it. I was done.

The demo went very well. There was some perplexment at what I’d done. All the other final year projects had been websites.

I felt I had manifested computer science.

I was happy with the result and sense of accomplishment. It had been my life for over 6 months. A complete obsession. There had been moments of thinking it wasn’t going to work and wanting to give up. In retrospect I could have made this easier on myself with some rigour and discipline around testing. I didn’t know better at the time. I was a hacker.

Oh yes. I forgot to write the dissertation. Which was a problem as that’s where the bulk of the grading would come from. Oops.

I never did finish that. In fact I didn’t finish the degree. I dropped out. I was burnt out.

I never revisited the emulator either. I was done with it. It had been about the journey, not the end product.

A rite of passage.

I dropped the code in GitHub a few years later. It’s unchanged since 2009. Here for anyone interested. There are comments through the code. Mine and also some pasted blocks from documentation sources.

I dusted off the code while writing this post. It compiled easily. Still works over 15 years later.

I have no idea what happened to those USB NES controllers.

Running on my MacBook as I finish up this post.

MacBook Pro resting on bed. Screen shows a window running NES Mario Bros game.

Never celebrated the achievement. This post is my way of doing that. And to remind myself: I can do big things.

Or maybe this is the missing dissertation.

Why did I write the emulator? Like with everything else I do, for the sheer hell of it.

Technical details for running the emulator

There is a simple Makefile in the repo. SDL needs to be installed along with the sdl-config tool. It will compile and run on most UNIX/Linux environments.

Game ROMs are needed. Don’t download ROMs illegally. There are public domain ROMs here — games people have cooked up for the NES. Have fun!

--

--