An Engineer’s Guide to Gameboy Architecture

I don’t like consumerism. One of my favorite Scholars, Bertrand Russell, once said

“It is preoccupation with possessions, more than anything else, that prevents us from living freely and nobly."

But you can bet I have a soft spot in my heart for Nintendo products. Pokemon on Game Boy Advance was one the only games I have ever truly enjoyed before being dragged by the dark, drab realities of life. I’d love to have a shelf with Pokemon merch, but I digress.

Now that we are done with that segment, let’s get started by looking at the beautiful, beautiful Game Boy Classic!

The Game Boy is as old as me, and it has more processing power than me. It has an 8-bit processor called the SHARP LR35902, which is a “hybrid” between Intel 8080 and Zilog Z80. Z80 is considered an enhancement of the 8080. Z80 had an enhanced instruction set that had single-bit addressing, shifts/rotates on memory and registers other than accumulator. You had program looping, program counter relative jumps, block I/O and byte search instructions. Z80 also had new IX and IY index registers and a better interrupt system. SHARP LR3590 had a little bit of both.

We had a clock speed of about 4.2 MHz, which is achieved by a Crystal Oscillator. All of this worked on 3V DC, 0.6W supply. Alt Text (That’s CPU + Power Processing Unit + Audio Processing Unit)

Gameboy’s 8-bit CPU is called DMG CPU, equipped with 6 registers of 16 bit each: AF, BC, DE, HL, SP and PC. Here’s what they mean -

Now in GameBoy, execution starts at location 0, which is where GameBoy’s boot ROM is located. You’ll find the first instruction for the cartridges at the location 0000000100000000 , and we’ll talk more about this in a minute.

A typical way to fetch the instruction from memory would look like this charming little self-explanatory pseudocode.

1. variable program_Counter = 0x0100 
2. variable operation = fetch_Operation(PC)
3. switch(operation){ case no_Operation{break}; case operation{operation; break;}

//The fetch_Operation would be
define operation{return memory[program_Counter++]

Now, remember, Z80 and GB’s CPU use syntactically similar languages, so when we look at some real GB codes, don’t be too surprised to discover that Z80 and LR35902 have similar looking codes. For example, the instruction extender is same in both (opcode 0xcb).

An important note on commands

Alright, now that these commands have been fetched, we need to execute these commands. There are 8-bit load commands and 16-bit load commands. They do the work of loading things from place A to place B (eg. loading the content of a register to a stack). Finally, there are 8-bit Arithmetical and Logical Operations (eg. increment a value stored in register). In the DMG CPU, there’s not a lot of 16-bit arithmetical operations to start with, and they just operate on the 16-bit registers. There’s also shifting and rotation (shifting but the bits wrap around the edges) commands (eg. 00010000 -> 00100000).

There are a few couple other control operations as well: HALT (Halt until interrupt), NOP (Don’t do anything), Enable/Disable Interrupts. Then you’ve got Jump operations, using which you can jump to any location in the memory.

Let’s talk about memory

Data is a bit obscure to the CPU. All this hullabaloo of wires we deal with in real world is irrelevant to the CPU. It is a processing unit, it gets data and it processes it. CPUs process all data, some correctly, some wrongly, but it is a heartless, agnostic machine, that takes in data, churns out data.

Address Bus is that good friend of the CPU that delivers it just that: Data. Address Bus are Read/Write lines that are used to transfer data.

Address Bus is also everyone else’s friend! The peripherals and cartridge are all on the address bus! Let’s dig a little bit deeper now.

Memory and Memory-Mapped I/O

Memory Mapped I/Os (MMIO) tend to share the memory space with the external memory. MMIO are just methods of connecting the CPU and the peripheries. Alt Text What you see above is the general memory map of GameBoy, that I took from here. They write in depth about GameBoy and I’ve used their article among others (linked below) to research for this article, shout out!

We will be looking specifically at ROM and Switchable ROM bank, which are the first two regions of the memory.

  0000-3FFF   16KB ROM Bank 00     (in cartridge, fixed at bank 00)
  4000-7FFF   16KB ROM Bank 01..NN (in cartridge, switchable bank number)
  8000-9FFF   8KB Video RAM (VRAM) (switchable bank 0-1 in CGB Mode)
  A000-BFFF   8KB External RAM     (in cartridge, switchable bank, if any)
  C000-CFFF   4KB Work RAM Bank 0 (WRAM)
  D000-DFFF   4KB Work RAM Bank 1 (WRAM)  (switchable bank 1-7 in CGB Mode)
  E000-FDFF   Same as C000-DDFF (ECHO)    (typically not used)
  FE00-FE9F   Sprite Attribute Table (OAM)
  FEA0-FEFF   Not Usable
  FF00-FF7F   I/O Ports
  FF80-FFFE   High RAM (HRAM)
  FFFF        Interrupt Enable Register

The memory you see at 0100-014F is the internal information area. It has the Nintendo Logo, from here the entry point is established, the boot procedure then jumps to the main cartridge program. Now there are other metadata codes and flags that we will skip right now.

Now that’s all about the CPU of the GameBoy. I dug a little into how cartridges work, but nothing too much in depth. One day when I understand the cartridge system, I’ll be back here!

To read more about display in GameBoy, refer to Rodrigo’s blogs here. A lot of the research for the article, was done by reading Raphael’s GameBoy building Series, which you can read here. Of course, with this I leave you with my other two favorite resources, Game Boy CPU Manual and Pan Doc’s Everything You Always Wanted To Know About GameBoy.

Credits for images: [1] http://meseec.ce.rit.edu/551-projects/spring2014/4-1.pdf
[2] https://www.quora.com/What-is-an-accumulator-in-computer-science
[3] GameBoy CPU Manual
[4] FreeCode Camp on Stacks
[5] Raphael’s Building GameBoy article