ASMSchool - Lesson 9
The universal first program isn't even safe from the GameBoy. Yes, this lesson is about
creating our first program that does something, and it's going to display "Hello, World!" Yes,
it might be a little bit cheesy, but this program will require some actual coding.... (oooohh scary!)
We're going to use the blank source template that I outlined in the last lesson as a base for
our Hello World program. First thing to do is open that file up and save it as HELLO.ASM. You
can use whichever text editor that you want, as long as it saves in plain text format. I'll be using
CGBIDE, since it has colored syntax highlighting.
Alright now that we have the source file open, lets do some good housekeeping and type in a
title for the program in the blank comment space at the beginning. Comments in RGBASM are
denoted with a semi-colon and every character after that on a line is considered a comment.
;This line is a comment.
I suggest typing something like "HELLO.ASM - Hello World Source Code" at the top of the
commented area. This way, when someone reads your source code later, they will know what
it is. This includes YOU too! There is nothing more frustrating than looking through tons and
tons of source files looking for a specific routine if you don't have something to distinguish
the contents of the file. (Of course, you COULD just use a text search to find keywords, but WHY?)
Now you can scroll down to the header area that contains the name of the cartridge. Just
change the text within the quotes to "HELLO WORLD" and remove the trailing zeros
on the same line, since the title should be 11 characters or less, and have extra zeros to make
it exactly 11 bytes long. And since "HELLO WORLD" is 11 bytes long, no extra zeros are
Pretty simple. The "DB" compiler directive just tells the compiler that the following data on the
line is to be treated as raw data. You can see quite a few examples of it in the header. I made a
big deal of making sure you edit the name because it would be awfully embarrasing to release
a game or a program, and have it's cart name be something like "BLANK ASM" or something
equally messed up.
Alright, now we have to change a few bytes that define the cartridge hardware, including cartridge
size, memory bank controller (MBC), whether or not we need any cartridge RAM, and if the target
machine will be DMG (monochrome GameBoy) or CGB (Color GameBoy). Since we are starting
out very simple, we will keep the target to the plain GameBoy. You'll find all of the correct
values for all of these in the GameBoy Crib Sheet, which you better have printed out by now...
hehehe. Otaku spent a good 15 minutes putting that together, you better show your appreciation!
(just kidding about the 15 minutes Otaku!)
We will be using the smallest possible cartridge size, which is 32K: the Home Bank and one
additional bank. We wont need to use the additional bank, but 32K is the normal minimum
cartridge size. And we will NOT need any cartridge RAM, since we aren't going to be saving
anything. Also, the memory bank controller (MBC) will be a plain MBC5, which is pretty simple
to use, and doesn't have any special problems. Also, since we wont be switching banks anyhow,
we could pretty much leave this one set to 0. So:
; $0143 (Color GameBoy compatibility code)
DB $00 ; $00 - DMG
; $80 - DMG/GBC
; $C0 - GBC Only cartridge
; $0144 (High-nibble of license code - normally $00 if $014B != $33)
; $0145 (Low-nibble of license code - normally $00 if $014B != $33)
; $0146 (GameBoy/Super GameBoy indicator)
DB $00 ; $00 - GameBoy
; $0147 (Cartridge type - all Color GameBoy cartridges are at least $19)
DB $00 ; $00 - ROM Only
; $0148 (ROM size)
DB $00 ; $00 - 256Kbit = 32Kbyte = 2 banks
; $0149 (RAM size)
DB $00 ; $00 - None
That should pretty much cover that part. If I've made any glaring mistakes, let me know. And uh...
any mistakes are intentional... yeah... that's it... sure... just to make sure you're paying
Anyhow, it's time to jump into the code. Scroll down to the Start label and remove the "JP START".
The very first thing we're going to do is DISABLE INTERRUPTS. This is done by the instruction
DI. Now let me clear something up: the DI instruction does NOT clear all of the bits of the IE
register to disable all of the interrupts. What it does is turns off a big "Interrupt Master Enable"
switch that disallows any interrupts from happening, even if we have their flags set in the IE
;* Program Start
SECTION "Program Start",HOME[$0150]
di ;disable interrupts
ld sp,$FFFE ;set the stack to $FFFE
call WAIT_VBLANK ;wait for v-blank
ld a,0 ;
ldh [rLCDC],a ;turn off LCD
call CLEAR_MAP ;clear the BG map
call LOAD_TILES ;load up our tiles
call LOAD_MAP ;load up our map
ld a,%11100100 ;load a normal palette
ldh [rBGP],a ;load the palette
ld a,%10010001 ; =$91
ldh [rLCDC],a ;turn on the LCD, BG, etc
Wow! That's a whole lot! (hint of sarcasm) But that is the main part of our program. Ok, here is a
quick run-down of this main part.
- First we disable interrupts
- Then we set our stack to the area of $FFFE
- Then we call a subroutine to wait until the LCD is in v-blank
- Next we load A with ZERO, and load that value into rLCDC which turns off the LCD
- Then we call a subroutine to clear the map
- And we call a subroutine to load our tiles
- Then we call a subroutine to load our tile map
- And then we set the palette to some normal values (black, gray, light gray, white)
- Next we load a value into A that turns on the LCD in the mode we want it, and load that value into rLCDC
- Now that the LCD is on, we can have an infinite loop
It seems like alot of work to do very little, but we are actually accomplishing alot in very
few bytes of real code.
Looking at the above code, I'm hoping it's simple enough for you to understand what
it's doing when you read it.
Ok, that's about it for this time. Sometime soon I will have to expand this lesson to contain the
subroutines in the main program loop I have illustrated above. They are pretty simple, no doubt,
I just haven't gotten to coding all the HTML. =P