Skip to main content

Build Process Overview

Building Una Aventura Inesperada involves three main stages:
  1. Asset Conversion: Converting images to NDS format (.s/.h files)
  2. Compilation: Compiling C source to ARM machine code
  3. Linking: Creating the final .nds ROM file
1

Prepare Assets

Graphics must be converted from standard formats (PNG, BMP) to NDS tile/bitmap data using grit.
2

Compile Source

The ARM cross-compiler (arm-none-eabi-gcc) compiles C code to ARM9 object files.
3

Link ROM

Object files are linked and packaged into an .nds ROM using ndstool.

Quick Start

If you have a Makefile configured:
# Build the ROM
make

# Clean build artifacts
make clean

# Rebuild from scratch
make clean && make
The output will be una-aventura-inesperada.nds in the project root.

Manual Build Process

If building without a Makefile:

1. Convert Graphics Assets

The game uses pre-converted graphics in .s assembly format. If you need to reconvert:
# Convert main menu
grit menuPrincipal.png -ftB -fh! -gTFF00FF -gt -gB8 -m! -omenuPrincipal

# Convert HUD
grit HUD.png -ftB -fh! -gTFF00FF -gt -gB8 -m! -oHUD

# Convert cinematics
grit CinematicaInicioF1.png -ftB -fh! -gTFF00FF -gt -gB8 -m! -oCinematicaInicioF1
The project already includes converted .s and .h files. You only need to run grit if modifying graphics.

2. Compile Source Files

arm-none-eabi-gcc -c \
  -mthumb -mthumb-interwork \
  -march=armv5te -mtune=arm946e-s \
  -DARM9 \
  -I$DEVKITPRO/libnds/include \
  -g -Wall -O2 \
  -o build/main.o \
  source/main.c

3. Assemble Graphics Data

# Assemble each .s file
arm-none-eabi-as -mthumb -mthumb-interwork \
  -o build/menuPrincipal.o \
  source/menuPrincipal.s

arm-none-eabi-as -mthumb -mthumb-interwork \
  -o build/HUD.o \
  source/HUD.s

