Building a small gaming emulator
I built a small game emulator in Go - some condensed thoughts.
Specific learnings building CHIP-8
What is an emulator
I don’t have a Playstation, but I happen to have a computer. Is it possible to somehow play Playstation games in my computer?
Yes - if you build a Playstation emulator for your computer. Like the name suggests, an emulator emulates the entire Playstation hardware, it creates a make-believe Playstation on your computer. More on that in a bit.
Motivation
My motivation for building an emulator was two-fold:
I have spent an inhuman amount of time playing Gameboy games on my computer using emulators: Visual Boy in particular.
A bit of free time at the airport led me to reading the story of Playstation 2’s engineer who built backward compatibility with Playstation 1 games - he essentially built a PS1 emulator inside the PS2. It was a pretty cool thing to do at a time when no gaming consoles were backward compatible.
I started off by trying to create a Gameboy emulator. On realizing I had no idea where to start, I dropped to the CHIP-8 emulator, on which people used to play games in the 70s/80s/90s. The basic idea still remains - just like the Gameboy, anyone can create games (ROMs) for the CHIP-8.
How do emulators work
The concept of emulators is not limited to gaming consoles but for the sake of brevity, let’s consider gaming consoles.
To understand what an emulator is - let’s internalize the fact that at their core, gaming consoles are essentially computers. The difference is that they are built with the sole purpose of running games. This also means a lot of the core concepts transfer over:
Like computers, gaming consoles will have a processor whose job is to process instructions one after the other.
Games are essentially programs or a set of instructions.
They have special audio, video hardware which interacts with the software and the running program to give the entire experience of playing a game i.e. what is displayed on the screen, what sounds are emitted.
Note that every console will have it’s own processors and different processors speak different languages. One processor might require the instruction AD to add two numbers - the same might be ADD in a different processor. Games are essentially programs written in the specialized processor language for the particular gaming console.
On a high Level
Let’s think about it:
Computers have processors, we can execute instructions just like the Playstation’s processor.
We have Playstation CD’s - these are programs which contain instructions in Playstation’s processor language. We can simply copy the same to our computer disk. These are what .iso files are - an exact sector-by-sector copy of the Playstation disk.
The problem: My computer’s processor understands a different language - Playstation’s AD needs to be translated into ADD for my computer.
The solution: What if we made a program which has each of the mappings for each instruction? It reads the Playstation iso file byte-by-byte and tells my computer the translated instruction for each Playstation instruction.
If PS2 instruction is AD → execute computer instruction ADD
If PS2 instruction is SUBSTR → execute computer instruction SUB
There you have it. That is exactly the job of the emulator.
On a slightly lower level
The actual manner it does it in is slightly different. A simple instruction-by-instruction translation would be extremely difficult since processors are quite complex and involve a lot of other moving parts.
It models the entire hardware of the Playstation in software:
If the PS2 RAM is 4GB it will allocate a specific area of memory as the RAM.
It will allocate separate variables for registers.
If PS2 instruction speed is 700 per second, it will execute PS2 instructions at that particular speed.
This is done in such a way that it is as close to running on PS2 as possible - for the best experience. Instruction translation is also a part of emulation, but it is not the only part.
Specific learnings building Chip-8
Writing emulators will involve the same set of steps with gotchas
Once you’ve written the CHIP-8, you realize that the core steps in building an emulator are the same. The difficulty might certainly vary and something like a Playstation emulator will definitely be quite difficult, with many more gotchas - but what remains true is that you are essentially modelling the hardware virtually to run a very specific instruction set.
P.S Strictly speaking, the CHIP-8 is an interpreted language and not a gaming hardware, but we won’t get into that here.
Instruction set translations can be weird
Unless you are the first one building an emulator for a particular console, you will usually refer to someone else’s documentation for the instruction translation.
The issue here is that if there might exist multiple versions of the instruction set. This can be for various reasons - maybe a new version of the console came out which had optimizations.
The same instruction will now trigger slightly different behaviours. Some games might be built with the older version, while others might be built with the newer one.
You can either keep config flags for ambigious behaviour to ensure your emulator can handle the maximum number of games.
Refer to multiple sources to see how they have translated instructions. For the Chip-8, I referred to Tobias V. Langhoff’s and Cowgod’s guides
How WASM helped me (but Go to WASM is a little dicey?)
I first tried hosting my emulator as a Go build on leapcell.io. It provided me with a Go Alpine container.
The issue: I am using SDL to handle keyboard inputs. SDL is basically a wrapper around OS functions such as keyboard inputs, among other things, which abstracts away OS constructs and provides a unified API across platforms to access things such as keyboard inputs. Hosting it in a container accessed via a browser → it wouldn’t have access to the keypresses of the person accessing it via a browser.
Fix: Creating a separate WASM build - the only difference being that keypresses are handled via Javascript Event Listeners. The big advantage was that I could simply host my WASM executable as a regular webpage on Github pages - it doesn’t require a complete Go runtime anymore.
The drawback was that the WASM executable ran much slower than my native Go build - due to some sort of Go runtime overhead (possibly) that I didn’t go into. I played around a bit and got it up to speed by batching instructions and redrawing screen after executing batched instructions rather than at every instruction.
Play
You can play with my CHIP-8 emulator by clicking here.
You can access the source code here.

