Making a Game Boy emulator

This video has convinced me that I should try to make a Game Boy emulator. My coding experience mostly involves writing small programs to carry out computations or visualisations of things related to my mathematics research. Given my new found interest in reverse engineering, emulation, and decompilation, this seems like a good way to learn how to write a bigger project, aswell as understanding (or hopefully rather discovering) how the problems involved with emulation are solved. I am also just about old enough to have owned a Game Boy while they were still being made. In fact, I think it might have been my first ever game console. I’m going to be mostly avoiding asking an LLM how to do “big picture” things so that this is more of a learning experience, but I am fine with enquiring about basic things.

My idea is to document the process here and show the, presumably naive, first attempts to do parts of this.

I went on to watch this video by the same creator afterwards which did a really good job of explaining what it is you need to do to build a Game Boy emulator, without telling you how to do it. He also provides some great resources that people have put together on the inner workings of a Game Boy.

What does it mean to emulate a Game Boy?

My understanding is that we are trying to write software that reproduces the behaviour of the hardware of the Game Boy. What does the hardware of a Game boy do? The primary thing it is supposed to do is run a Game Boy game, that is, process the instructions on a game cartridge and cause “things to happen” that those instructions were intended to.

Our first hexdump

A Game Boy cartridge contains read-only memory (ROM). This ROM contains a whole load of ones and zeros that the Game Boy is supposed to be able to understand. I have acquired a file called tetris.gb that is sitting on my computer which contains the same ones and zeros as the original Game Boy Tetris ROM. To take a look inside I’m going to use the xxd command line tool. The command xxd -u -l 512 tetris.gb outputs the following to the console.1

00000000: C3 0C 02 00 00 00 00 00 C3 0C 02 FF FF FF FF FF  ................
00000010: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ................
00000020: FF FF FF FF FF FF FF FF 87 E1 5F 16 00 19 5E 23  .........._...^#
00000030: 56 D5 E1 E9 FF FF FF FF FF FF FF FF FF FF FF FF  V...............
00000040: C3 7E 01 FF FF FF FF FF C3 BE 26 FF FF FF FF FF  .~........&.....
00000050: C3 BE 26 FF FF FF FF FF C3 5B 00 F5 E5 D5 C5 CD  ..&......[......
00000060: 6B 00 3E 01 E0 CC C1 D1 E1 F1 D9 F0 CD EF 78 00  k.>...........x.
00000070: 9F 00 A4 00 BA 00 EA 27 F0 E1 FE 07 28 08 FE 06  .......'....(...
00000080: C8 3E 06 E0 E1 C9 F0 01 FE 55 20 08 3E 29 E0 CB  .>.......U .>)..
00000090: 3E 01 18 08 FE 29 C0 3E 55 E0 CB AF E0 02 C9 F0  >....).>U.......
000000a0: 01 E0 D0 C9 F0 01 E0 D0 F0 CB FE 29 C8 F0 CF E0  ...........)....
000000b0: 01 3E FF E0 CF 3E 80 E0 02 C9 F0 01 E0 D0 F0 CB  .>...>..........
000000c0: FE 29 C8 F0 CF E0 01 FB CD 98 0A 3E 80 E0 02 C9  .).........>....
000000d0: F0 CD FE 02 C0 AF E0 0F FB C9 FF FF FF FF FF FF  ................
000000e0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ................
000000f0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ................
00000100: 00 C3 50 01 CE ED 66 66 CC 0D 00 0B 03 73 00 83  ..P...ff.....s..
00000110: 00 0C 00 0D 00 08 11 1F 88 89 00 0E DC CC 6E E6  ..............n.
00000120: DD DD D9 99 BB BB 67 63 6E 0E EC CC DD DC 99 9F  ......gcn.......
00000130: BB B9 33 3E 54 45 54 52 49 53 00 00 00 00 00 00  ..3>TETRIS......
00000140: 00 00 00 00 00 00 00 00 00 00 00 01 01 0A 16 BF  ................
00000150: C3 0C 02 CD E3 29 F0 41 E6 03 20 FA 46 F0 41 E6  .....).A.. .F.A.
00000160: 03 20 FA 7E A0 C9 7B 86 27 22 7A 8E 27 22 3E 00  . .~..{.'"z.'">.
00000170: 8E 27 77 3E 01 E0 E0 D0 3E 99 32 32 77 C9 F5 C5  .'w>....>.22w...
00000180: D5 E5 F0 CE A7 28 12 F0 CB FE 29 20 0C AF E0 CE  .....(....) ....
00000190: F0 CF E0 01 21 02 FF 36 81 CD E0 21 CD CC 23 CD  ....!..6...!..#.
000001a0: B7 23 CD 9E 23 CD 8C 23 CD 7D 23 CD 6E 23 CD 5F  .#..#..#.}#.n#._
000001b0: 23 CD 50 23 CD 41 23 CD 32 23 CD 23 23 CD F8 22  #.P#.A#.2#.##.."
000001c0: CD E9 22 CD DA 22 CD CB 22 CD BC 22 CD AD 22 CD  ..".."..".."..".
000001d0: 9E 22 CD D7 1E CD B6 FF CD CA 18 FA CE C0 A7 28  .".............(
000001e0: 1A F0 98 FE 03 20 14 21 6D 98 CD 3B 24 3E 01 E0  ..... .!m..;$>..
000001f0: E0 21 6D 9C CD 3B 24 AF EA CE C0 21 E2 FF 34 AF  .!m..;$....!..4.

What are we looking at? Where are all of the promised ones and zeros?

Every byte (8 bits) has been converted to a two digit hexadecimal number, making things more compact and easier to read.

Okay, fine, but what are we looking at?

The program xxd is decorating the pure data. The leftmost column is the address (given in hex) of the first byte in each row. The right most column with all the dots is the result of xxd showing the associated ASCII character of a byte, when such a printable character exists. Otherwise it prints a dot. Usually this just produces a garbled mess of random characters but if strings have been encoded in ASCII onto the ROM, then they will show up here. The very standout TETRIS text suggests that we are at least looking at the right ROM. The collection of hex in the middle is the actual data from the ROM. Each byte written as a 2 digit hex number. A bytes position in a row lines up with the ASCII character or dot in the right most block. You should be able to figure out what the ASCII encoding of the word TETRIS is.

Thanks, I now know the ASCII encoding of TETRIS, but I still don’t know what we’re really looking at.

Me neither! This ROM is supposed to consist of instructions that the Game Boy understands. I am not a Game Boy (I presume that you are not either) and so I don’t necessarily understand these instructions. According to the Pan Docs, however it does it (and I don’t know how yet), when the Game Boy boots the game, it begins reading at address $0100. They go on to say “Most commercial games fill this 4-byte area with a nop instruction followed by a jp $0150”. For the TETRIS ROM, those bytes are 00 C3 50 01. So the Game Boy starts reading these one at a time. If we assume that TETRIS falls into “most commerical games”, then 00 should stand for a nop or “no operation”. I can get behind as being a sensible number to assign to the act of doing nothing. So then C3 50 01 must stand for whatever jp $0150 means. In fact, we can see 0150 in there except that its backwards. This is because Game Boy memory is little-endian. When the Game Boy is reading the bytes of a number, the first byte it reads is the least significant and the last byte it reads is the most significant.


Footnotes

  1. The flag -u tells xxd to make everything upper case. The flag -l [num] only prints the first [num] bytes. ↩