Exploring Emulation in Go: CHIP-8

Tom Elliott
May 26, 2018 · 5 min read
Tetris running on CHIP-8

Finding a guide

A quick Google search led me to Laurence Muller’s excellent tutorial, which gives an overview of the general concepts and provides a few sample implementations of opcodes (including the more difficult graphics related ones). The tutorial stops short of explaining all the opcodes, since they’re all listed on Wikipedia and elsewhere, and this leaves just enough challenge for a first time implementer. Not only that, but I was able to work through the tutorial itself in a few hours, and have a great starting point to finish everything off the next day.

Implementing Opcodes (the repetitive bit)

I got hold of a couple of roms from other projects (there are tons of examples out there), and loaded them against the skeleton I had. I found that implementing the opcodes was much less tedious if I loaded up a rom, and ran it until it hit an unimplemented opcode, then I could fix that opcode and move on to the next.

Graphics and Input

I was already familiar with Pixel, a 2D game library for Go, so it was an easy choice for this project. The structure recommended by the tutorial lent itself really well to separating the actual rendering of graphics from the CHIP-8 emulation itself. All I needed to do was expose the appropriate inputs and outputs and add calls to handlers inside the main loop.

Emulation loop adapted for Pixel

Fine Tuning

It was pretty clear that the timers were off when I saw Tetris running way too fast. Re-reading, I discovered that they needed to be counting down at 60Hz, which the skeleton provided by the tutorial wasn’t doing. Go’s concurrency support made it easy to limit the counters to this frequency, using a time.Ticker and a select statement to only decrement if there was a tick waiting in the channel.

From Switch Statements to Functions

My initial implementation of opcodes involved a very large switch statement, which was difficult to follow and moreso to debug. The tutorial recommended moving away from this to a function based approach as a further goal for the project, so I created a separate function for each major opcode, and mapped them to the mask values previously checked by the switch statement.

Next Steps

This has been a fascinating weekend project that I’d recommend to anyone who feels like dipping their toe into the world of emulation programming. Especially if you feel like you don’t have time for it, you can have something up and running in a few hours!

average-coder

The Average Coder

Tom Elliott

Written by

The Average Coder

average-coder

The Average Coder