Section Constants#

These are to be used with the codegenDecl pragma to place your variables and procedures into certain regions of memory. They cannot be used for local variables, as those are always on the stack which is in IWRAM.


# Define an array which is statically allocated in EWRAM.
var collisionGrid {.codegenDecl: DataInEwram.}: array[2048, uint16]
const DataInIwram = "__attribute__((section(\"\"))) $# $#"#

Put variable in IWRAM (default).

const DataInEwram = "__attribute__((section(\"\"))) $# $#"#

Put variable in EWRAM

const ArmCodeInIwram = "__attribute__((section(\".iwram.text\"), target(\"arm\"), long_call)) $# $#$#"#

Put procedure in IWRAM.

const ThumbCodeInEwram = "__attribute__((section(\".ewram.text\"), target(\"thumb\"), long_call)) $# $#$#"#

Put procedure in EWRAM.

Memory-mapped arrays#

var romMem: array[0x1000000, uint16]#

Access to ROM as an array of halfwords.

The max ROM size is 32MiB.

var sramMem: array[0x10000, uint8]#

Access to SRAM as an array of bytes.

This has a maximum size of 64KiB, though many carts don’t actually have that much available.


These types are used with the waitcnt register.


On Nim 1.6 and later, you can omit the enum prefixes as long as you enable overloadable enums.

In other words, you can write N3_S1 instead of WsRom0.N3_S1.

type WsSram = enum#

SRAM access timings

type WsRom0 = enum#

ROM access timings.

Initial access to ROM takes N cycles, sequential access takes S cycles.

For more information on N cycles and S cycles, see the asm chapter of Tonc.

type WsRom1 = enum#

Access timings for ROM mirror starting at 0x0A000000.

type WsRom2 = enum#

Access timings for ROM mirror starting at 0x0C000000.

type WsPhi = enum#

PHI Terminal Output. This allows the GBA to supply a clock signal to the cartridge hardware, but is not used in practise.

type WaitCnt = object#

Waitstate control

I/O Registers#

var waitcnt: WaitCnt#

Waitstate control register.

This controls the number of CPU cycles taken to access cart memory (ROM and SRAM).

The “standard” setting (used by most commercial games) is as follows:

  sram = WsSram.N8_S8,   # 8 cycles to access SRAM.
  rom0 = WsRom0.N3_S1,   # 3 cycles to access ROM, or 1 cycle for sequential access.
  rom2 = WsRom2.N8_S8,   # 8 cycles to access ROM (mirror #2) which may be used for flash storage.
  prefetch = true        # prefetch buffer enabled.

In this example, waitcnt.rom0 determines the access time for the default view into ROM.


The preferred access time of “3,1” works on every flashcart except for the SuperCard SD and its derivatives. If you want to support the SuperCard without compromising performance for all, use the slowGamePak proc.

There are two additional ROM mirrors located at 0x0A000000 and 0x0C000000, which have access times determined by waitcnt.rom1 and waitcnt.rom2.

The mirrors may be useful for carts containing multiple ROM chips. For example on some carts the upper 128KiB of ROM is mapped to flash storage which would require different access timings.


proc slowGamePak(): bool#

Check if the cartridge does not support fast ROM access, which might be the case if the game is running on the SuperCard MiniSD.


if slowGamePak():
  waitcnt.init(rom0 = WsRom0.N4_S2)
  waitcnt.init(rom0 = WsRom0.N3_S1)