# Repeat for all .s files...
arm-none-eabi-gcc \
  -specs=ds_arm9.specs \
  -mthumb -mthumb-interwork \
  -march=armv5te \
  -L$DEVKITPRO/libnds/lib \
  -o una-aventura-inesperada.elf \
  build/*.o \
  -lnds9

5. Create the ROM

ndstool -c una-aventura-inesperada.nds \
  -9 una-aventura-inesperada.elf \
  -b icon.bmp "Una Aventura Inesperada;Puzzle Game;By Author"

Compiler Flags Explained

Architecture Flags

FlagPurpose
-mthumbUse 16-bit Thumb instruction set for smaller code
-mthumb-interworkAllow mixing ARM and Thumb code
-march=armv5teTarget ARMv5TE architecture (NDS CPU)
-mtune=arm946e-sOptimize for ARM946E-S processor

Compilation Flags

FlagPurpose
-O2Optimization level 2 (balance speed/size)
-gInclude debugging information
-WallEnable all warnings
-DARM9Define ARM9 macro for conditional compilation

Linker Flags

FlagPurpose
-specs=ds_arm9.specsUse NDS ARM9 linker specifications
-lnds9Link against libnds library

Asset Conversion Process

Image to Assembly

The game stores graphics as assembly data files. Here’s how the conversion works:
# Convert a 256x192 bitmap
grit menuPrincipal.png \
  -ftB          # Output bitmap format
  -fh!          # Don't create header (manual)
  -gTFF00FF     # Transparency color
  -gt           # Generate for tiles
  -gB8          # 8-bit depth
  -m!           # No map output
  -omenuPrincipal

Header File Format

Generated headers follow this pattern (~/workspace/source/source/menuPrincipal.h):
// menuPrincipal.h
extern const unsigned int menuPrincipalBitmapLen;
extern const unsigned int menuPrincipalBitmap[];

Assembly Data Format

The .s files contain raw bitmap data:
.section .rodata
.align 4
.global menuPrincipalBitmap
menuPrincipalBitmap:
    .word 0x12345678
    .word 0x9ABCDEF0
    # ... bitmap data

Tile System Compilation

The tile system (teselas.h) is compiled directly as C arrays (~/workspace/source/source/teselas.h:1):
// Tile data is embedded in header
u8 t_jugadorF1Parte1[64] = {
    12, 12, 12, 1, 1, 1, 1, 1,
    12, 12, 12, 1, 1, 5, 5, 4,
    // ... 8x8 tile data
};
These are loaded at runtime via DMA (~/workspace/source/source/main.c:1067):
dmaCopy(t_jugadorF1Parte1, tileMemory, sizeof(t_jugadorF1Parte1));

Build Output Files

Intermediate Files

build/
├── main.o              # Compiled main.c
├── menuPrincipal.o     # Assembled menu graphics
├── HUD.o               # Assembled HUD graphics  
├── CinematicaInicioF1.o
├── Pregunta1-1.o
└── ...                 # All other .s files
```text

### Final Output

```text
una-aventura-inesperada.nds    # Nintendo DS ROM (playable)
una-aventura-inesperada.elf    # ELF binary (for debugging)
una-aventura-inesperada.map    # Memory map (optional)
```text

<Note>
The `.nds` file is the only file needed to play the game on hardware or emulators.
</Note>

## Memory Map

The linker uses NDS-specific memory regions:

| Region | Address Range | Purpose |
|--------|---------------|--------|
| ARM9 RAM | 0x02000000 - 0x023FFFFF | Main program memory (4MB) |
| VRAM | 0x06000000 - 0x06FFFFFF | Video memory (656KB) |
| Tile RAM | BG_TILE_RAM_SUB(1) | Background tiles |
| Map RAM | BG_MAP_RAM_SUB(0) | Tile map data |

## Build Optimization

### Size Optimization

To reduce ROM size:

```makefile
CFLAGS += -Os          # Optimize for size
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS += -Wl,--gc-sections  # Remove unused sections

Speed Optimization

For better performance:
CFLAGS += -O3          # Maximum optimization
CFLAGS += -ffast-math  # Fast floating point
CFLAGS += -funroll-loops
The game currently uses -O2 as a balance between size and speed.

Build Troubleshooting

Common Issues

1

Missing libnds

Error: fatal error: nds.h: No such file or directorySolution: Install nds-dev package:
sudo dkp-pacman -S nds-dev
2

Undefined References

Error: undefined reference to 'dmaCopy'Solution: Link against libnds:
-lnds9
3

Wrong Architecture

Error: bad instruction or illegal instructionSolution: Verify ARM flags:
-march=armv5te -mthumb -mthumb-interwork
4

Missing DEVKITARM

Error: arm-none-eabi-gcc: command not foundSolution: Set environment variables:
export DEVKITPRO=/opt/devkitpro
export DEVKITARM=$DEVKITPRO/devkitARM
export PATH=$DEVKITARM/bin:$PATH

Debugging Build Issues

Enable verbose output:
make VERBOSE=1
Or add to Makefile:
V := 1

Testing the Build

Using an Emulator

# Run in DeSmuME emulator
desmume una-aventura-inesperada.nds

On Hardware

  1. Copy the .nds file to your flashcard
  2. Insert flashcard into Nintendo DS
  3. Launch from the DS menu

Continuous Integration

Example GitHub Actions workflow:
.github/workflows/build.yml
name: Build NDS ROM

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    container: devkitpro/devkitarm
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Build ROM
      run: |
        make
    
    - name: Upload ROM
      uses: actions/upload-artifact@v2
      with:
        name: una-aventura-inesperada.nds
        path: una-aventura-inesperada.nds

Advanced Build Topics

Custom Linker Scripts

For advanced memory management, create a custom linker script:
/* custom.ld */
OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

MEMORY {
    rom : ORIGIN = 0x08000000, LENGTH = 32M
    ewram : ORIGIN = 0x02000000, LENGTH = 4M
}

SECTIONS {
    .text : { *(.text) } > rom
    .data : { *(.data) } > ewram
    .bss : { *(.bss) } > ewram
}

Parallel Builds

Speed up compilation with parallel jobs:
make -j$(nproc)  # Use all CPU cores
Parallel builds can significantly reduce compilation time on multi-core systems.

Build docs developers (and LLMs) love