slashbinbash.de / GameBoy Development

Resources on how to program the GameBoy are scarce, most of the information dates back to the late 90s, early 2000s, lots of links point to websites that don't exist anymore and many development tools are discontinued or outdated.

This post is meant for people who are interested in game development on the GameBoy and have some programming background but have never done anything directly on hardware and with assembler. Its purpose is to give you an idea of what lies ahead of you and push you in the right direction. One article is definitely not enough to explain everything you need to know so you will have to do some research on your own, but I will try to provide you with the necessary information and links.

First I will give you a quick introduction on how to get started with GameBoy development. Then I will talk about some of the basic concepts that you have to consider while programming. Finally I will provide you with some additional links.

Content
Getting Started
Development Environment
Concepts
Debugging
Resources

Getting Started

Michael Steil did The Ultimate Game Boy Talk in 2016 which is by far the best introduction to the GameBoy, and GameBoy development. Make sure to watch it.

Before you search for assembler tutorials it is essential that you familiarize yourself with the GameBoy hardware as good as possible. It is much more important to understand where data is stored and where you need to move it to, in order to achieve certain things, before you write your first line in assembler.

Probably the most important document is the original Pan Docs or "Everything You Always Wanted To Know About GAMEBOY - but were afraid to ask". There are three versions to my knowledge:

The original gives you a very good basis for understanding the GameBoy hardware. The John Harrison version is only a minor update to the original with references to GALP's gbhw.inc. The nocash version contains much more information on the processor, sound I/O and details specific to the GameBoy Color. It is more comprehensive but can also be overwhelming for newcomers, thus I suggest you start with the original. Try to familiarize yourself as good as possible with the GameBoy hardware before you start programming.

Duo's GameBoy ASMSchool will teach you the basic architecture and instructions of the GameBoy CPU (Sharp LR35902). If you have never programmed in assembler before, this is a good source to start.

ECE238Spr08 provides many tutorials, source code examples and libraries that will help you develop your own games. It also has a HelloWorld.asm example with detailed comments explaining every step of the program. There are other examples that teach you how to load sprites and read the pad and button input.

GameBoy CPU Manual tries to combine information from different sources and documents into one concise manual that you should definitely read.

Development Environment

To set up your development environment you will need a text editor, preferably with syntax highlighting. I happen to use Notepad++ with a custom syntax highlighting configuration that you can get here.

Since you will need to convert numbers from decimal to hexadecimal to binary you should find a calculator that can do this for you. If you are on Windows 7 you can set the calculator to "Programmer mode" which will let you type in hexadecimal and binary numbers. This way you can check what bits are set in memory by typing in the hex value.

Next you need an assembler and linker. The Rednex GameBoy Development System (RGBDS) seems to be the standard choice. You can download the original version at rift.dk or an updated version at otakunozoku.com. Check out the documentation for help.

Last but not least you need to get an emulator and debugger. I personally use BGB which has many helpful features like a visualized video RAM view and a dedicated I/O memory view.

Hello World!

I've compiled an archive that includes the original RGBDS binaries for Windows 95/98 from rift.dk, and the following files that were downloaded from ECE238Spr08/software and slightly modified to make for a clearer project structure:

assemble.bat Creates a GameBoy binary file from your source code
makelnk.bat Creates a link file for the assembly
inc\gbhw.inc Defines symbols for all hardware addresses
inc\ibmpc1.inc Creates tiles for all IBM ASCII characters in video RAM
src\hello-world.asm HelloWorld.asm example source code
src\memory.asm Provides very basic memory set/copy operations

Download Archive

To compile the source code execute assemble hello-world in the command-line. If successful, it will result in the following output:

c:\gameboy\project>assemble hello-world
assembling...
Output filename obj\hello-world.obj
Assembling src\hello-world.asm
Pass 1...
Pass 2...
Success! 3481 lines in 0.01 seconds (16066153 lines/minute)
linking...
fixing...
Validating header:
    Nintendo Character Area is OK
    ROM size byte is OK
    Cartridge type byte is OK
    Checksum changed from 0x0000 to 0xF932
    CompChecksum changed from 0x00 to 0xA7

