bios#

This module exposes the GBA system calls (aka. BIOS functions).

The function names are PascalCase as is the convention used by Tonc, GBATek and others, which also conveniently helps to avoid clashing with Nimโ€™s reserved keywords such as div and mod.

Attention

These arenโ€™t fully documented yet - please refer to GBATek in the meantime.

Types#

type ResetFlag = enum#
type ResetFlags = set[ResetFlag]#

A bitset of flags to be passed to RegisterRamReset

type CpuSetMode = enum#
type CpuSetStride = enum#
type CpuSetOptions = object#
type CpuFastSetOptions = object#
type BitUnpackOptions = object#
type MultibootOptions = object#
type MultibootMode = enum#

Procedures#

Resetting#

proc SoftReset()#
proc RegisterRamReset(flags: ResetFlags)#

Performs a selective reset of memory and I/O registers.

Note

This also enables the โ€œforced blankโ€ bit of the display control register (dispcnt.blank), which will turn the screen white until you set it to false.

Halting#

proc Halt()#

Halts the CPU until any enabled interrupt occurs.

proc Stop()#

Stops the CPU and turns off the LCD until an enabled keypad, cartridge or serial interrupt occurs.

proc IntrWait(clear: bool, irq: set[IrqIndex])#

Wait until any one of the specified interrupts occurs.

Parameters:

clear

If true, pre-acknowledged interrupts will be disregarded and the routine will wait for them to be acknowledged again.

irq

Which interrupt(s) to wait for.

proc VBlankIntrWait()#

Wait for the next VBlank period.

This is equivalent to IntrWait(true, {iiVBlank}).

If the VBlank interrupt is not enabled, then this will hang.

Example:

import natu/[irq, bios]

irq.enable(iiVBlank)

while true:
  VBlankIntrWait()

Arithmetic#

proc Div(num, den: int): int#

Basic integer division.

Parameters:

num

Numerator.

den

Denominator.

Returns num / den.

Note

Dividing by zero results in an infinite loop. Try DivSafe instead.

proc DivArm(den, num: int): int#

Basic integer division, but with switched arguments.

Parameters:

den

Denominator.

num

Numerator.

Returns num / den.

Note

Dividing by 0 results in an infinite loop.

proc Sqrt(num: uint): uint#

Integer Square root.

proc ArcTan(dydx: FixedT[int16,14]): int16#

Arctangent of dy/dx.

Takes a 2.14 fixed-point value representing the steepness of the slope.

Returns an angle in the range -0x4000..0x4000 (representing -๐œ‹/2 to ๐œ‹/2).

Warning

This gives completely wrong results for inputs outside the range -0x2000..0x2000 (-1.0 to 1.0).

As such, it can only effectively return angles in the range -0x2000..0x2000 (-๐œ‹/4 to ๐œ‹/4).

Consider using ArcTan2 instead.

proc ArcTan2(x, y: int16): uint16#

Full-circle arctangent of a coordinate pair.

          +Y
           โ”‚  . (x,y)
           โ”‚ /
           โ”‚/โ•ฎฮธ
-X โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +X
           โ”‚
           โ”‚
           โ”‚
          -Y

This calculates the angle between the positive X axis and the point (x, y).

The value returned is in the range 0x0000..0xffff (0 to 2๐œ‹).

Warning

In most mathematical libraries the parameters to atan2 are ordered as y, x, but here theyโ€™re x, y.

Memory copy / fill#

proc CpuSet(src: pointer, dst: pointer, opts: CpuSetOptions)#

Transfer via CPU in word/halfword chunks.

The default mode is 16-bit copies.

When opts.mode == cmFill it will keep the source address constant, effectively performing fills instead of copies.

When opts.stride == csWords it will copy or fill in 32-bit steps instead.

Parameters:

src

Source address.

dst

Destination address.

opts

Number of transfers, mode and stride.

Note

This basically does a straightforward loop-copy, and is not particularly fast.

In fill-mode, the source is still an address, not a value.

proc CpuFastSet(src: pointer, dst: pointer, opts: CpuFastSetOptions)#

A fast transfer via CPU in 32 byte chunks.

This uses ARMโ€™s ldmia/stmia instructions to copy 8 words at a time, making it rival DMA transfers in speed.

