Two years ago I thought it would be fun to attempt to write a GameBoy emulator. After dropping the project and picking it back up a bunch of times, it has now finally gotten to the point where some well known games appear to be decently playable for at least their first level. Many other games don't start at all or are full of glitches, some even crash my emulator. Nevertheless, this is a milestone moment for me so it deserves a blogpost.
The emulator is written in C using SDL to display frames on the screen. The code is a great showcase of my changing style preferences and increasing programming experience throughout the last two years. I'm planning to do a big cleanup, and maybe even a C++ rewrite someday when it's in a more complete state.
Structurally, the program consists of three parts: the CPU, the GPU, and the memory. The parts all have their own C file and roughly represent separate pieces of hardware inside the GameBoy/cartridge. There are many great guides out there on the specific workings of these parts, so I won't delve too deeply into that, but here is a quick overview:
- CPU: The CPU is emulated by a fetch-decode-execute cycle. This is the biggest time sink. You'll have to correctly implement all of the GameBoy Z80's instructions, including all their quirks and exceptions.
- GPU: The GPU, or LCD controller does all the graphical work, drawing things like the background layer and the foreground sprites. Emulating this requires a good understanding of the graphical pipeline inside the GameBoy, and all the relevant timings, registers and flags.
- Memory: The memory that's used by most GameBoy games is largely inside the cartridge. Because different games have different needs, there are many different types of memory bank controllers, which all need to be implemented.
I'm now at the state where I've implemented the above parts well enough that I can show some cool progress:
There's many things that still need to be implemented like audio, game saving (cartridges with batteries), cartridges with real time clocks, graphical windows, and bunch of MBCs. Apart from those features there are still a lot of bugs in the already implemented parts, causing weird glitches and crashes (as you can see in the video above). This has been and will stay the hardest part of this project: the constant debugging.
Check out my Bitbucket repository for this project. Pull requests are always welcome!