Hardware Contents First demo

2. Setting up a development environment

2.1. Devkit Introduction

There are several development kits available for GBA programming. Most of these contain tools for assembly and C/C++. There are a number of development kits based on the GNU compiler collection (GCC) for the ARM CPU. In order of appearance, these are DevKitAdvance (DKA), HAM and devkitARM (dkARM), all of which are freeware. In the last two years or so, devkitARM (dkARM) has replaced DevKit Advance (DKA) as the toolchain of choice. dkARM is smaller, faster and more up-to-date than DKA and will be the focus of this tutorial.

A different type of beast altogether is HAM. This not only has the toolset, but also a library of useful functions and macros called HAMlib. The IDE for HAM called VisualHAM is included in the package. Of course, there's also the official ARM Development Suite (ADS), but that's rather pricey. There is also a BASIC environment called DragonBASIC. Like all BASICs, it's a lot easier to get something up and running than with C, but also less powerful because it hides all the bit-fiddling. The core functions are all written in a special version of assembly called TIN, and so you can extend the language if you want.


Since I actually like all that low level stuff like bit-fiddling and pointer work my language of choice is C, so that's what this tutorial will use as well. All the techniques presented here can be used in any language, though, only the syntax changes.

2.2. Setting up your environment


2.2.1. devkitPro (DKP)

DKP structure
Fig 2.1: devkitPro dir tree.

There are a number of C/CPP toolchains available, mostly based on the Gnu Compiler Collection (GCC). The de-facto standard for GBA programming is devkitPro (DKP). DevkitPro is actually a more than just for GBA development; it also houses tools for PSP, GameCube and probably Wii in the future too. For GBA development, the specific toolchain is called devkitARM, but the names can be used interchangeably. DevkitArm can also be used for the NDS.

Installing DKP is easy: just download the latest installer from www.devkitpro.org and follow the wizard. The essential tools of DKP are:

The full installation of DKP also comes with a number of other items that, while not essential, are worth having as well.

Most of the options of the installer make sense, so installing shouldn't be too hard. If you do run into trouble at this stage, you can also setup the whole thing manually by downloading each separate component from the devkitPro SourceForge page ( http://prdownloads.sourceforge.net/devkitpro/) and installing the pieces yourself.


Using devkitPro

And now for the hard part. Well, at least for us Windows-types who are used to a GUI doing all the actual work for us. GCC (and thus DKP too) uses a command-line interface, so instead of dialog boxes and mouse-clicks, you're working with shell commands (with documentation if you're lucky) and a good deal of typing.

Relax, it's not that difficult; you just have to pay a little more attention, that's all. When dealing with command-line tools, there are three things to consider: the name of the tool you want to use, the command-line arguments that it can work with, and the concept of paths. The first two are usually covered by a manual or a tutorial; also, if you know the name you can often find out what kind of arguments it wants by using ‘tool-name --help’. The path of a tool is the full name of a file, including all the directories. The environment needs to know the exact location of the tool, not just the basename. There are many ways of doing this, depending on OS and development environment, so I can't really go into detail about that now. I will give an easy, universal way of dealing with this point before the chapter is done though.

Setting the path

This seems one of the major obstacles of getting things running. The DKP installation sets a few thing up itself and if you're running DKP Sanctioned Makefiles (™, ®, etc) there should be no trouble. However, there is still a lot of non-DKP makefiles and batchfiles out there (including Tonc), so you will have to know a little bit about this. Here are a few ways of setting the path.

As a minimum example of what you'd need to do to get things done in a command-line environment, the following is what you'd have to do to turn the first demo first.c into a working GBA binary. Note, some of these instructions will be Windows specific, but should have comparable commands in your own operating system.

First, open up a command-line environment (Start Menu, Run, type cmd). Then browse through to [TONCDIR]\code\basic\first. Once there, you can compile and link your stuff by entering the following.

@ add path manually; not required if you've set it globally
@ modify for your own dir-structure, of course
PATH= e:\dev\devkitPro\msys\bin;e:\dev\devkitPro\devkitARM\bin;

