Last weekend while digging around on one of my USB sticks, I found some old test code I wrote for the GBA over 10 years ago. I though the files were lost forever, so I was quite happy that I found them. The code itself was written in an obscure assembler for Windows, so my first goal was to port it to a more modern tool that preferably could cross assemble on both my PC and Mac. I decided to give the vasm a try. After some initial problems with strange syntax and me not understanding what the error messages meant, I got it to assemble into a binary file. To my surprise, the resulting binary could be loaded into the emulator and it worked the way it should! From there I cleaned up the code, removing stuff I didn’t need for the Hello World Project and added the result to the repository.
This is by far the shortest example to date. The video mode I chose made it very easy to draw graphics on screen, and the setup required is minimal. A short note before we continue; the semantics of the data types are not the same as on the 68k processor. On Arm, a word is 32-bit, while on the 68k it’s 16-bit. This can occasionally cause some confusion, at least it has for me when my focus was not high enough.
At the beginning we tell the assembler to use the arm instruction set (which is 32 bit, as opposed to the thumb instruction set that has 16 bit instructions). Then we tell it that the following code will be executed at position 0x08000000, which is where the GBA ROM entry point is.
The first instruction we run makes a jump (branch) over the ROM header. After the branch, we define the GBA header. I have no idea why the values in the header are what they are or if they are correct, but this is what my old code did, and the emulators I’ve tried haven’t complained yet.
.arm ; Use arm instruction set. ; header... .org 0x08000000 ; GBA ROM Address starts at 0x08000000 .section text b _start .space 0xf0,0x9c ; fill 0xf0 (240) bytes with 0x9c ; Game title starts at 0x080000a0, 12 chars .ascii "Hello World!" ; 12 chars ; game code follows, 4 chars. .ascii "1234" ; then two chars of makers id... .byte "GB" ; after that, i don't know. .space 0xba,0 ; Rest of header.. fill (186 bytes) with 0 _start:
Lets begin by setting the display mode. By setting Mode 4, we get 256 colour chunky graphics mode, i.e. each byte in the graphics memory corresponds to the color at that position in the palette. In Mode 4, only background 4 is used, so we need to enabled that background layer.
; Set display mode mov r4,#0x04000000 ; Display control register. mov r2,#4|0x400 ; Set mode 4 and enable background 2 str r2,[r4] ; store mode in display control register
Time to setup the palette. Since the graphics only consists of two colours, we read both colours from the palette data in one go and writes them to the palette memory. Each entry in the palette consists of two bytes, with packed RGB data, 5 bits per channel. The least significant bits are the red channel, the next 5 bits are green and finally 5 bits representing the blue channel. The most significant bit is ignored.
adr r0,palette ; address to palette data mov r1,#0x05000000 ; palette register address ldr r3,[r0] ; load colour data (32-bit = 2 colours) str r3,[r1] ; store in palette register
Time to update the screen with some pixels. Here we setup two nested loops, on for row and one for column. For each pixel on each row, a color entry is read from the pixel data and written to screen. To optimize a bit, we handle four pixels at a time, and also, it is not possible to write just one byte to the VRAM; doing so will result in the same value being written to the other byte in the other half of the 16-bit location.
adr r4,hello_data-4 ; use address 4 bytes before to use auto update later mov r3,#0x06000000 ; VRAM sub r3,r3,#4 ; subtract 4 to allow auto update work later mov r0,#6 ; 6 rows .row_loop: mov r1,#48/4 ; 48 bytes per row = 12 words .pixel_loop: ldr r2,[r4,#4]! str r2,[r3,#4]! subs r1,r1,#1 bne .pixel_loop add r3,r3,#240-48 subs r0,r0,#1 bne .row_loop
There is one thing in the loop above that might be hard to understand without further explanation. I’m thinking about the [r4,#4]! syntax. What is does is access the data pointed to by r4 + 4 bytes; the exclamation mark at the end indicates that the r4 register will be updated with the same offset that was used in the access. So, 4 will be added to r4 after the data access. r3 and r4 will therefore increase after each read/write, so the source and destination addresses will be updated for every iteration in the loop.
We have reached the end of the executable code and here we just enter an infinite loop by jumping to the same location forever.
stay_forever: b stay_forever
Now all code is done and we reach the data. First we have two entries of colour data; black and white. These are the values that are written to the palette register.
palette: .half 0x0000,0x7fff
And finally the graphics data. Same graphics as the other examples, except here we have indexed colour mode, so 0 means colour 0 in palette, and 1 means colour 1 in palette. Simple as that.
hello_data: .byte 0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1 .byte 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0 .byte 0,1,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,0,1,1,0,0,0,1 .byte 0,0,0,1,0,0,1,1,0,0,0,1,1,0,0,1,0,0,1,1,1,0,1,0 .byte 0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,0,1,0,0,1 .byte 0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0 .byte 0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,0,1,0,0,1 .byte 0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0 .byte 0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1 .byte 0,1,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0 .byte 0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,0,0,1,1,0,0,0,0 .byte 1,0,1,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1,1,0,1,0
That is it. I’m quite fond of the ARM assembly language, it’s quite readable compared to, oh say PowerPC assembler code.
There are many site on the internet dedicated to programming Gameboy and Gameboy Advance. Here are a few links that might be useful. Since the original version of my code was written over 10 years ago, I can’t give links to the resources I used initially, but I hope the links below fill your needs.