When opts.mode == cmFill it will keep the source address constant, effectively performing fills instead of copies.

Parameters:

src

Source address. Must be word aligned.

dst

Destination address. Must be word aligned.

opts

Number of words to transfer, and mode.

Note

Both source and destination must be word aligned; the number of copies must be a multiple of 8.

In fill-mode, the source is still an address, not a value.

memcpy32/16 and memset32/16 basically do the same things, but safer. Use those instead.

Checksum#

proc BiosChecksum(): uint32#

Calculate the checksum of the BIOS.

Returns:

  • 0xbaae187f for GBA / GBA SP / Game Boy Micro / Game Boy Player

  • 0xbaae1880 for DS / DS Lite / DSi / 3DS Family.

Rotation / scaling#

These procedures are misnomers, because ObjAffineSet is merely a special case of BgAffineSet. Results from either can be used for both objs and bgs.

proc ObjAffineSet(src: ptr ObjAffineSource, dst: pointer, num: int, offset: int)#

Sets up a simple scale-then-rotate affine transformation. Uses a single ObjAffineSource struct to set up an array of affine matrices (either BG or Object) with a certain transformation. The matrix created is:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
| sxยทcos(ฮฑ) | -sxยทsin(ฮฑ) |
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
| syยทsin(ฮฑ) | syยทcos(ฮฑ)  |
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Parameters:

src

Array with scale and angle information.

dst

Array of affine matrices, starting at a pa element.

num

Number of matrices to set.

offset

Offset between affine elements. Use 2 for BG and 8 for object matrices.

Note

Each element in src needs to be word aligned.

proc BgAffineSet(src: ptr BgAffineSource, dst: ptr BgAffineDest, num: int)#

Sets up a simple scale-then-rotate affine transformation. See ObjAffineSet for more information.

Decompression#

(see GBATek for format details)

proc BitUnPack(src: pointer, dst: pointer, bup: BitUnpackOptions)#
proc LZ77UnCompWram(src: pointer, dst: pointer)#
proc LZ77UnCompVram(src: pointer, dst: pointer)#
proc HuffUnComp(src: pointer, dst: pointer)#
proc RLUnCompWram(src: pointer, dst: pointer)#
proc RLUnCompVram(src: pointer, dst: pointer)#
proc Diff8bitUnFilterWram(src: pointer, dst: pointer)#
proc Diff8bitUnFilterVram(src: pointer, dst: pointer)#
proc Diff16bitUnFilter(src: pointer, dst: pointer)#

Sound#

proc SoundBias(bias: uint32)#
proc SoundDriverInit(src: pointer)#
proc SoundDriverMode(mode: uint32)#
proc SoundDriverMain()#
proc SoundDriverVSync()#
proc SoundChannelClear()#
proc MidiKey2Freq(wa: pointer, mk: uint8, fp: uint8): uint32#
proc MultiBoot(mb: MultibootOptions, mode: MultibootMode): int#

Multiboot handshake

proc HardReset()#

Reboots the GBA, including playing through the GBA boot intro.

proc SoundDriverVSyncOff()#
proc SoundDriverVSyncOn()#

Extras#

Additional utilities from Tonc which are built atop the BIOS routines.

proc VBlankIntrDelay(count: uint)#

Wait for count frames.

proc DivSafe(num, den: int): int#

Divide-by-zero safe division.

The standard Div hangs when den == 0. This version will return int.high or int.low, depending on the sign of num.

Parameters:

num

Numerator.

den

Denominator.

Returns num / den.

proc Mod(num, den: int): int#

Modulo: num % den.

proc DivMod(num, den: int): int#

Modulo: num % den.

proc DivAbs(num, den: int): uint#

Absolute value of num / den.

proc DivArmMod(den, num: int): int#

Modulo: num % den.

proc DivArmAbs(den, num: int): uint#

Absolute value of num / den.

proc CpuFastFill(wd: uint32, dst: pointer, words: uint)#

A fast word fill.

While you can perform fills with CpuFastSet(), the fact that swi 0x01 requires a source address makes it awkward to use. This function is more like the traditional memset formulation.

Parameters:

wd

Fill word.

dst

Destination address.

words

Number of words to transfer.