NDS Programming (Part 3)
3.1 Development Environment
The best choice for NDS development is Nintendo’s official development kit — excellent, with complete development and debugging tools (I’ve never seen one). But it’s expensive and not for sale to just anyone — you need a good relationship with Nintendo. So common people can’t get it unless they join Konami, Namco, etc. The dev tools URL is http://www.warioworld.com.
If you can’t be an imperial guard, be a folk hero. A group of skilled people abroad built their own DIY development environment. They call themselves Homebrew. This environment is called devkitPro. All our development work below uses devkitPro.
devkitPro supports multiple game consoles — not just NDS, but also GBA, PSP, NGC, and GP32. Some use MIPS, some PowerPC — beyond our scope. We’ll focus on NDS.
3.2 Installing and Configuring the Development Environment
devkitPro is a SourceForge.net project. Get the latest from SourceForge at http://sourceforge.net/projects/devkitpro. A Google search should turn up many links.
devkitPro is fully open source. You can download source code for almost all libraries and tools from SourceForge. If you’re a programmer who wants to understand every detail (like me), reading devkitPro’s code is a good choice. Like other open source projects, the NDS documentation in devkitPro is pathetically minimal. To learn how to write programs and use library functions, there’s basically one approach — read the code.
Download an exe file named something like devkitProUpdater-1.2.7.exe. This isn’t directly an installer, but it handles online installation of the latest devkitPro. If your internet isn’t slow and your hard drive isn’t small, select all options — that’s my style. Install it on the root directory, e.g., D:\devkitPro.
After installation, configure three environment variables: DEVKITARM (point to devkitARM directory), DEVKITPRO (point to devkitpro root). Important: these paths must use Unix-style paths — use “/” not “". D drive should be written as “/d/” not “D:”. Also set the PATH to include the compiler and other tool directories. You can set environment variables via “My Computer” → Properties, but I prefer writing a batch script to set them without affecting the whole system.
My batch script:
@echo off
REM
REM Written by Jason He; Set up NDS development environment
REM 4/19/2006
REM
REM set environment
set DEVKITARM=/D/devkitPro/devkitARM
set DEVKITPRO=/D/devkitPro
REM set path
set PATH=%PATH%D:\devkitPro\devkitARM\arm-elf\bin;D:\devkitpro\devkitarm\bin;D:\devkitpro\msys\bin;
cd /d D:\devkitPro\examples\nds\
echo Welcome to enter NDS development world!
Save this as nds.bat. Then create a shortcut pointing to: %SystemRoot%\system32\cmd.exe /K D:\devkitPro\nds.bat. Double-click to open the development environment.
3.3 Compiling the NDS Hello World
Before writing our own program, let’s compile and run devkitPro’s built-in example. In the command-line environment, cd to D:\devkitPro\examples\nds\Graphics\2D\hello_world. Just type make and compilation begins. After completion, the hello_world directory will contain several new files — the most important being hello_world.nds. If you’ve used a flash cart, you know .nds files are ROM files that NDS can run.
3.4 Running Hello World
If you have an NDS + flash cart, just copy the file to the flash cart and run it like any other NDS game. On my Super Card SD, it runs directly without conversion.
If you have an NDS but no flash cart, there’s a software called WifiMe that can download hello_world.nds from PC to NDS via WiFi. But it requires high-end PC WiFi hardware. I haven’t tried WifiMe, so I won’t detail it.
If you don’t even have an NDS, you can still run it with an NDS emulator. Since NDS hardware is complex, current emulators are primitive — can’t run commercial games, but fine for example code.
A promising emulator is ideas, still being updated. There’s also ensata (leaked Nintendo internal emulator), but it’s no longer updated. Several other emulators exist — choose as you like.
We can develop and debug our own games this way.
3.5 Code Analysis
3.5.1 Hello World Directory Structure
Now that Hello World runs on NDS, let’s look at the code to understand how it works.
Directory structure after make (I’ve added explanations):
hello_world.arm9 // Compiled output, ARM binary
hello_world.elf // ELF format binary
hello_world.nds // Executable NDS ROM
Makefile // Build script
build/ // Build output, temporary files
hello_world.map // Map file
main.d // Dependency file
main.o // Object file
include/ // Header files (empty)
source/
main.cpp // Source file
Before make, only two files existed: makefile and main.cpp. To create a new project, you just need these two. You can copy the arm9 or combined template from D:\devkitPro\examples\nds\templates\.
3.5.2 main.cpp
The main.cpp code is short — no assembly. It consists of several sections:
Section 1: Header includes
#include <nds.h>
#include <nds/arm9/console.h>
#include <stdio.h>
Section 2: Global variable and Vblank()
volatile int frame = 0;
void Vblank() {
frame++;
}
Section 3: main() function
int main(void) {
touchPosition touchXY;
irqInit();
irqSet(IRQ_VBLANK, Vblank);
irqEnable(IRQ_VBLANK);
videoSetMode(0);
videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankC(VRAM_C_SUB_BG);
SUB_BG0_CR = BG_MAP_BASE(31);
BG_PALETTE_SUB[255] = RGB15(31,31,31);
consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
iprintf(" Hello DS dev'rs\n");
iprintf(" www.devkitpro.org\n");
iprintf(" www.drunkencoders.com");
while(1) {
swiWaitForVBlank();
touchXY = touchReadXY();
iprintf("\x1b[10;0HFrame = %d", frame);
iprintf("\x1b[16;0HTouch x = %04X, %04X\n", touchXY.x, touchXY.px);
iprintf("Touch y = %04X, %04X\n", touchXY.y, touchXY.py);
}
return 0;
}
Try modifying the code and recompiling. Homework: the default text is white — can you change the color?
3.5.3 Makefile
The makefile automates compilation. make.exe reads it and decides how to build the system. Because of makefile, just type make and the system builds automatically.
Due to Windows programmers being “spoiled” by IDEs, makefiles often intimidate. If you’re afraid of makefiles, Google some tutorials.
This makefile is a template. For new projects, just modify a few macros. Key parts:
include $(DEVKITARM)/ds_rules
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := gfx source data
INCLUDES := include build
LIBS := -lnds9
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin)))
With this, we know which files to compile, which libraries to link, and the output name. When creating a new project, just modify these settings.
