Skip to content

What this reference adds over GBATEK

Facts extracted from static analysis of the retail GBA BIOS (SHA1 300c20df6731a33952ded8c436f7f186d25d3492) and verified against the binary. These are the items GBATEK either omits, states vaguely, or leaves as "unknown".

Extracted constants (verified against the binary)

Item Value Location
BIOS word-sum (GetBiosChecksum) 0xBAAE187F whole image
ArcTan polynomial coeffs (Horner order, Q14) 169, 912, 2332, 4022, 5802, 8321, 13905, 41721 0x0474
Affine sin table 256 × s16, 1.14 fixed point, round(16384·sin(i·2π/256)) 0x0D5C
m4a equal-temperament ratio table 12 × Q31, round(2^(31+n/12)) (0x800000000xF1A1BF39) 0x31B8
m4a samples-per-frame table 12 × u16 [96,132,176,224,264,304,352,448,528,608,672,704] → 5734…42048 Hz 0x31E8
MidiKey2Freq key table per-key packed byte (hi nibble=shift, lo nibble=ratio index) 0x3104
SoundArea magic "Smsh" = 0x68736D53 work area +0x00
Multiboot cipher string "// Coded by Kawasedo" 0x2D34
Multiboot LCG c = c*0x6F646573 + 1
Multiboot key K 0x43202F2F (normal) / 0x6465646F (multiplay)
Multiboot CRC16 init 0xC387 poly 0xC37B (normal); init 0xFFF8 poly 0xA517 (multiplay)

Behavioral facts GBATEK under-documents

  • BIOS read-protection guard (0x0BA4/0x0B9C). Shared by CpuSet, CpuFastSet, BitUnPack and all decompression SWIs. Aborts (returns silently) when the source lies in 0x00000000–0x01FFFFFF (BIOS region + mirrors). This blocks using these SWIs to copy the BIOS out of itself.
  • Div division-by-zero appears to hang (divisor-align loop) for |numerator| ≥ 2; only ±1/0 and 0/0 return. INT_MIN/-1 returns 0x80000000 without crashing.
  • ArcTan is only valid for |x| ≤ 1.0; outside that the polynomial diverges (error up to ~243°, sign flip near x≈1.75). ArcTan2 sidesteps this by always dividing the larger axis by the smaller.
  • CpuFastSet rounds the count up to a multiple of 8 words — it can overshoot the destination by up to 7 words.
  • VRAM decompressors (LZ77Vram/RLVram/Diff8Vram) buffer half-words; an odd output length drops the final byte. LZ77Vram back-references can read a not-yet-flushed half-word (stale VRAM).
  • Decompressors ignore the type nibble in the header (except Huffman's data-width nibble). 8-bit vs 16-bit Diff is chosen only by which SWI you call.
  • RegisterRamReset always forces DISPCNT to 0x80 and always writes the SIO regs 0x04000114 ← 0x8000 and 0x04000120 ← 0x07 regardless of the reset flags (the well-known SIO-corruption bug), plus a GetBiosChecksum-style System-mode window.
  • IntrWait/VBlankIntrWait poll the BIOS flag word at 0x03007FF8, which the BIOS IRQ dispatcher never sets — the user IRQ handler must OR serviced bits into it.
  • Halt/Stop/CustomHalt all funnel to a HALTCNT (0x04000301) store: 0x00 / 0x80 / caller r2.

IWRAM state map (confirmed)

Address Use
0x03007F00 SYS/USR stack top
0x03007FA0 IRQ stack top
0x03007FE0 SVC stack top
0x03007FF0 SoundArea work-area pointer
0x03007FF8 IntrWait/VBlankIntrWait flag word
0x03007FFA SoftReset destination flag (0→ROM, else→RAM)
0x03007FFC user IRQ handler pointer