arm-eabi-gcc -mthumb-interwork -c first.c
arm-eabi-gcc -specs=gba_mb.specs -mthumb-interwork first.o -o first.mb.elf
arm-eabi-objcopy -O binary first.mb.elf first.mb.gba
gbafix first.mb.gba

The first line is how I'd set the path on my system, but I'm absolutely certain it'll be done differently on your system. The rest will be the same for everyone. Fig 2.2 shows exactly what I did in the DOS box, and here's what each line does.

  1. Set the path. First, you have to set the path so that the MSYS and devkitARM tools are visible, which are in their respective ‘bin’ directories.
      e:\dev\devkitPro\msys\bin
      e:\dev\devkitPro\devkitARM\bin
    Actually, the MSYS directory isn't even necessary here, but will be required later so I added it anyway. Setting the path here is only necessary if you hadn't done it elsewhere, like in autoexec.bat or the system variables.
  2. Compile the source. The second step is compiling. I have a file called first.c that contains a simple GBA program. I'll show you the contents later, since that's not important right now. This step uses the arm-eabi-gcc compiler to compile the C file (.c) to an object file (.o). The prefix is usually specific to the toolchain, and will avoid confusion with other GCC variants. By the way, if you are programming in C++ instead of C you're probably better off with g++, not gcc.
  3. Link. This links all the objects into one executable ELF file. You can actually compile and link at the same time, but it is good practice that you keep them separate: serious projects usually contain multiple files and you don't want to have to wait for the whole world to recompile when you only changed one. This becomes even more important when you start adding data (graphics, music, etc).
  4. Translate to binary. The ELF file still contains debug data and can't actually be read by the GBA (though most emulators will accept it). arm-eabi-objcopy strips the debug data and makes sure the GBA will accept it. Well, almost.
  5. Validate header. Each GBA game has a header with a checksum to make sure it's a valid GBA binary. Normally, compilation doesn't supply one, so we have to use a tool like DarkFader's gbafix to fix the header. This tool comes with DKP, so you don't have to download it separately.

The tools names hare are arm-eabi-gcc, arm-eabi-objcopy and gbafix, which are made visible by adding devkitARM's bin directory to the path. Things like -c, -o are option flags specific to each tool. For example, it's the -c option that tells the compiler to only compile the source and not create a final executable, and -mthumb-interwork tells the compiler to allow for both ARM and THUMB code in the binary, which is a good thing.

How do you know which ones you need? By looking in the manuals. Or by browsing other peoples stuff. I've collected a few of the more common flags here.

Using dkARM via a DOS-box Fig 2.2: Using devkitARM via a DOS-box

Prefer devkitPro over DevKit Advance
A lot of older tutorials and homebrew source are set up to use DevKit Advance. This toolchain was useful in its day, but those days have long since past. If you're still using DKA, I must insist that you make the change to devkitPro.
Essential devkitPro flags

The flags -mthumb-interwork and -specs=XX in the compilation and linking steps are required for dkARM. Use XX=gba_mb.specs for multiboot code and XX=gba.specs for a normal ROM-based code. (Don't worry if you don't know what that means right now; just use them as the example does.)

devkitARM r19 incompatibilities

As of revision r19, dkARM uses the newer ‘eabi’ platform, which is different from and in fact incompatible with the previous ‘elf’ platform. If you're completely new this shouldn't be a problem, but for if you're updating from previous version there are a few things you should know.

I'm sure these issues will be resolved in the future, but if you want to stick with r18 for now, all you have to do is change the prefix back to ‘arm-elf’.

Cart vs multiboot builds

There are two different kinds of gba builds: ‘cart’ builds and ‘multiboot’ builds. A cart build puts the main code and data in the 32MB ROM (0800:0000h) of a cart. A multiboot build puts that stuff in the 256kB EWRAM (0200:0000). Commercial games are obviously cart builds, but make use of multiboot builds to make single-cart multiplayer possible.

Other than the maximum size, there is little difference in gameplay between both. For homebrew, multiboot does have one advantage, namely that you can load a game up to hardware without the need of an expensive flashcart; you can build your own PC-GBA cable for peanuts. For this reason, all the demos here are set for multiboot builds.


