GBDoK (v1.2) (by Manfred Linzner (aka Pink/Abyss) and Jason (aka Icehawk) ) Table of Contents: 0. Introduction 0.1 Overview 0.2 History 1. Graphics 1.0 Important Notes 1.1 Background 1.2 Color Gameboy Support 1.3 Display 1.4 Display Modes 1.5 Sprites Window 1.6 Window 2. Miscellaneous 2.1 Interrupts 2.2 Joypad 3. Memory 3.1 Banks 3.2 How to include binary data-banks to your ROM image 4. Color Gameboy Programming Info 4.1 How to set your ROM to CGB-Mode 4.2 How to write real CGB comaptible Code 5. References 5.1 Webpages 5.2 IRC Channels 0.0 INTRODUCTION 0.1 Overview This document is mainly for upcoming (color)Gameboy coders who use Pascal Felberīs excellent GBDK package. A basic knowledge of the C programming language will greatly help you understand how to program for the gameboy using GBDK. GBDK has almost no documentation about itīs internal functions regarding graphics, interrupts and other important things. This document tries to give you an quick overview about all GBDK-functions and explains some ColorGameboy specific details. 0.2 History 13.05.99 Version 1.2 - Updated links. - Updated text version to by syncronized with the HTML version. - Added a few lines here and there due to personal experience. 13.05.99 Version 1.1 - Converted the whole document to HTML - Severall bug-fixes and additions 28.01.99 Version 1.00 - Added information about including binary files as additional ROM BANKS. - Fixed section 4.2 (ATTRIBUTES must be set first!) - Added alot of descriptions to the routines described. - A little bit of bug fixes and added routines. 22.01.99 Version 0.9 - Corrected some bugs - Added BANK-Switching info - Added history 12.01.99 Version 0.8 - First public release of GBDoK 1. Graphics 1.0 Important Notes The Gameboy Uses an LCD display with a resolution of 160x144. The supported sprites are 8x8 and 8x16. There is no way to use 32x32 sprites, so don't ask. The gameboy supports a max of 40 sprites with 10 on one horizontal axis at one time. Before writing any data to the videomem you have to disable the LCD-Display (display_off();). On a real gameboy you are not able to upload data to the videomem while the LCD is processing. Gameboy emulators may not suffer from this problem. If your programm needs to write to the videomem while displaying something you have to be in the Vertical-Blank.Itīs also possible to write data to the videomem while being in the Horizontal-Blank but this needs a special interrupt handling. Also have in mind that most emulaotrs will fill all RAM/ROM with zeros. A real gameboy wonīt do that. At the end of all programs, it is a good habit to fill at least the visible screen data to all 0s. All of the information provided is compiled from various sources and own experiences. This document is for educational purposes and īhomebrewī GB-development. GameBoy and CGB is copyrighted by Nintendo Co., LTD. 1.1 Background void hide_bkg(); // Disable background Calling hide_bkg(); turns all the background tiles off. The sprites are still visible. This command does not work with no$gmb. void show_bkg(); // Enable Background Calling show_bkg()/SHOW_BKG; turns all the background tiles. This is used to turn them on after using the hide_bkg(); * Note : On the Gameboy Color, the background tiles start automatically, however, on the gameboy and gameboy pocket, they initially start off, so call a SHOW_BKG; after you load your background data. void scroll_bkg(int x, int y); // Scroll background x/y >=0 <=255 void set_bkg_data(int first_tile, int nb_tiles, unsigned char *data); /* -128 <= first_tile <= 127 * -128 <= first_tile+nb_tiles <= 127 * nb_tiles >= 1 */ set_bkg_data is used to load the background tiles and palette information into memory. first_tile is the first tile that you want to load data into, usually 0. nb_tiles is the number of tiles you want to load into memory. *data is a pointer to the unsigned char that the tiles are stored in. void set_bkg_tiles(int x, int y, int w, int h, unsigned char *tilelist); /* 0 <= x <= 31 * 0 <= y <= 31 * 1 <= w <= 32-x * 1 <= h <= 32-y */ set_bkg_tiles puts the tile data onto the screen. You must load the tiles into memory using set_bkg_data first. x is the starting location in tiles (pixels / 8) to load the data into. y is the starting location in tiles (pixels / 8) to load the data into. w is the width of the data you want to load in tiles. h is the height in tiles of the data you want to put on the screen. *tilelist is a pointer to an unsigned char that has a tile map of what you want to be displayed. 1.2 Color Gameboy Support * Note: Before you can set the color attributes for a tile you have to switch to the 2nd video-memory bank (VBK_REG=1). The CGB can now address upto 512 tiles (by use of BIT 3 from the attribute byte) The attribute byte looks like this: BIT 0-2: Palettenumber (0-7) BIT 3 : Character Bank select BIT 5 : Flip Tile Horizontal BIT 6 : Flip Tile Vertical BIT 7 : Background Priority VBK_REG = 1; /* Use this before setting tile-attributes */ VBK_REG = 0; /* Use this before setting tile-offsets */ VBK_REG sets the Video Bank Register. When set to zero, it loads the tile data into the background. When set to one, it loads the palette data into the background. You're supposed to set the palette data before you set the tile data. void set_bkg_palette(UBYTE first_palette,UBYTE nb_palettes,UWORD *rgb_data); set_bkg_palette loads the palette data into memory so the gameboy color can access it. first_palette is the first palette to be loaded. nb_palettes is the number of palettes to load. *rgb_data is a pointer to where the palette data is located. * Note : Never forget to set all 8 palettes after another Itīs not safe to set individual palettes * Note/Plug : Jason's Colors.h has the most common colors predefined for use with gbdk projects. void set_sprite_palette(UBYTE first_palette,UBYTE nb_palettes,UWORD *rgb_data); set_sprite_palette loads the sprite palette into memory so the gameboy color can access it. first_palette is the first palette to be loaded. nb_palettes is the number of palettes to load. *rgb_data is a pointer to where the palette data is located. * Note : Never forget to set all 8 palettes after another Itīs not safe to set individual palettes * Note/Plug : Jason's Colors.h has the most common colors predefined for use with gbdk projects. /* GB type (GB, PGB, CGB) */ /* Read this byte to determine the type of Gameboy*/ extern UBYTE _cpu; #define DMG_TYPE 0x01 /* Original GB or Super GB */ #define MGB_TYPE 0xFF /* Pocket GB or Super GB 2 */ #define CGB_TYPE 0x11 /* Color GB */ So if you want to be backwards compatible to the normal gameboy use this: if(_cpu == 0x11) { color-related material } where 0x11 can also be replaced with CGB_TYPE. 1.3 Display void display_on(); display_on() turns the display on. void display_off(); display_off() turns the display off. 1.4 Display Modes void mode(int m); **mode defines** M_TEXT_OUT M_DRAWING M_TEXT_INOUT These modes are used for the GBDK built in libraries. M_TEXT_OUT allows puts and other text-oriented tools to be used. M_DRAWING allows GBDK's plot and other routines (such as directy.h downloadable from Jason's site) to be used. M_TEXT_INOUT allows for puts and gets to be used. 1.5 Sprites void show_sprites(); /* Enable Sprites */ show_sprites() displays sprites properly configured on the visible screen. * Note : Newer GBDK versions support SHOW_SPRITES; void hide_sprites(); /* Disable Sprites */ hide_sprites() makes all sprites not visible. void sprites8x8(); /* Set Spritesize to 8x8 */ Sets the sprites to be eight pixels wide by eight pixels tall. * Note : Newer GBDK versions support SPRITES_8x8; void sprites8x16(); /* Set Spritesize to 8x16 */ Sets the sprites to be eight pixels wide by sixteen pixels tall. * Note : Newer GBDK versions support SPRITES_8x16; void set_sprite_data(int first_tile, int nb_tiles, unsigned char *data); /* 0 <= first_tile <= 255 * 0 <= first_tile+nb_tiles <= 255 * nb_tiles >= 1 */ set_sprite_data loads data into the sprite ram area. By doing this, sprites are able to contain the patterns you have designed. first_tile is the first tile from the data to be loaded. nb_tiles is the number of tiles that you want to be loaded. *data is a pointer to an unsigned char that contains the tile data you want to be loaded. void set_sprite_tile(int nb, int tile); /* 0 <= nb <= 39 * 0 <= tile <= 255 */ set_sprite_tile configures sprites so that they can be visible by loading the sprite tile into the selected sprite. nb refers to which of the 40 visible sprites you would like to load data into. tile is an integer refering to which tile from the loaded data set in set_sprite_data you want to be accessed by the sprite. void set_sprite_prop(int nb, int prop); /* 0 <= nb <= 39 */ ** sprite propperties (use with set_sprite_prop) ** S_PALETTE S_FLIPX S_FLIPY S_PRIORITY set_sprite_prop sets properties for each sprite. S_PALETTE (gameboy color only) contains the palette information. S_FLIPX allows the x-axis to be flipped/mirrored. S_FLIPY allows the y-axis to be flipped/mirrored. S_PRIORITY contains data referring to if this tile should be on top of other tiles or not. void move_sprite(int nb, int x, int y); /* 0 <= nb <= 39 * 0 <= x <= 255 * 0 <= y <= 255 */ move_sprite moves the specified sprite to another x-y location. nb is the number of the sprite (0-39) that you would like to move. x is the new x-location for the sprite. y is the new y-location for the sprite. 1.6 Window void show_window(); show_window() displays the window. void hide_window(); hide_window() hides the window. void move_win(UBYTE x,UBYTE y); move_win(x,y) moves the window to another location. x is the new x location for the window. y is the new y location for the window. void scroll_win(BYTE x,BYTE y); /*Move Window relative to current position*/ scroll_win scrolls the window to another location. x is how many pixels horizontally you would like to scroll the window. y is how many pixels vertically you would like to scroll the window. 2. Miscellaneous 2.1 Interrupts Note: Use disable_interrupts() before setting new interrupts. void enable_interrupts(); enable_interrupts() sets the interrupts to active. Using this allows routines set for interrupts to be called. void disable_interrupts(); disable_interrupts() disables the interrupts. Many routines use disabled interrupts to perform their tasks. void add_VBL(int_handler h); While interrupts are disabled, add_VBL(h) allows routines to be run when the vblank interrupt flag is called. h is the routine to perform. void add_LCD(int_handler h); While interrupts are disabled, add_VBL(h) allows routines to be run when the lcd interrupt flag is called. h is the routine to perform. void add_TIM(int_handler h); While interrupts are disabled, add_VBL(h) allows routines to be run when the timer interrupt flag is called. h is the routine to perform. void add_SIO(int_handler h); While interrupts are disabled, add_VBL(h) allows routines to be run when the serial input/output interrupt flag is called. h is the routine to perform. void add_JOY(int_handler h); While interrupts are disabled, add_VBL(h) allows routines to be run when the joystick interrupt flag is called. h is the routine to perform. set_interrupts(UBYTE flags); Interrupt-Flags VBL_IFLAG LCD_IFLAG TIM_IFLAG SIO_IFLAG JOY_IFLAG set_interrupts(flags) specifies which interrupts to call. * Note : (Use "|" to combine them) * Mote : VBL_IFLAG should always be set. 2.2 Joypad **Joypad defines** J_START = Start button J_SELECT = Select button J_B = B J_A = A J_DOWN = Down arrow on joypad J_UP = Up arrow on joypad J_LEFT = Left arrow on joypad J_RIGHT = Right arrow on joypad int joypad(); joypad() returns a byte containing which buttons from the joypad defines are pressed int waitpad(int mask); waitpad(mask) stops executing the program until the button(s) specified in mask are pressed. void waitpadup(); waitpadup() stops executing the program until all buttons on the pad are released. example: int i,x,y; i = joypad(); if(i & J_START) pause(); if(i & J_UP) y--; if(i & J_DOWN) y++; if(i & J_LEFT) x--; if(i & J_RIGHT) x++; 3. Memory 3.1 Banks GBDK doesnīt supports Memory-BANKS automatically. You have to link them with the compiler. GBDK i.e. canīt split huge data into several roms. You have to handle the BANKS yourself with direct memory adressing. The best way of handling BANKs is to put all your program-code into BANK(0) and your data-code into BANK (1-31). Using the MBC1 memory bank controller ------------------------------------- #define SWITCH_ROM_MBC1(b) \*(unsigned char *)0x2000 = (b) SWITCH_ROM_MBC1(b) switches the current changable 16k ROM to the bank specified by b. #define SWITCH_RAM_MBC1(b) \*(unsigned char *)0x4000 = (b) SWITCH_RAM_MBC1(b) switches the RAM bank to the bank specified by b. #define ENABLE_RAM_MBC1 \*(unsigned char *)0x0000 = 0x0A ENABLE_RAM_MBC1 enables support for external ram. #define DISABLE_RAM_MBC1 \*(unsigned char *)0x0000 = 0x00 DISABLE_RAM_MBC1 disables support for external ram. Using the MBC5 memory bank controller ------------------------------------- Note! Using MBC5 and bankswitching seems to have a slight error in the code. #define SWITCH_ROM_MBC5(b) \*(unsigned char *)0x2000 = (b)&0xFF; \*(unsigned char *)0x3000 = (b)>>8 SWITCH_ROM_MBC5(b) switches the current changable 16k ROM to the bank specified by b. #define SWITCH_RAM_MBC5(b) \*(unsigned char *)0x4000 = (b) SWITCH_RAM_MBC5(b) switches the RAM bank to the bank specified by b. #define ENABLE_RAM_MBC5 \*(unsigned char *)0x0000 = 0x0A ENABLE_RAM_MBC1 enables support for external ram. #define DISABLE_RAM_MBC5 \*(unsigned char *)0x0000 = 0x00 DISABLE_RAM_MBC1 disables support for external ram. void hiramcpy(UBYTE dst,const void *src,UBYTE n); hiramcpy copies procedures from ROM to RAM. 3.2 How to include binary data-banks to your ROM image If you want to include binary code into your program you can use the following procedure. - Compile a standard 32KB ROM Image - Set BYTE 0x147 to 1 (ROM+MBC1) - Set BYTE 0x148 to your used romsize - Add your 16KB Binaryfile to that image (i.e. on MS-DOS systems simply use COPY /b main.gb + bank01.gb final.gb) 0 - 256Kbit = 32KByte = 2 banks 1 - 512Kbit = 64KByte = 4 banks 2 - 1Mbit = 128KByte = 8 banks 3 - 2Mbit = 256KByte = 16 banks 4 - 4Mbit = 512KByte = 32 banks 5 - 8Mbit = 1MByte = 64 banks 6 - 16Mbit = 2MByte = 128 banks 52 - 9Mbit = 1.1MByte = 72 banks 53 - 10Mbit = 1.2MByte = 80 banks 54 - 12Mbit = 1.5MByte = 96 banks - Finally use RGBFIX95 to pad your file and fix all the other stuff. For accessing this (extern) data from C you can use this method: UBYTE *data,externdata; data=(UBYTE*)0x4000; SWITCH_ROM_MBC1(2) // Switch to ROM Bank 2 externdata=*data; // Here you already access BANK 2 SWITCH_ROM_MBC1(1) // Switch back to ROM Bank 1 4. Color Gameboy Programming Info: 4.1 How to set your ROM to CGB-Mode - Write 0x80 to rombyte-offset 0x143 (=CGB mode) ( you can do this at link-time by setting this linkerswitch: Wl-yp0x143=0x80) Without setting this byte most emulators will treat your program wrong (and of course the real CGB too). 0xC0 is supposed to be used for GBC-only roms, however most emulators currently do not support, this, so you can use the if(_cpu == 0x11) to make sure the game runs in color-only mode. 4.2 How to write real CGB comaptible Code For being compatible to the real Gameboy you should use this order when coding: - Disable LCD, Disable Interrupts (see 1.3 and 2.1) - Identify if the Gameboy you are currently running on is a CGB (see 1.2) - Transfer color palettes (see 1.2) - Transfer VRAM (video-memory) (see 1.1) - Transfer attributes to Bank1 (see 1.1 and 1.2) - Transfer tilesoffsets to Bank0 (BF CHR Code Transfer) (see 1.1) - Enable LCD Display (see 1.3) - Go on with your normal code.... 5. References 5.1 Webpages Gameboy Developer's Kit Pascal Felber Needed to compile your C files. http://www.gbdev.org/GBDK/ SHINīEN Entertainment Manfred Linzner Makers of the GHX Soundengine (a commercial gameboy soundengine). Find GBDoK here. http://www.shinen.com/GBDoK/GBDoK.html Gameboy Development News Jason Daily updated site telling about the day's development. Also contains ASM and C examples, utilities and misc. shit. Find GBDoK here. http://www.gbdev.org/news/ Gameboy Mailing List The maintainer of this list is Kalle Pihlajasaari. Mailing list... don't e-mail with ROM requests or stuff answered on webpages/this doc. http://www.ip.co.za/people/kalle/gb/list.htm Gameboy Webring Genetic Fantasia List of several gameboy development webpages http://www.geneticfantasia.com/html/webring.html No$Gmb Martin Korth Best all-around gameboy emulator and debugger. Shareware, though. http://www.work.de/nocash DBOY BouKiChi Freeware Gameboy Color/SGB emulator based off of an early VGB. http://members.xoom.com/foo01/ Harry Mulder's Gameboy Development Harry Mulder Author of Gameboy Tile Deisgner and Gameboy Map Builder. http://www.casema.net/~hpmulder/ Gamelist's Mailing List Archive Gamelist Rarely updated archive of the mailing list. Visit here before mailing the list. http://www.geocities.com/SiliconValley/Platform/6906/ Bung Enterprises Bung Makers of flash carts and other goodies to test your gameboy programs on the GB/CGB. http://www.bung.com.hk/ IRC Channels #gbdev on EFNET Contains many serious gameboy developers with the occasional 31337 hax0r.