Text
Code: Helpful Libraries
Last time I lied, there's a bit more stuff before the tutorial. I thought I'd post some useful library files, because we'll be needing them soon.
◆ Memory Routines: filling a memory area with a common value, copying data from one memory location to another
◆ Hardware Defines: useful constants and hardware registers for Game Boy, Game Boy Color, and Super Game Boy hardware.
I'll explain these a little bit:
Memory Routines
Include this library in the code area of your ROM to get two useful memory routines: filling a memory area with a common value, copying data from one memory location to another.
In Wiz:
include 'memory.wiz'
In RGBDS:
INCLUDE "memory.z80"
Here's the documentation for these functions:
— memset — Fills a range in memory, starting at hl and spanning bc bytes, with a specified byte value a.
Arguments hl = destination address bc = byte count a = value
— memcpy — Copies bc bytes from the source at hl to the destination at de.
Arguments de = destination address hl = source address bc = byte count
Hardware Defines
Include this library anywhere to get a bunch of useful constants and hardware registers for the Game Boy, Game Boy Color, and Super Game Boy.
In Wiz:
include 'gameboy.wiz'
In RGBDS:
INCLUDE "gameboy.z80"
Please open the file in a text editor to see what constants are defined exactly, but here's a quick list of stuff it has constants for: ◆ Boot-header Constants ◆ LCD Controller - for configuring basic screen settings. ◆ LCD Status - for managing status interrupts and detecting current LCD state. ◆ LCD OAM DMA - for copying all sprites' Object Attribute Memory to the screen. ◆ RAM areas for tile memory, bg maps, object attribute memory, and wavetable for audio. ◆ Background Scroll Registers ◆ Scanline State and Interrupt Management ◆ Window Positioning ◆ GB Monochrome Palette ◆ GBC Color Palette ◆ GBC Bank Selection (for extra Video RAM and Work RAM banks) ◆ GBC Speed Settings ◆ GBC Infrared Communication ◆ GBC DMA Transfer ◆ Super Game Boy Packets ◆ Audio Settings ◆ Tone, Tone 2, Wave, and Noise ◆ Joypad ◆ Link Cable ◆ Timer ◆ Interrupt Configuration
It's recommended that you also read the "Pan Docs" for some relevant information: http://nocash.emubase.de/pandocs.htm -- These roughly correspond to the stuff mentioned in there.
Alternatively there's the GBDev wiki which contains a lot of similar info: http://gbdev.gg8.se/wiki/articles/Main_Page
Later!
If you want to check them out, you can download these libraries.
You can also view the source on Github.
Catch you later!
2 notes
·
View notes
Text
Tutorial: Making Art for the Game Boy
Last time, there was a tutorial on how to write an empty boilerplate Game Boy ROM. Before any useful progress can happen, we will really want to be able to display things on the Game Boy screen. You could make placeholder patterns in code, or by manually typing hex values, but that's a bit of work. It'd be way nicer to just be able to load up some real images!
A big problem with homebrew development is the lack of accessible tools. To help with this effort, I've made a few things available online. You can use them by just opening them in a modern web browser.
Go here to try out "Brew Tool", which is a collection of different tools I've made for homebrew stuff: http://make.vg/brewtool/
Out of all of those, there two tools of interest for making art:
◆ Map Tool - You tell it to open an image that adheres to the Game Boy Color restrictions, and it spits out a .chr tileset, a Game Boy Color palettes, and the map data for that image.
◆ CHR Tool - You tell it to open an image, and it tries its best to convert to a 4-color palette. You can adjust the which palette values it uses for each color being converted, and then you can save the final image as a .chr.
The code is open source and available to view, so anyone with some JavaScript knowledge can modify and make improvements. You can also make asks here or submit an issue on GitHub.
Anyway, let's dive into some stuff.
Map Tool
This tool is designed to be pretty simple to use. It will automatically extract tiles and palettes and map data from an image you give it, but it expects images that conform to the Game Boy Color background art limitations:
◆ Maximum of 4 colors per 8x8 area. ◆ 256 unique tiles max (doesn't use the GBC's extra tileset memory -- assumes that you might still want your art compatible with the original GB) ◆ 8 unique palettes (of 4 colors) max
Any image that doesn't follow these requirements is rejected and won't finish loading.
You can give Map Tool an image like this:
And it will spit out a tileset, like this:
and a palette that looks like this:
It does a pretty good job of looking at image, and extracting unique tile patterns and color palettes.
This auto-detection has some weird flaws, and sometimes creates redundant tiles (where the palette is different but pattern is the same) or palettes that may not be the same way an actual person might organize them. Buuuuuut, the important part, is that it extracts enough data from the original image to reassemble it later.
You can save a bunch of junk from here:
Tileset
◆ The raw GB tileset (.chr) can be used to embed the raw art in the ROM in a way the GB and GBC expects. ◆ The tileset image is just a png of the tileset you see. ◆ The combined tileset image is a png of all the tiles in the tileset, used against every palette combination.
Palettes
◆ The raw 15-bit palette (.pal) is a binary file containing the 15-bit RGB palette in a way the Game Boy Color understands. ◆ The attibute set is just an image that contains all the color palettes. Each palette additionally fits in an 8x8 pixel block (which is the size of an attribute tile on the GBC). Might be useful to someone.
Map
There are a bunch of different formats for the tile map: ◆ The tile map is a map using the 8x8 tiles in the tileset to make a background image. It's a CSV text file. ◆ The attribute map is a secondary map that decides which palettes to use for each tile, for the Game Boy Color. It's a CSV text file. ◆ The combined map uses the combined tileset image to make te original map, as a CSV text file. ◆ The combined tiled map uses the combined tileset image to make the original map. This is a .tmx map file, which you can open with Tiled. When you're done messing with the map, you can save it back to an image file! ◆ Binary tile map is the tile map in raw binary format, which you can load on the Game Boy. ◆ Binary attribute map is the attribute map in raw binary format (which decides which palette gets used where), which you can load on the Game Boy.
There's a lot of options here, but for getting a background we can store in the ROM, these are things we're interested in: raw GB tileset (.chr), raw 15-bit palette (.pal), binary tile map, and binary attribute map. Save your art somewhere handy.
CHR Tool
CHR Tool is a little more manual than Map Tool, you give it an image you want to convert into a tileset. It doesn't create maps for you, and it doesn't detect palettes, or cut out redundant tiles. You can also use this tool to preview a .chr file you've already made.
You give CHR Tool an image with a bunch of tiles, maybe something like this:
You can adjust the palette conversion by hand in case it messed something up by changing the numbers between 0 - 3 in the little boxes. Finally, you'll get something like this:
You can save this as a .chr now. This tool is capable of saving Game Boy and NES .chr files, and can also save the color-reduced tileset as a PNG.
Wrapping Up
◆ If you don't want to use this there are other tools, such as YY-CHR, and various commandline tools for converting images into files. Or you might consider using a hex editor if you're comfortable with that. I've also written a Python script that converts paletted PNG images into CHR files that requires Python 2.7 and PIL. None of these tools are quite as accessible though, so this is why I made web-based tools.
◆ These tools mainly spit out simple, raw, uncompressed binary formats. Depending on how much art your game uses down the road, there may need to be another step to add lossless compression to the data. RLE compression is pretty simple, but probably want something like dictionary compression too. Squish is a silly project I've made to that end: https://github.com/Bananattack/squish
◆ Feel free to contribute to make better tools! The homebrew community at large could use them!
Next time, we'll go over how to actually embed some artwork into a Game Boy ROM.
24 notes
·
View notes
Text
Tutorial: Making an Empty Game Boy ROM (in Wiz)
The Game Boy and Game Boy Color were very cool handhelds with lots of nifty games. Maybe at one point you've wondered "hmm, what was programming for the Game Boy like?" or you've wanted to make your own. Assembly is confusing and messy, but it's entirely possible to learn.
I plan to write a bunch of tutorials from the ground up, explaining how to use the Game Boy hardware to do different techniques. Before that, I should explain the bare minimum to get a ROM that "works", even if it does nothing yet.
If you don't understand everything here, don't worry, you don't have to right now. A lot of this can be copy-pasted verbatim and changed later, but I've taken time to break it down and explain different pieces.
This tutorial uses a high-level assembly language named Wiz, which is included with the download link at the bottom. Since it is a relatively new tool and still in development, there is another tutorial explaining the same stuff, but for the RGBDS assembler located here: http://assemblydigest.tumblr.com/post/77198211186/tutorial-making-an-empty-game-boy-rom-in-rgbds
Layout
First thing to do is to tell the assembler how its different memory banks are laid out. Make a text file, name it game.wiz (or game.txt or whatever you want really), then open it and put the following:
let K = 1024 bank rom: rom * 16 * K bank rom2: rom * 16 * K bank ram: ram * 4 * K bank ram2: ram * 4 * K bank hram: ram * 127
It will need to be changed more later, but the above settings are a good placeholder for a simple original Game Boy ROM with no special hardware.
A few things:
◆ rom and rom2 is the Read Only Memory on the cartridge that holds the program code and data. They're split into 16 KB banks.
Memory Bank Controller hardware allows cartridges to have more than 16K banks of ROM, by using a technique called Bank Switching. This technique allows selecting what bank of memory gets shown at 0x4000 .. 0x7FFF, but it won't be used yet.
◆ ram and ram2 is Random Access Memory used to read and write information that the code uses while it runs.
The Game Boy has 2 banks of 4 KB RAM. The Game Boy Color expands this and gives you 8 banks to work with, and you can bank-switch which 4K bank can be used at 0xD000 .. 0xDFFF.
◆ hram is a another chunk of systen RAM on the Game Boy, which is 127 bytes. It stands for High RAM, because it occupies 0xFF80 .. 0xFFFE - which is the "high" part of the Game Boy's 16-bit address space.
Some cartridges will have their own RAM on the cartridge, which can be used for a variety of things. It is sometimes possibly battery-backed to create save files.
These are really simple declarations so the assembler knows a bit about where to locate different pieces of code, data, and runtime variables in the ROM.
◆ This explains the Memory Map of the Game Boy in more detail: http://nocash.emubase.de/pandocs.htm#memorymap
Boot Header
Now that the assembler knows enough information, there is also the matter of giving some information to the Game Boy. The Game Boy will only run cartridges that pass the boot verification, and everything else will lock on the startup screen. To pass the boot procedure, there needs to be a Boot Header that adheres to a Game Boy format. The header also has enough information about the hardware the catridge uses, which can be used by emulators.
You can skim this and change the headers later.
The first section in the header is pretty boring, but can be used to store really small subroutines aligned to 8-byte boundaries, called RST Handlers. (There's a series of optimized instructions called rst (short for restart) which take less CPU cycles and use less bytes in the ROM to call.)
// RST handlers. in rom, 0x0000: return in rom, 0x0008: return in rom, 0x0010: return in rom, 0x0018: return in rom, 0x0020: return in rom, 0x0028: return in rom, 0x0030: return in rom, 0x0038: return
The next section is a series of Interrupt Handlers, for responding to different events that can be triggered by the Game Boy hardware. These are also aligned to 8-byte boundaries.
// Interrupt handlers. in rom, 0x0040: goto! draw in rom, 0x0048: goto! stat in rom, 0x0050: goto! timer in rom, 0x0058: goto! serial in rom, 0x0060: goto! joypad
There are few different interrupts:
◆ draw is a Vertical Blank ("v-blank") handler. It happens once every frame when the LCD screen has drawn the final scanline. During this short time it's safe to mess with the video hardware and there won't be interference. ◆ stat is a Status Interrupt handler. It is fired when certain conditions are met in the LCD Status register. Writing to the LCD Status Register, it's possible to configure which events trigger the Status interrupt. One use is to trigger Horizontal Blank ("h-blank") interrupts, which occur when there's a very small window of time between scanlines of the screen, to make a really tiny change to the video memory. ◆ timer is a Timer Interrupt handler. It is fired when the Game Boy's 8-bit timer wraps around from 255 to 0. The timer's update frequency is customizable. ◆ serial is a Serial Interrupt handler. It is triggered when the a serial link cable transfer has completed sending/receiving a byte of data. ◆ joypad is a Joypad Interrupt handler. Its primary purpose is to break the Game Boy from its low-power standby state, and isn't terribly useful for much else. ◆ The Interrupt Flag register can be used to determine which interrupt has happened. ◆ The Interrupt Enable register configures what events will triggered interrupts.
Then there is a small area with some free space which you can use for whatever you want, which is 152 bytes long. We ignore this for now.
Following that, there is an area that is 4 bytes in length that can hold code for the Startup Routine, which is executed directly after the cartridge passes the boot check.
// Startup handler. in rom, 0x0100: nop goto! main
Since this is tiny, pretty much all that fits is an instruction to jump somewhere else in the ROM.
Next, there is some binary data that defines the Nintendo logo. This data on the cartridge must match the exact logo in Game Boy's internal boot ROM, or the Game Boy boot procedure will lock up after the logo is displayed.
// The Nintendo Logo. in rom, 0x0104: byte * 48: 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E
Then there's the Title for the ROM, which is 11 characters in all caps. Any unusued bytes should be filled with 0. (Wiz will do this by repeating the last byte of "byte * N: ..." statement to pad the data.)
// The title, in upper-case letters, followed by zeroes. in rom, 0x0134: byte * 11: "TEST", 0
The Manufacturer Code is an uppercase 4 letter-string, but on older titles it's used for more letters in the game title. Lots of emulators will display this as part of the title, which is undesirable, so here it's just filled with 0 values.
// The manufacturer code. in rom, 0x013F: byte * 4: 0
The GBC Compatibility Flag decides whether the ROM is compatible with both the Game Boy Color and the original Game Boy, or if it was a GBC-exclusive. Monochrome games use it as another uppercase letter in the title. Saying the ROM is exclusive doesn't actually prevent the ROM from starting if it is run on an original Game Boy, but both compatible/exclusive settings have the effect of enabling extra features on the Game Boy Color.
// Gameboy Color compatibility flag. in rom, 0x0143: let GBC_UNSUPPORTED = 0x00 let GBC_COMPATIBLE = 0x80 let GBC_EXCLUSIVE = 0xC0 byte * 1: GBC_UNSUPPORTED
The Licensee Code is a two-character name in upper case. Which was used to indicate who developed/published the cartridge.
// "New" Licensee Code, a two character name. in rom, 0x0144: byte * 2: "OK"
The Super Game Boy compatibility flag indicates whether this ROM has extra features on the Super Game Boy. If set, then a ROM can utilize the Super Game Boy transfer transfer protocol to add things like border images, custom palettes, screen recoloring, sprites, sound effects, and sometimes even data that can be sent to SNES RAM and run on the SNES (both 65816 and SPC programs).
// Super Gameboy compatibility flag. in rom, 0x0146: let SGB_UNSUPPORTED = 0x00 let SGB_SUPPORTED = 0x03 byte * 1: SGB_UNSUPPORTED
The Cartridge Type determines what Memory Bank Controller the cartridge has, as well other additional hardware that the Game Boy can use: rumble, extra RAM, battery-backed saves, a real-time clock, etc. Some carts are pretty unique, like Tamagotchi and Game Boy Camera.
// Cartridge type. Either no ROM or MBC5 is recommended. in rom, 0x0147: let CART_ROM_ONLY = 0x00 let CART_MBC1 = 0x01 let CART_MBC1_RAM = 0x02 let CART_MBC1_RAM_BATTERY = 0x03 let CART_MBC2 = 0x05 let CART_MBC2_BATTERY = 0x06 let CART_ROM_RAM = 0x08 let CART_ROM_RAM_BATTERY = 0x09 let CART_MMM01 = 0x0B let CART_MMM01_RAM = 0x0C let CART_MMM01_RAM_BATTERY = 0x0D let CART_MBC3_TIMER_BATTERY = 0x0F let CART_MBC3_TIMER_RAM_BATTERY = 0x10 let CART_MBC3 = 0x11 let CART_MBC3_RAM = 0x12 let CART_MBC3_RAM_BATTERY = 0x13 let CART_MBC4 = 0x15 let CART_MBC4_RAM = 0x16 let CART_MBC4_RAM_BATTERY = 0x17 let CART_MBC5 = 0x19 let CART_MBC5_RAM = 0x1A let CART_MBC5_RAM_BATTERY = 0x1B let CART_MBC5_RUMBLE = 0x1C let CART_MBC5_RUMBLE_RAM = 0x1D let CART_MBC5_RUMBLE_RAM_BATTERY = 0x1E let CART_POCKET_CAMERA = 0xFC let CART_BANDAI_TAMA5 = 0xFD let CART_HUC3 = 0xFE let CART_HUC1_RAM_BATTERY = 0xFF byte * 1: CART_ROM_ONLY
The ROM Size determines how much read-only memory is available on the cartridge. The simplest has two 16 KB banks, and each setting is some multiple of 32 KB.
// Rom size. in rom, 0x0148: let ROM_32K = 0x00 let ROM_64K = 0x01 let ROM_128K = 0x02 let ROM_256K = 0x03 let ROM_512K = 0x04 let ROM_1024K = 0x05 let ROM_2048K = 0x06 let ROM_4096K = 0x07 let ROM_1152K = 0x52 let ROM_1280K = 0x53 let ROM_1536K = 0x54 byte * 1: ROM_32K
The RAM Size indicates how much random-access memory is on the cartridge. This is additional RAM on top of the RAM that GB / GBC provides, and it might be battery-backed to persist data as saves and so on. Apparently for the MBC2, you need to say it has "no RAM" even though the MBC2 actually does have its own RAM memory.
// Ram sizes. in rom, 0x0149: let RAM_NONE = 0x00 let RAM_2K = 0x01 let RAM_8K = 0x02 let RAM_32K = 0x03 byte * 1: RAM_NONE
Then finally some other stuff, that doesn't really need to be explained too much. The data located for the Header Checksum and Global Checksum is calculated by the assembler or an external patching tool, because it's too tedious to calculate by hand. Wiz does this as one of the final steps when writing a GB ROM. The Header Checksum needs to be correct or the cartridge won't pass the boot check
/// Destination code. in rom, 0x014A: let DEST_JAPAN = 0x00 let DEST_INTERNATIONAL = 0x01 byte * 1: DEST_INTERNATIONAL // Old licensee code. // 0x33 indicates new license code will be used. // 0x33 must be used for SGB games. in rom, 0x014B: byte * 1: 0x33 // ROM version number in rom, 0x014C: byte * 1: 0x00 // Header checksum. // Assembler needs to patch this. in rom, 0x014D: byte * 1: 0xFF // Global checksum. // Assembler needs to patch this. in rom, 0x014E: word * 1: 0xFACE
Whew, and we're done!
For more information, there are some resources:
◆ The Cartridge Header: http://nocash.emubase.de/pandocs.htm#thecartridgeheader
◆ Reverse engineering the Game Boy's internal boot code: http://gbdev.gg8.se/wiki/articles/Gameboy_Bootstrap_ROM
Loose Ends
After the boot header, there needs to a little bit more going on, so the program can actually compile.
in rom, 0x0150: func main do loop sleep end end task nothing do end let draw = nothing let stat = nothing let timer = nothing let serial = nothing let joypad = nothing
This creates a main function that just loops forever, sleeping periodically to use minimal battery life. This will also use placeholder interrupt handlers that do nothing, for now.
Putting it All Together
Finally, you need to run wiz to build the project: (change "game.wiz" for whatever name you give your input file, and "game.gb" for whatever name you want the ROM file to have)
wiz game.wiz -gb -o game.gb
It should spit out text similar to this:
* wiz: version 0.1 >> Building... >> Writing ROM... >> Wrote to 'game.gb'. * wiz: Done.
And there you go! If all went well, you should see game.gb, your very own Game Boy ROM. It does nothing useful yet, but it's now an empty template which boots up and can be used to make a game.
◆ You can download the code and assembler here.
◆ You can also view the code and this tutorial on Github!
◆ This download does not include a Game Boy emulator, but there are plenty available online.
◆ I really recommend BGB if you're on Windows, as it is probably the most accurate GB emulator and it contains many developer-friendly features.
◆ You can also buy cartrdiges like the Drag N Derp to test on real hardware.
Next Steps
In another part, there will be a tutorial to make a ROM that actually does more than just pass the boot check. Things like:
◆ How to make graphics for the Game Boy ◆ Tiles and the Background Layer ◆ The Window Layer ◆ Sprites ◆ Scrolling ◆ Game Boy Color hardware ◆ Scanline Effects ◆ Math ◆ Algorithms ◆ Bank Switching ◆ Neat Programming Tricks
Expect a new tutorial soon!
8 notes
·
View notes
Text
Tutorial: Making an Empty Game Boy ROM (in RGBDS)
The Game Boy and Game Boy Color were very cool handhelds with lots of nifty games. Maybe at one point you've wondered "hmm, what was programming for the Game Boy like?" or you've wanted to make your own. Assembly is confusing and messy, but it's entirely possible to learn.
I plan to write a bunch of tutorials from the ground up, explaining how to use the Game Boy hardware to do different techniques. Before that, I should explain the bare minimum to get a ROM that "works", even if it does nothing yet.
If you don't understand everything here, don't worry, you don't have to right now. A lot of this can be copy-pasted verbatim and changed later, but I've taken time to break it down and explain different pieces.
This tutorial uses Z80 assembly and an assembler named RGBDS, which is included with the download link at the bottom. There is another post explaining how to do the same stuff but using Wiz, a high-level assembly language instead: http://assemblydigest.tumblr.com/post/77203696711/tutorial-making-an-empty-game-boy-rom-in-wiz
Layout
First thing to do is to tell the assembler where to put the code. Make a text file, name it game.z80 (or game.txt or whatever you want really), then open it and put the following:
SECTION "rom", HOME
◆ This defines a section named rom located in the HOME bank (ROM bank 0).
◆ RGBDS sections are kind of ugly, but you can read a bit about them here: http://otakunozoku.com/RGBDSdocs/asm/section.htm
Boot Header
Now that the assembler knows enough information, there is also the matter of giving some information to the Game Boy. The Game Boy will only run cartridges that pass the boot verification, and everything else will lock on the startup screen. To pass the boot procedure, there needs to be a Boot Header that adheres to a Game Boy format. The header also has enough information about the hardware the catridge uses, which can be used by emulators.
You can skim this and change the headers later.
The first section in the header is pretty boring, but can be used to store really small subroutines aligned to 8-byte boundaries, called RST Handlers. (There's a series of optimized instructions called rst (short for restart) which take less CPU cycles and use less bytes in the ROM to call.)
; $0000 - $003F: RST handlers. ret REPT 7 nop ENDR ; $0008 ret REPT 7 nop ENDR ; $0010 ret REPT 7 nop ENDR ; $0018 ret REPT 7 nop ENDR ; $0020 ret REPT 7 nop ENDR ; $0028 ret REPT 7 nop ENDR ; $0030 ret REPT 7 nop ENDR ; $0038 ret REPT 7 nop ENDR
RGBDS requires you to pad areas manually, it has no "org" directive to skip ahead in the ROM, and you can't use the same SECTION with different addresses twice. So you need use the REPT (repeat) macro or DS (define storage) directive to pad bytes manually.
The next section is a series of Interrupt Handlers, for responding to different events that can be triggered by the Game Boy hardware. These are also aligned to 8-byte boundaries.
; $0040 - $0067: Interrupt handlers. jp draw REPT 5 nop ENDR ; $0048 jp stat REPT 5 nop ENDR ; $0050 jp timer REPT 5 nop ENDR ; $0058 jp serial REPT 5 nop ENDR ; $0060 jp joypad REPT 5 nop ENDR
There are few different interrupts:
◆ draw is a Vertical Blank ("v-blank") handler. It happens once every frame when the LCD screen has drawn the final scanline. During this short time it's safe to mess with the video hardware and there won't be interference. ◆ stat is a Status Interrupt handler. It is fired when certain conditions are met in the LCD Status register. Writing to the LCD Status Register, it's possible to configure which events trigger the Status interrupt. One use is to trigger Horizontal Blank ("h-blank") interrupts, which occur when there's a very small window of time between scanlines of the screen, to make a really tiny change to the video memory. ◆ timer is a Timer Interrupt handler. It is fired when the Game Boy's 8-bit timer wraps around from 255 to 0. The timer's update frequency is customizable. ◆ serial is a Serial Interrupt handler. It is triggered when the a serial link cable transfer has completed sending/receiving a byte of data. ◆ joypad is a Joypad Interrupt handler. Its primary purpose is to break the Game Boy from its low-power standby state, and isn't terribly useful for much else. ◆ The Interrupt Flag register can be used to determine which interrupt has happened. ◆ The Interrupt Enable register configures what events will triggered interrupts.
Then there is a small area with some free space which you can use for whatever you want, which is 152 bytes long. We ignore this for now.
; $0068 - $00FF: Free space. DS $98
Following that, there is an area that is 4 bytes in length that can hold code for the Startup Routine, which is executed directly after the cartridge passes the boot check.
; $0100 - $0103: Startup handler. nop jp main
Since this is tiny, pretty much all that fits is an instruction to jump somewhere else in the ROM.
Next, there is some binary data that defines the Nintendo logo. This data on the cartridge must match the exact logo in Game Boy's internal boot ROM, or the Game Boy boot procedure will lock up after the logo is displayed.
; $0104 - $0133: The Nintendo Logo. DB $CE, $ED, $66, $66, $CC, $0D, $00, $0B DB $03, $73, $00, $83, $00, $0C, $00, $0D DB $00, $08, $11, $1F, $88, $89, $00, $0E DB $DC, $CC, $6E, $E6, $DD, $DD, $D9, $99 DB $BB, $BB, $67, $63, $6E, $0E, $EC, $CC DB $DD, $DC, $99, $9F, $BB, $B9, $33, $3E
Then there's the Title for the ROM, which is 11 characters in all caps. Any unusued bytes should be filled with 0, which we do with the DS directive.
; $0134 - $013E: The title, in upper-case letters, followed by zeroes. DB "TEST" DS 7 ; padding
The Manufacturer Code is an uppercase 4 letter-string, but on older titles it's used for more letters in the game title. Lots of emulators will display this as part of the title, which is undesirable, so here it's just filled with 0 values.
; $013F - $0142: The manufacturer code. DS 4
The GBC Compatibility Flag decides whether the ROM is compatible with both the Game Boy Color and the original Game Boy, or if it was a GBC-exclusive. Monochrome games use it as another uppercase letter in the title. Saying the ROM is exclusive doesn't actually prevent the ROM from starting if it is run on an original Game Boy, but both compatible/exclusive settings have the effect of enabling extra features on the Game Boy Color.
; $0143: Gameboy Color compatibility flag. GBC_UNSUPPORTED EQU $00 GBC_COMPATIBLE EQU $80 GBC_EXCLUSIVE EQU $C0 DB GBC_UNSUPPORTED
The Licensee Code is a two-character name in upper case. Which was used to indicate who developed/published the cartridge.
; $0144 - $0145: "New" Licensee Code, a two character name. DB "OK"
The Super Game Boy compatibility flag indicates whether this ROM has extra features on the Super Game Boy. If set, then a ROM can utilize the Super Game Boy transfer transfer protocol to add things like border images, custom palettes, screen recoloring, sprites, sound effects, and sometimes even data that can be sent to SNES RAM and run on the SNES (both 65816 and SPC programs).
; $0146: Super Gameboy compatibility flag. SGB_UNSUPPORTED EQU $00 SGB_SUPPORTED EQU $03 DB SGB_UNSUPPORTED
The Cartridge Type determines what Memory Bank Controller the cartridge has, as well other additional hardware that the Game Boy can use: rumble, extra RAM, battery-backed saves, a real-time clock, etc. Some carts are pretty unique, like Tamagotchi and Game Boy Camera.
; $0147: Cartridge type. Either no ROM or MBC5 is recommended. CART_ROM_ONLY EQU $00 CART_MBC1 EQU $01 CART_MBC1_RAM EQU $02 CART_MBC1_RAM_BATTERY EQU $03 CART_MBC2 EQU $05 CART_MBC2_BATTERY EQU $06 CART_ROM_RAM EQU $08 CART_ROM_RAM_BATTERY EQU $09 CART_MMM01 EQU $0B CART_MMM01_RAM EQU $0C CART_MMM01_RAM_BATTERY EQU $0D CART_MBC3_TIMER_BATTERY EQU $0F CART_MBC3_TIMER_RAM_BATTERY EQU $10 CART_MBC3 EQU $11 CART_MBC3_RAM EQU $12 CART_MBC3_RAM_BATTERY EQU $13 CART_MBC4 EQU $15 CART_MBC4_RAM EQU $16 CART_MBC4_RAM_BATTERY EQU $17 CART_MBC5 EQU $19 CART_MBC5_RAM EQU $1A CART_MBC5_RAM_BATTERY EQU $1B CART_MBC5_RUMBLE EQU $1C CART_MBC5_RUMBLE_RAM EQU $1D CART_MBC5_RUMBLE_RAM_BATTERY EQU $1E CART_POCKET_CAMERA EQU $FC CART_BANDAI_TAMA5 EQU $FD CART_HUC3 EQU $FE CART_HUC1_RAM_BATTERY EQU $FF DB CART_ROM_ONLY
The ROM Size determines how much read-only memory is available on the cartridge. The simplest has two 16 KB banks, and each setting is some multiple of 32 KB.
; $0148: Rom size. ROM_32K EQU $00 ROM_64K EQU $01 ROM_128K EQU $02 ROM_256K EQU $03 ROM_512K EQU $04 ROM_1024K EQU $05 ROM_2048K EQU $06 ROM_4096K EQU $07 ROM_1152K EQU $52 ROM_1280K EQU $53 ROM_1536K EQU $54 DB ROM_32K
The RAM Size indicates how much random-access memory is on the cartridge. This is additional RAM on top of the RAM that GB / GBC provides, and it might be battery-backed to persist data as saves and so on. Apparently for the MBC2, you need to say it has "no RAM" even though the MBC2 actually does have its own RAM memory.
; $0149: Ram size. RAM_NONE EQU $00 RAM_2K EQU $01 RAM_8K EQU $02 RAM_32K EQU $03 DB RAM_NONE
Then finally some other stuff, that doesn't really need to be explained too much. The data located for the Header Checksum and Global Checksum is calculated by an external patching tool, because it's too tedious to calculate by hand. The Header Checksum needs to be correct or the cartridge won't pass the boot check. Running rgbfix will patch your ROM for you.
; $014A: Destination code. DEST_JAPAN EQU $00 DEST_INTERNATIONAL EQU $01 DB DEST_INTERNATIONAL ; $014B: Old licensee code. ; $33 indicates new license code will be used. ; $33 must be used for SGB games. DB $33 ; $014C: ROM version number DB $00 ; $014D: Header checksum. ; Assembler needs to patch this. DB $FF ; $014E- $014F: Global checksum. ; Assembler needs to patch this. DW $FACE
Whew, and we're done!
For more information, there are some resources:
◆ The Cartridge Header: http://nocash.emubase.de/pandocs.htm#thecartridgeheader
◆ Reverse engineering the Game Boy's internal boot code: http://gbdev.gg8.se/wiki/articles/Gameboy_Bootstrap_ROM
Loose Ends
After the boot header, there needs to a little bit more going on, so the program can actually compile.
; $0150: Code! main: .loop: halt jr .loop draw: stat: timer: serial: joypad: reti
This creates a main function that just loops forever, sleeping periodically to use minimal battery life. This will also use placeholder interrupt handlers that do nothing, for now.
Putting it All Together
Finally, you need to run a few different RGBDS tools to build the project:
rgbasm -ogame.obj game.z80 rgblink -mgame.map -ngame.sym -ogame.gb game.obj rgbfix -p0 -v game.gb
◆ "game.z80" is the name of your input file ◆ "game.map", "game.sym" and "game.obj" are build artifacts. ◆ "game.sym" can be used for debugging in BGB. ◆ "game.gb" is the name you want the resulting ROM file to have.
It should spit out text similar to this:
Output filename game.obj Assembling game.z80 Pass 1... Pass 2... Success! 244 lines in 0.00 seconds (4879999 lines/minute)
And there you go! If all went well, you should see game.gb, your very own Game Boy ROM. It does nothing useful yet, but it's now an empty template which boots up and can be used to make a game.
◆ You can download the code and assembler here.
◆ You can also view the code and this tutorial on Github!
◆ This download does not include a Game Boy emulator, but there are plenty available online.
◆ I really recommend BGB if you're on Windows, as it is probably the most accurate GB emulator and it contains many developer-friendly features.
◆ You can also buy cartrdiges like the Drag N Derp to test on real hardware.
Next Steps
In another part, there will be a tutorial to make a ROM that actually does more than just pass the boot check. Things like:
◆ How to make graphics for the Game Boy ◆ Tiles and the Background Layer ◆ The Window Layer ◆ Sprites ◆ Scrolling ◆ Game Boy Color hardware ◆ Scanline Effects ◆ Math ◆ Algorithms ◆ Bank Switching ◆ Neat Programming Tricks
Expect a new tutorial soon!
14 notes
·
View notes