To make the distinction between cart and multiboot binaries clear, they are sometimes different extensions. Cart builds generally use plain 'ol ‘.gba’. Multiboot builds often use ‘.mb’, ‘.mb.gba’ or ‘_mb.gba’.


Better building through automization: batch-files and makefiles

Right, now that you've seen the basic steps of working with devkitARM via a DOS-box (fig 2.2), let's never do anything like this again. If you're prone to typos (and let's face it, who isn't) or just lazy, you're going to loathe having to type this every time you want to compile your code. There are two ways of making life easier in this respect, the first is to put the commands in a batch (.BAT) file and run that. There is a first.bat in the directory of the first demo that you can just execute and it'll run the commands in the batch-file automatically. No more tedious typing, hoozah!

Well, that's actually only half true. You still need to add the build steps to the batch-file yourself, which is alright at first, but for bigger projects it will become a major hassle. A second point against batchfiles is that they're pretty dumb. Unless you want to comment out specific commands, it'll rebuild every file in the project, which becomes annoyingly time-consuming for bigger projects. And there are other similar disadvantages of batch-files that I won't go into here. Instead, we'll use a third option: makefiles.


Makefiles are a lot like batch-files, only more advanced. For one thing, they check whether or not files need compiling or assembling by themselves. They can also make complex use of variables and have extensive string manipulation and wildcard capabilities that make them much more versatile than batch-files. The problem is getting to grips with their syntax. This isn't quite the time yet for a full exposition, but I'll show you the makefile equivalent of the commands given above in the next section.

Learn to use makefiles

While it is true that batchfiles are easier to set up, in the end using makefiles is just so much better. Take a little effort to learn the makefile syntax; it's well worth it.

2.2.2. HAM and Visual HAM

For the record I know very little about HAM; I use dkARM in combination with the Visual C++ IDE. I will tell you what I do know, but I can't guarantee it's 100% accurate.
HAM is a full-fledged GBA development environment that can take care of a lot of the low level stuff like sprite and map loading, special effects, timers and all that stuff. It also contains a 3rd party sound/music library called Krawall and a full IDE with all the important editing tools. And, of course, a truckload of demos.

Setting up HAM is easy: simply download the freeware version from www.ngine.de and install. And then install again because it's only the installer that you've just installed :P. After the second install everything will be ready, but you'll actually have two copies of each, one of them can safely be removed. Oh, and make sure that the path doesn't have spaces in it, HAM doesn't like that (and you shouldn't either).

After that you should be ready to roll. I say ‘should’ because if you're moving from DKA to HAM you may encounter a small problem building the demos. HAM needs a file called "cygwin1.dll" to run. The DKA r4 self-extractor from the PERN project copies a file of that name into the Windows System folder, which is an older version than HAM expects. If this is the case then building stops even before it really begins. Of course if you've read HAM's faq you already know all about that. In any case, this was the only problem I had when getting HAM working.

Underneath HAM it's still GCC, by the way, meaning that normal GBA code can be ported between devkitARM and HAM's toolchain without too much fuss. HAM also uses the makefile system (a very fine makefile system I might add), but all that stuff will be hidden from sight by the IDE. As you add or remove files from the Visual HAM workspaces (.VHW) it'll update the list accordingly (FYI, the file information is stored in VHO files).

HAM vs HEL

VisualHAM's creator, Peter Schraut has also written an add-on library called HEL. Unlike HAM, some time has been spent on optimizing HEL's code, or at the very least to make it not slow. If you're using HAM, consider using HEL as well.


2.2.3. DragonBASIC

If C and assembly give you the creeps, you can try the more user-friendly DragonBASIC. If you don't know assembly or C yet, but want to do some GBA programming, you might want to give this a try, because C and assembly aren't exactly the easiest languages to learn. But even if you do, DragonBASIC can be interesting because it is simply the fastest way of getting test-cases up and running.

Although I mainly work in C I know that DragonBASIC is very easy to use. All the core functions are browsable and if you can't figure it out from that there's always the tutorials and there are both online and offline help-files. One area where DragonBASIC is very different from using C is in that it can use bitmaps like BMP and PCX directly, without the need of a converter. This is both a blessing and a curse, it's a blessing because it'll allow you to get something up and running in no-time, but you need to be sure that (a) your bitmap is in the right bitdepth and (b) your bitmap editor can create BMPs and PCXs that leave the palette intact (MS-Paint doesn't, for example). This is a problem with C as well, of course, but at least you can look at the converted C-file and read the bit-depth from it.

2.3. GNU Makefiles

There are many ways to get your code compiled. The first would be to type in all the commands manually …

with the usual long list of compiler flags …

per file …

without typos …

for every time you want to build the project.

Yah, I didn't think so either.


Entering the commands manually is, not to put a finer point on it, batshit insane. Fortunately, there are a number of ways to automate the whole build process. The first would be to use a batch-file, which is essentially a file with the relevant commands in them, which when invoked will run all the commands automatically. Sounds good, huh? Well yeah, it may be better than doing everything manually, and it may work well enough for very small projects, but for anything bigger batchfiles are just too messy, difficult to maintain and slow.

A more professional approach is makefiles, which is what we'll be using here. Like batchfiles, makefiles contain the commands to build the project, but they are a lot more structured which is essential for anything bigger than a trivial test project.

For example, with makefiles you can create variables for commonly used items, which makes it easier to maintain. The commands are organised in rules, which has a nice benefit that you can have one rule for types of files. The rules also check whether a file is out of date, so you don't have to wait for each and every file in your project if you've changed just one of them. You also have a large number of pattern substitution techniques at your disposal which can help you automate your work. Lastly, makefiles are platform-independent, which is always a good thing.


2.3.1. A minimal makefile

The Tonc makefile project is pretty complicated and contains multiple makefiles, controlled by the master makefile tonc.mak. To keep things simple, I'll only show the makefile for the first demo called makefile.mak.


makefile.mak contains the basic commands that you'd need to build first.c into first.gba. Mind you, it is a very minimal makefile, intended to give you a brief look into the syntax of a makefile, not anything you'd want to use for a larger project.

#
# Makefile
#
# a minimal makefile (and I do mean minimal, look to the others
# for real-life use)

PATH   := $(DEVKITARM)/bin:$(PATH)

PROJ   = first
CC     = arm-eabi-gcc
OBJCOPY= arm-eabi-objcopy

.PHONY : build clean

build : 
	$(CC) -mthumb-interwork -c $(PROJ).c
	$(CC) -specs=gba_mb.specs -mthumb-interwork $(PROJ).o -o $(PROJ).mb.elf
	$(OBJCOPY) -v -O binary $(PROJ).mb.elf $(PROJ).mb.gba
	gbafix $(PROJ).mb.gba

clean : 
	@rm -fv $(PROJ).o
	@rm -fv $(PROJ).mb.gba
	@rm -fv $(PROJ).mb.elf

The most common elements of makefiles are comments, variables, rules and commands. As you may have guessed, '#' indicates a comment. A variable is something like

XX= yy

and works very much like a C macro: whenever make encounters $(XX) it will substitute yy in its place. Oh, the parentheses are required, otherwise make will think you mean ($X)X, which would be bad. Examples here are PROJ, CC and OBJCOPY. If by any chance you're wondering whether I should have used another variable for the prefix used in these last two, the answer is yes. Good call, by the way; keep it up. The PATH ‘variable’ here refers to the global path; because the devkitPro installer creates a system variable for the devkitARM directory, we can use it to add its bin directory so that the compiler tools will be recognized. If already modified the system path, this line isn't necessary. If you're using another toolchain, the line wouldn't work; but as I said, DKP is the recommended toolchain anyway.


The lines with colons

target : prerequisite
    command

indicate rules. The things you want built, the targets, are on the left-hand side of the colon; the things needed for that, prerequisites, are on the right. On the following line(s) are the commands, preceded with a tab. Yes, I do mean an actual tab. By default, the first rule that make encounters starts the make-chain. If a prerequisite is out of date, it'll run the command. Note that prerequisites can be targets themselves, though this file doesn't illustrate that. This file has two independent rules, one for build and one for clean, which will remove all the output. You can run this rule by adding it to the command-line options when you invoke make, more on that later.


Tabs, not spaces, before make commands

NOTE: GNU's make requires tabs before actual commands, not spaces. If you copy-paste, you may have to place the tabs manually.

One thing I haven't told you yet is what ".PHONY" means. This is a an example of a directive. Normally the targets of the rules are file-names. The commands are only run when the target doesn't exist or is older than its prerequisites. Since none of the commands of, say, build actually creates a file called "build", the file shouldn't ever exist and commands would always be executed. But what happens when it does exist? Well, since the rule doesn't have prerequisites the file is always up to date and the commands never run. To counter this, you tell make that the file is a PHONY.


And that's basically what a makefile looks like. Again, this isn't a very advanced makefile; it's just one step above your garden variety batch file (which is why the lines after the ‘build’ rule should be so familiar) and hardly uses any of the things that make makefiles so useful. In a proper makefile you will want to separate the compile and link steps and make files of file variables that contain lists of file names and stuff like that. If you want to know more about how that works, you can read more on makefiles and common compiler flags in this appendix.


2.3.2. Running makefiles

Invoking from the command line

Of course, having a makefile means nothing unless you know how to run it. Makefiles are executed by a tool called make, which comes with the msys installation (and also HAM). To run it, you do something like this:

make -f filename target

The -f flag says which makefile to run (in our case makefile.mak. The flagless option target denotes the main rule for the make process, which in this case can be either build or clean.

Make also has a number of interesting default options. For example, if you don't give a target, it'll just run the first rule in the file, in this case 'build'.

Also if you do not specify a filename for the makefile, it'll look for either 'GNUmakefile', 'Makefile' or 'makefile' and run that. Conversely, your makefile is named like this, you won't have to specify the file to run make on. This simplifies the make process, because you don't have to remember what file to call, you just call make by itself in a certain directory and it'll do what's necessary. This is actually the standard procedure for makefiles; but may be a little annoying if you're used to double-clicking to open a file; extensionless files can't be opened like that. There are ways around that, though: you could have the rules in a .mak and let Makefile include that, or you can use some Regedit-fu to open extensionless with your editor of choice (look here for an example of that).

Of course, make has plenty more options, but this is not the time. Just RTFM is you want more info.


Invoking from not the command line

Running make from the command line is the most obvious way of doing it, but it's probably not the most convenient way. Most non-trivial text editors and all IDE's will have ways of running shell commands; you could even make a batchfile to call make for all I care.

DevkitPro comes with one of those non-trivial editors (Programmer's Notepad), and it is capable of running external commands. Even better, it already has the commands make and make clean! The short-keys for these are Alt+1 and Alt+2, respectively. Note that these only work for the default makefile names, so something with an extension is right out.

To get IDEs and other editors to run make usually takes a little more doing. Because there are so many of these, setting them up will not be covered here; google or use the help files to figure out what needs to be done for your editor. I have examples for setting up conTEXT, an alternative for PN, and MS Visual Studio (5 and 6) in this appendix. The DKP site also has a few examples in the FAQ


2.3.3. Building Tonc projects

As said, I control the Tonc projects via a master makefile called tonc.mak. This has a number of rules through which one can build or clean any or all of the sub-projects, as well as create the tonc library libtonc.a that's used in the later projects. In the main tonc-code directory there's also a dummy makefile called ‘Makefile’, which relieves you of the terrible burden of having to type the 11 characters of ‘-f tonc.mak’. And also reduces the chance of typos, so it's actually not such a bad idea (why not use that file as a master makefile? Because you can't open an extensionless file in Windows Explorer by a double click. Unfortunately). To build or clean anything you can use one of the commands from table 1. Note the absence of an -f option, and the initialisation of variable ‘DEMO’, which is then used inside the makefile. Feel free to look inside tonc.mak so see how it's done, but be aware that you won't readily understand it if you're new to makefiles or the bash shell.

Table 1: building tonc projects.
to ... run ...
build tonclib.a make utils
build foo demo make DEMO=foo
clean foo demo make DEMO=foo clean
build all demos make build_all
clean all demos make clean_all
Modified Feb 8, 2007, J Vijn. Get all Tonc files here