Developing for the Game Boy Color in 2024

This July I developed a small program for the Game Boy Color. Nothing too complicated it just shows a small animation and plays a sound. It's basically trying to pretend to be a custom bootscreen.

I wrote it in Game Boy assembler using the RGBDS toolchain.

It was a lot of fun but also very tedious. I have a huge amount of respect for the original developers for the Game Boy. The people that made Pokémon and Tetris are magicians.

Tools

For assembling and linking I used RGBDS, then GIMP to create PNGs with indexed colours, and finally Python to generate a sine wave lookup table for doing some maths inside the assembly code.

I used a Makefile to invoke these tools in the right order and launch the final binary in Gearboy: a Game Boy emulator.

An emulator is essential because it gives you a fast feedback loop during development, but it doesn't remove the need to test on real hardware. The first time I tried my program on a real Game Boy half the graphics were missing; it took me a while to figure out why.

VRAM

One thing that tripped me up is that you can't access VRAM at certain times. To get around this I wrote the data to general purpose memory and then copied it over to VRAM when I knew it was safe to do so ("Shadow OAM"). This worked fine on the emulator but breaks on real hardware because there isn't actually enough time to copy the memory over. Even if you start copying as soon as it's safe to do so, you won't finish before your time is up; the Game Boy is just that slow.

The solution is to use a special command to copy a block of memory in just 160 clock cycles (Start DMA). Issue is, you can't access normal memory while the command is doing work which is where your code is normally stored. You need to place the code that invokes the command into a special region of memory that stays available during the copy.

After applying this and some other fixes the code successfully ran on real hardware.

GB Assembly

The Game Boy system is very limited: something that would be easy in most other systems, positioning sprites into a flag shape, becomes complicated; requiring 44 lines of assembly.

This is primarily because of the low register count. You only get five of them: a, b, c, d, hl.

hl allows you to reference memory locations and with a you can do some basic arithmetic. The other registers are very limited so you end up constantly moving stuff in and out of a.

Result

I'm happy with the final result. It shows a Hämis from Noita, scrolling up, and holding an animating flag. At the end of the scrolling it plays two notes.

You can check out the source code on my GitHub: hamis.asm.

Run it inside your browser! Powered by riperiperi/amebo.

Learning materials

The following resources were helpful to me when learning about Game Boy dev: