Introduction

Hello, and welcome to the Gameboy Software Development Kit documentation, GBSDK for short.

First off, if you need any help. Drop by our chat. There are various communication methods. See gbdev chat. There are many people in there that can help with any kind of problem.

Next up:

  • Summary: Explains the goals of the project, limitations and other important bits.
  • Required reading: Lists essential knowledge and reading to work with the Gameboy and the GBSDK

Summary

The goal of GBSDK is as following:

Provide an environment to allow C and Assembly programming for the Gameboy, with a low amount of abstraction.

Also note that this targets the following hardware:

  • DMG: Origonal gameboy (First version, known as the gray brick)
  • SGB: Super Gameboy (Running gameboy games on the Super Nintendo)
  • CGB: Gameboy Color (Adds color support and a few more minor features)

Note that the Gameboy Advanced is a very different device. And not part of the targets for GBSDK. The Gameboy Advanced has a Gameboy Compatibility mode, which is essentially a Gameboy Color (CGB). But full Gameboy Advanced development information can be found on gbadev]

To compare it with two other well known environments:

GBDK-2020

GBDK-2020 provides a C programming environment. It hides a few hardware details behind abstractions, and it provides high level functions for some parts, while low level for other parts. Which results in people not understanding what the hardware is doing and why things are not working as expected.

A simple example is printf() which GBDK-2020 provides. It allows writting text to the screen. But, the Gameboy does not have any text output, it has a tile based rendering. So this uses a large amount of available graphic tiles to provide this text drawing facility. It makes drawing text easy, but also adds multiple layers of hidden behavior.

Both GBDK-2020 and GBSK use sdcc as a C compiler. So the basic C support is the same, but the libraries and build systems are very different.

rgbds

rgbds is the nr1 used assembler for Gameboy programming. If you want to do assembly for the gameboy, then rgbds is your friend. And GBSDK uses rgbds as well!

However, stand alone it only provides the assembler and nothing more. No default project setup, no intergration with C, everything else you'll need to do yourself.

So, GBSDK

So, GBSDK stands a bit in the middle between rgbds and GBDK-2020. It does provide the facilities to program in C. But it does not provide high level abstractions, it only provides the facilities to access the hardware. It also integrates with rgbds as an assembler, instead of using the asxxxx assembler that sdcc uses by default.

Additional reading

To use GBSDK you best have a few other resources at hand.

  • Pandocs: The ultimate resource. Read this, memorize it. Read it again. Everything about how the gameboy hardware works is in here. And some things are essential to understand. Especially most of the rendering section (everything except the Pixel FIFO).
  • Some kind of C tutorial. If you don't know how to program in C yet, you better get some basic understanding of what functions, variables, parameters, globals, locals, etc are. (still need some recommendation for a good tutorial)

Setup

The following chapters will outline how to get started with GBSDK:

Installation

Windows

Download the latest release package from gbsdk-winenv and extract it somewhere.

Running the gbsdk-bash.exe will give you a commandline shell where you can do builds (all required tools are installed in this)

Alternatively, install WSL (if you have Windows 10 or 11) and follow the linux setup.

Linux

You'll need to install the following tools, everything can be newer then the specified versions, specified versions are minimal known working versions.

  • python 3.6
  • sdcc 4.2.0
  • rgbds 0.5.1

Assuming a debian based system, you'll need the following steps:

# Install package from the package manager
sudo apt-get install python3 build-essential bison libboost-dev libpng-dev flex texinfo pkg-config

# Get and build sdcc
wget https://sourceforge.net/projects/sdcc/files/sdcc/4.2.0/sdcc-src-4.2.0.tar.bz2/download -O sdcc-src.tar.bz2
tar -xjvf sdcc-src.tar.bz2
cd sdcc-4.2.0
./configure --disable-pic14-port  --disable-pic16-port
make -j$(nproc)
sudo make install
cd ..

# Get and build rgbds
wget https://github.com/gbdev/rgbds/releases/download/v0.5.1/rgbds-0.5.1.tar.gz -O rgbds-src.tar.gz
tar -xzvf rgbds-src.tar.gz
cd rgbds
make
sudo make install
cd ..

MacOS

Seriously. No clue, follow Linux installation mostly, I guess. Something something brew instead of apt-get?

New project

There are two ways to setup a new project:

  1. Use the template on github and directly create a new repository
  2. From scratch

Using the template

First, make sure you have a github account, and that you are logged in.

Next, select the Use this template button on the template page, and create a your own repository.

You can clone this with the github desktop application, or from the commandline (also in the gbsdk-windows-environment) with:

# Replace daid/gbsdk-template.git with your own repository
git clone https://github.com/daid/gbsdk-template.git --recursive

Be sure to add --recursive to get the gbsdk submodule!

This gives you a template project which is ready to be build. You're now ready to setup build configuration.

Set up a project from scratch

Your project will need 3 things:

  1. A Makefile
  2. gbsdk
  3. A directory for source files, and for asset files

Makefile

The Makefile is very bare bones, it just needs to define some project settings. So make a new empty text file with the following contents:

# Name of your project, will set the name of your ROM.
PROJECT_NAME := Project_Name
# Run "rgbfix --mbc-type help" for possible MBC types
MBC     := ROM
# Target should be a combination of DMG, CGB and SGB
TARGETS := DMG

include gbsdk/rules.mk

gbsdk

Next to the makefile, you need a directory named "gbsdk" with the gbsdk contents. You can get this as a git submodule, a git clone or downloading the zip from https://github.com/daid/gbsdk

Make sure the directory is named gbsdk (or that the makefile is adjusted to look at the right directory)

Source directory

Create two empty directories, one named src and one named assets. In the src directory create a main.c file with the following contents:

#include <sdk/hardware.h>

void main() {
}

This creates an bare minimum piece of code that compiles but does nothing.

Project configuration

Main project configuration is set in the Makefile in your project directory. It configures the following settings:

PROJECT_NAME

Sets the name of the resulting rom file. As well as the title stored in this rom (which some emulators show, but otherwise has no effect)

MBC

This defines which MBC is used for the rom. As well as which extra features this MBC should support.

For example, if you want a large rom with save games, you'll most likely need MBC := MBC5+RAM+BATTERY

TODO: There is no way to set SRAM size yet...

TARGETS

This defines which hardware the rom targets. It can be any combination of DMG, CGB and SGB.

For example: TARGETS := DMG CGB create a rom that targets both the DMG and CGB, and should be able to run on both, and enables color features on the CGB.

Note that not having a target enabled will not expose the relevant API functions. So if SGB is not in the TARGETS list, then for example the sgb_send() function will not be available.

Building & Running

Building your project

Building your project is the easest thing ever. Just run the command: make -j4

You'll first have to cd to the directory of your project. So, for example, on windows, if you have your project in your Documents. You'll need to open the gbsdk-bash.exe and run the following steps:

cd ~/Documents/MostAwesomeGameboyProjectEver
make -j4

With a bit of luck, you'll get a MostAwesomeGameboyProjectEver.gb file.

Running your rom

There are many ways to run your rom. All emulators listed here have very high emulation accuracy, meaning that if they run in the emulator, it's pretty much ensured that it will run on real hardware.

  • BGB is pretty much the goto emulator on Windows. It has debugging tools, but only for assembly.
  • Emulicious is another excellent choice. It has debugging tools. (TODO: Check if C level debugging works with the vscode extension)
  • SameBoy excellent emulator. But, debugging tools are only available on MacOS.
  • EverDrive-GB X7 while emulators are great. Nothing can replace testing on real hardware. The EverDrive flash carts are the top of the line carts. The X7 has all the features you would want, but is also the most expensive model. The X3 or X5 could be enough for your usage.
  • EZ-Flash Jr the budget flash cart. It has most of the same features as the EverDrive-GB X7, but is cheaper. However, it's power consumption is higher so batteries run dry quicker.

One important reason to run on real hardware is the screen. The screens of the gameboy are quite different (in a bad way) from modern LCDs, colors will look different, motion blur on the DMG is a real thing. While emulators have options to emulate this, it never really matches the real deal.

Note

In some cases, if you rename files, you might get an No rule to make target error. In this case first run make clean. This is an issue that still needs to be solved in GBSDK.

Stay away from VisualBoyAdvance this emulator is used a lot, but it is buggy and broken accuracy wise. There is a good chance that you make your rom bug free on this emulator and that it does not run on real hardware.

C API

The C API is divided into multiple sections. All the following sections go into the details on what functions are provided and how to use them.

Registers

By including the file sdk/hardware.h you will get access to all the registers mentioned in the Pan Docs. See the include file for all possible registers and bit definitions.

Each register is prefixed with an r, so LCDC becomes rLCDC. Registers that are CGB only will only be available of the CGB is enabled in the project configuration.

Examples:

#include <gbsdk/hardware.h>


void function() {
	//Enable the LCD with the background and the window enabled.
	// Use the memory at 0x9800 for the background tilemap, and at 0x9C00 for the window tilemap.
	rLCDC = LCDC_ON | LCDC_WINON | LCDC_WIN9C00 | LCDC_BGON;
	
	//Set a default background palette with all 4 colors.
	rBGP = 0b11100100;
	
	//Set the window start somewhere on the screen.
	rWX = 100;
	rWY = 100;
}

Video

TODO

LCD Control

Most of the LCD control features are handled by the registers directly, without any API abstraction.

  • rLCDC: LCD on/off and various feature bits.
  • rSTAT rLY rLYC: LCD runtime status and interrupt related.
  • rSCX rSCY: Background render offset.
  • rWX rWY: Window position.

The pandocs section on rendering explains all these registers really well.

There is one support function:

void lcd_off(void);

This turns off the LCD in a proper way. Disabling the LCD at the wrong time can damage DMG hardware and thus should be avoided. This function will ensure that it is done properly.

Note: It's usually bad form to turn of the LCD. Think very carefully what you are doing before you turn off the LCD. While it does enable faster copies to VRAM, the screen will turn white. This is noticable in Pokemon for example, where they fade to black, turn the screen off for a short while and then turn it back on. Causing a white flash.

Joypad

The joypad functionality is provided by sdk/joypad.h.

It provides the following features:

  • void joypad_update(void): function to update the joypad values. This should usually be called once a frame.
  • uint8_t joypad_state: variable that contains buttons held at the last joypad_update() call.
  • uint8_t joypad_pressed: variable that contains buttons that where pressed down at the last joypad_update() call but not at the joypad_update() call before that (newly pressed buttons)
  • PAD_DOWN PAD_UP PAD_LEFT PAD_RIGHT PAD_START PAD_SELECT PAD_B PAD_A: bit definitions for joypad_state and joypad_pressed

Example usage:

#include <sdk/joypad.h>
#include <sdk/hardware.h>

uint8_t value;

void function() {
	while(1) {
		// Update the joypad_state and joypad_pressed variables
		update_joypad();

		// Break out of the loop if start or select is pressed
		if (joypad_pressed & (PAD_START | PAD_SELECT))
			break;

		// If left is hold down, change some value
		if (joypad_state & PAD_LEFT)
			value = value - 1;

		//Assumes vblank interrupt is setup
		HALT();
	}
}

Banking

Banking is needed to fit more then 32KiB of ROM into a single Cartridge. The general process is as follows:

  • Data and code is contained in banks.
  • Data and code in bank0 is always available.
  • Only one other bank is active at the same time, meaning that code in one bank cannot access code/data in another.
  • It is possible to call code in another bank from a different bank, if setup correctly.

Banking is one of the those things that makes Gameboy Progamming more complex. You need to think about what code you put in bank0. And what can be placed in banks.

Banking with gbsdk (and sdcc) works per .c file. Each file can be assigned a bank. And all code/data of that will will then be placed inside that specific bank.

You can use:

#pragma bank 1 // Places this .c file in bank 1
#pragma bank auto // Places this .c file in a bank assigned by the compiler.

Note: Multiple .c files can be placed in the same bank, and the auto option can place multiple things in the same bank.

Calling functions in other banks

TODO