After that you can find hello-world.gb in the obj-folder. Open BGB and load up the game to see if it is working. You should see the text "Hello World!" being displayed in the center of the screen.

Hello World! in BGB

Concepts

Now that you have everything set up lets talk about some of the programming concepts that you have to consider when developing. If you have already read the Pan Docs or any of the tutorials, most of the information below will sound familiar.

Memory

The first thing you have to realize is that you are working directly on memory that can be addressed, ranging from $0000 to $FFFF. The address space is separated into different areas that each serve a very specific purpose which also means that they will be interpreted differently by the hardware.

The ROM on the cartridge for example can be accessed in the range from $0000 to $7FFF. As soon as the GameBoy boots up it will execute everything that starts at $0100, which is the entry point of your program. That is basically the equivalent to the main()-method.

The GameBoy has a video RAM ($8000-$9FFF) that is meant for storing data that will be displayed on screen i.e. the 8x8 pixel images that will be used as tiles or sprites. Tiles are immovable images that are placed on an evenly spaced grid, whereas sprites can be moved freely to any position on the screen. Usually the background of your game will consist of tiles and the moving characters will be sprites. The memory also contains information on how the background is composed by referencing the images with a simple number. Keep in mind that the background is actually bigger (32x32 tiles) than the physical LCD screen (20x18 tiles). By moving the virtual screen around you can create the effect of scrolling backgrounds, which is used in many games.

Sprites work differently than tiles. Since you can position them freely on the screen you not only have to save a reference to the image that you want to display but also its position. This is done in the Object Attribute Memory (OAM) which ranges from $FE00 to $FE9F. You can only store 40 sprites at this location. When the LCD draws the background and sprites it will read these two memory locations and determine what to display, so if you write any other data to the video RAM the screen will most likely display random garbage.

There is also a chunk of memory that is only for communicating with the other devices ($FF00-$FF7F). If you want to turn on the LCD, move the virtual screen, change the color palette, check what buttons the player presses or operate the sound chip, you will have to change certain bits in this memory range. Knowing what bits to read and write will be essential for initializing and controlling the GameBoy hardware.

You can use the internal RAM ($C000-$DFFF) to store game related data, like how many lives your character has, what the player's score is, the game state, etc. It is very important to think about how you want to use this memory in advance, come up with data structures, figure out how much space they will require and where you want to locate them. Create a memory map that you can reference while you program and that tells you exactly what each memory range is used for.

Processor

All the data that you want to move from one memory location to another has to go through the processor (unless you use the DMA). This also gives you the opportunity to manipulate the data before you write it to the desired location. To achieve this, the processor itself has small data storages called registers. All the computations that the CPU does use these registers so the data they contain is not persistent. If you run out of registers during a calculation you can always use the stack as a storage. It is accessed quicker by the hardware than the internal RAM and is located between $FF80 and $FFFE, commonly referred to as the high RAM. The SP register, the stack-pointer, always points to the last piece of data you pushed onto the stack. If you need to store something for a longer period of time you should write it to the internal RAM.

For example if the character in your game has 5 lives you have to save this information in the internal RAM. When you initialize your game you can tell the processor to write the number 5 to the address $C000:

LD   A, 5         ;first load the number 5 into the register A
LD   [$C000], A   ;then load the contents of register A (5) to the internal RAM

You are basically initializing a variable like you would in any other language, except you have to tell the computer exactly where you want the value to be stored. If your character loses a life you need to load the number at $C000 into register A, decrease it by one and write it back to its original location:

LD   A, [$C000]   ;load the contents of the memory at $C000 to register A
DEC  A            ;decrease the number stored in register A by 1
LD   [$C000], A   ;write the value back to the original location

There are many ways of solving things in assembler depending on what situation you are in. If you really want to get your hands dirty you can start counting the clock cycles and size of instructions to optimize your code even more. Here is an alternative to the code above:

