Table of Contents

Linking and memory management

In Wonderful's ecosystem, instead of relying on the linker and a post-link tool, linker wrappers are utilized instead. This allows handling everything from object linking to program file output in one step on the user side, as well as implementing high-level configuration facilities which generate a link script.

# This call...
$ arm-none-eabi-ld -o program.elf [objects...] [flags...]

# ...becomes:
$ wf-gbatool link rom|multiboot -o program.gba --output-elf program.elf -- [objects...] [flags...]

# By default, wfconfig.toml in the current working directory is used
# (see below). To use a different file:
$ wf-gbatool link rom|multiboot -c other_wfconfig.toml -o program.gba --output-elf program.elf -- [objects...] [flags...]

Cartridge metadata

GBA cartridges contain some user-configurable metadata. To edit it, create a wfconfig.toml file with the following contents:

[cartridge]
logo = "official"
title = "Program"
code = "XXXX"
maker = "WF"

Default memory placement

The GBA contains two separate blocks of memory: 32 kilobytes of fast IWRAM and 256 kilobytes of slower EWRAM. In Wonderful's GBA target, memory which is not explicitly marked as belonging to IWRAM or EWRAM with a section attribute is placed in EWRAM by default. However, this can be changed to IWRAM by using he following wfconfig.toml configuration:

[memory]
data-region = "iwram"

Memory overlays

wf-gbatool link also allows you to easily use memory overlays: overlapping areas of memory containing code and data that can be easily swapped out. For example, the following wfconfig.toml configuration:

[memory.overlay]
iwram = [
  ["one", "two"],
  ["one", "three"],
  ["four"]
]

creates three valid IWRAM layout configurations:

This allows minimizing the amount of IWRAM space occupied by code. One can use the following helper (also provided in <gba/overlay.h>) to load such an overlay from ROM to RAM:

#define gba_overlay_load(TYPE, NAME) \
    { \
        extern char __load_addr_ ## TYPE ## _ ## NAME ; \
        extern char __load_start_ ## TYPE ## _ ## NAME ; \
        extern char __load_stop_ ## TYPE ## _ ## NAME ; \
        memcpy( \
            &__load_addr_ ## TYPE ## _ ## NAME , \
            &__load_start_ ## TYPE ## _ ## NAME , \
            &__load_stop_ ## TYPE ## _ ## NAME - \
            &__load_start_ ## TYPE ## _ ## NAME ); \
    }
    
#define gba_overlay_load_iwram(NAME) gba_overlay_load(iwram, NAME)

// EWRAM is also supported!
#define gba_overlay_load_ewram(NAME) gba_overlay_load(ewram, NAME)

From there, the helper can be used as follows:

__attribute__((noinline, section(".iwram_one"))) void func_a(void) {
    // ...code...
}

__attribute__((noinline, section(".iwram_four"))) void func_b(void) {
    // ...code...
}

// ...function...
    gba_overlay_load_iwram(one);
    func_a();

    gba_overlay_load_iwram(four);
    func_b();