LD   HL, $C000    ;load memory location to the 16-bit HL register
DEC  [HL]         ;decrease the value at the memory location by 1

This will save you 3 cycles and 3 bytes, provided that your HL register is free for use.

So everything you do boils down to moving and processing data. The only difference is that you have to do it very explicitly and that the programming language or the operating system does not protect you from making mistakes that could erase critical data or write garbage to the memory that interfaces with the hardware.

Debugging

Aside from having to program in assembler you will spend most of your time debugging your code so a good debugger is very important. You can use a debugger to trace through your program and see what each operation does to the registers and memory. Even if it looks a little overwhelming at first you will learn where to look when in order to get the information you need.

BGB debugger

The top-left segment of the window is for tracing through your program. It will display the assembler code as well as the operation codes in hexadecimals. By pressing F3 the debugger will go from line to line and execute each individual operation. Use F7 if you want to jump into a CALL and F8 to jump out of it. You can set breakpoints by double clicking on the line that you want the debugger to stop at. Pressing F9 will run the program until it hits a breakpoint. You will also get a visual indication of how jump operations with conditions react, look for the '~' sign.

At the bottom-left you have your memory view. If you feel like your program is not reading or writing the correct data from or to memory you can press CTRL+G to go to a specific memory location and see what is going on while you are tracing. Sometimes you forget to initialize the memory that you want to use with 00 (or any other valid value) which can result in faulty reads, or you thought that you have written something to a certain memory location but the game is not reacting to the expected data. This is where you would look for it.

The top-right segment is the register view. It is very useful for when you are writing your own calculations but they are not doing what you expect them to do. Sometimes you are overwriting data in one register that you need later in the calculation or you are reading the wrong register by accident. Sometimes you want to see if a shift-operation is giving you the data you are looking for or if a call returns the correct value. This is the only way to find out. You can also check the CPU-flags at a glance in case you need to know what flags a certain operation sets.

The bottom-right segment is your stack. Bugs that come from using the PUSH and POP operations wrong can be difficult to track. This is where you would check what data the stack-pointer is pointing to.

What makes the BGB debugger great is that you additionally have a video RAM viewer, that gives you visual feedback of your background, tiles and sprites, and the I/O map, which tells you exactly how the GameBoy is configured at the moment. Without them you would have to go through the memory yourself and tediously pick out all the information that you need so this will definitely save you a lot of time.

Also check out the map file in the obj-folder that is created when assembling the GameBoy-binary. It gives you an overview of the general memory usage of what basically is the cartridge ROM, including label and function addresses. This will be a good indicator if everything was included correctly and where you can find specific functions in the debugger.

Resources

If you have any questions about GameBoy Development, visit the IRC channel #gbdev on EFNet.

Communities
GameBoy Dev'rs
Gameboy Development
Tutorials, source code, etc.
Duo's GameBoy ASMSchool Assembler basics on the GB-CPU
ECE238Spr08 Class Assembly programming class on the GB-CPU
GALP v1.0++ GameBoy Assembly Language Primer (updated by Peter Fidelman)
GameBoy Crib Sheet Hardware cheat sheet
GBsound.txt Sound System Guide by Jonathan Gevaryahu (01/2004)
BennVenn's Rev. Engin. Guide Reverse engineering GameBoy games
Pan Docs
GBspec.txt Original by kOOPa (03/1998)
pandocs.txt nocash updated version (10/2001)
gbspec.txt John Harrison updated version (03/2008)
Manuals
Z80 CPU User Manual
GameBoy Programming Manual Official programming manual
GameBoy CPU Manual Compilation of documents
Tools
RGBDS v1.10 GameBoy assembler and linker. Original version (03/1999)
RGBDS v1.11 Otaku No Soku updated version (08/1999)
RGBDS (multi-platform) Bentley's updated version
BGB Recommended GameBoy emulator and debugger
No$GMB GameBoy emulator and debugger by nocash
GBDK GameBoy Developers Kit