SWI 0x1A — SoundDriverInit¶
- Entry:
0x00001664(THUMB; SWI table stores0x00001665) - Status: verified (hardware-checked 2026-07-08: cycle counts and return registers measured on real GBA; struct layouts remain from static analysis)
Summary¶
Initializes the BIOS software sound mixer ("Direct Sound" PCM engine). The caller
supplies a pointer to a SoundArea work buffer (a large zero-able RAM struct,
≈ 0xFB0 bytes). The routine:
- stores the SoundArea pointer at fixed IWRAM address 0x03007FF0 (all later sound
SWIs find the work area through this pointer),
- zero-fills the work area,
- programs the APU registers and the two sound-FIFO DMA channels (DMA1 → FIFO A,
DMA2 → FIFO B) to stream the mixer's PCM output buffers,
- installs default function-pointer hooks (mostly no-op stubs) and the sequencer
command jump-table pointer,
- writes the SoundArea identity word and calls the internal mode/frequency setup
with a default sampling rate,
- resynchronises the FIFO DMA to the scanline/V-count timing before returning.
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| r0 | ptr | Pointer to the SoundArea work buffer to initialize (WRAM, ~0xFB0 bytes) |
Returns¶
| Reg | Out | Meaning |
|---|---|---|
| — | — | SoundArea initialized; global sound pointer set at 0x03007FF0 |
Register/DMA programming performed¶
SOUNDCNT_X(0x04000084) ←0x008F: master sound enable (bit7) set.SOUNDCNT_H(0x04000082) ←0xA90E: PSG master volume 100%, Direct Sound A & B at 100%, DS-A routed right + FIFO-A reset, DS-B routed left + FIFO-B reset, both Direct Sound timers = Timer 0.SOUNDBIAS+1(0x04000089) : bit 6 (SOUNDBIAS bit 14, amplitude-resolution / sampling-cycle) set, low bits preserved.- DMA1:
DMA1SAD(0x040000BC) ← SoundArea +0x350(PCM mix buffer A);DMA1DAD(0x040000C0) ←0x040000A0(FIFO A);DMA1CNT_Hcleared then later enabled by the VSync routines. - DMA2:
DMA2SAD(0x040000C8) ← SoundArea +0x980(PCM mix buffer B);DMA2DAD(0x040000CC) ←0x040000A4(FIFO B);DMA2CNT_Hcleared. - Work-area pointer written to
0x03007FF0(offset+0x30of the block based at0x03007FC0).
Inferred SoundArea struct layout¶
Base = SoundArea pointer. Identity word 0x68736d53 ("Smsh") marks a valid/ready
area and doubles as a re-entrancy lock (sound SWIs bump it by 1 while running and
restore it on exit; a mismatch makes the SWI a no-op).
| Offset | Size | Field (inferred) | Notes |
|---|---|---|---|
| 0x00 | u32 | ident / lock | set to 0x68736d53; used as busy guard |
| 0x04 | u8 | pcmDmaCounter | V-blank countdown, reload from +0x0B |
| 0x05 | u8 | reverb | set by SoundDriverMode (0..0x7F) |
| 0x06 | u8 | maxChans / active PCM channel count | init = 8 |
| 0x07 | u8 | masterVolume | init = 15 (0x0F) |
| 0x08 | u8 | freq (sample-rate index) | set by mode helper |
| 0x09 | u8 | mode/misc bits | |
| 0x0B | u8 | pcmDmaPeriod | frames per DMA buffer cycle; reload for +0x04 |
| 0x10 | s32 | pcmSamplesPerVBlank | from freq table (96..704) |
| 0x14 | s32 | pcmFreq / derived rate | |
| 0x18 | s32 | divFreq / derived | |
| 0x1C | ptr | CGB(PSG) channel array (4 × 0x40) | used by SoundChannelClear |
| 0x20 | u32 | MPlayMain-hook enable flag | 0 by default |
| 0x24 | ptr | MPlayMain hook function | 0 by default |
| 0x28 | ptr | main-update hook | init = no-op stub (0x1708) |
| 0x2C | ptr | hook | init = stub |
| 0x30 | ptr | hook | init = stub |
| 0x34 | ptr | sequencer command jump table | init = 0x3738 (BIOS table) |
| 0x38 | ptr | VSync/aux hook function | init = 0x2424 |
| 0x3C | ptr | hook | init = stub |
| 0x50 + i*0x40 | 0x40 | PCM channel[i], i = 0..11 | 12 mixer voices; status byte at +0 |
| 0x350 | ~0x630 | PCM mix buffer A (→ FIFO A via DMA1) | |
| 0x980 | ~0x630 | PCM mix buffer B (→ FIFO B via DMA2) |
The 12 PCM channels occupy 0x50..0x350 (12 × 0x40). "Direct Sound channels" here
means software mixer voices, not the two hardware FIFOs; SoundDriverMain mixes all
active voices down into the two PCM buffers each frame.
Algorithm¶
- Save the SoundArea pointer; disable DMA1/DMA2 control high halfwords.
- Program
SOUNDCNT_X,SOUNDCNT_H,SOUNDBIASresolution bit, and DMA source/dest as listed above; store the mix-buffer-A address intoDMA1SAD. - Store the SoundArea pointer to
0x03007FF0. - Zero-fill the work area via
CpuSet(memfill of ~4016 bytes / 1004 words). - Set defaults: maxChans = 8, masterVolume = 15, hook slots to stubs, jump-table
pointer =
0x3738, VSync hook =0x2424. - Call the internal mode/frequency helper (
0x170A) with default frequency index (bits 16–19 = 4 ⇒ ~13379 Hz), which fills pcmSamplesPerVBlank/pcmFreq and derived timer/period fields, waits for a safe V-count window, and enables the FIFO DMA. - Write the identity word
0x68736d53to offset 0 and return.
Edge cases & known bugs¶
- The work area must be at least
0xFB0bytes and word-aligned; the fill and the buffer offsets assume this. - The routine does not check the caller pointer for validity.
Clobbered registers¶
Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0 = 0x68736D53 ('Smsh' ident), r1 = 0x9F, r3 = 0x170 leftover. r2, r4–r12, r13, and CPSR (flags and mode) came back bit-identical on every tested path. r11/r12 are explained by the SWI dispatcher (it pushes {r11, r12, lr} — see 10_irq_boot_and_iwram.md) and CPSR by the SPSR restore on return; r2 and r4–r10 must be preserved or restored by the routine itself — where a static note above claims r2 is destroyed, the hardware disagrees at the caller level. Raw data: results/clobber_audit_pass2.csv.
Cycle count¶
Hardware-measured net CPU cycles (worker-ROM harness, TM0/TM1 cascade at F/1,
13-cycle baseline subtracted; identical across 3 runs — see
02_hardware_verification_checklist.md § Measurement setup).
64325 cycles, constant across runs (work-area clear dominates).
Open questions (need hardware verification)¶
- Exact meaning of offsets
0x14/0x18(pcmFreq vs. divFreq) and the derived timer reload written by the0x170Ahelper. - Precise per-channel (0x40-byte) field layout — see SoundDriverMain.
- Whether
maxChansdefault 8 is later overridden by SoundDriverMode.
GBATEK cross-reference¶
Fills in the SoundArea/"SoundInfo"/work-area layout that GBATEK leaves largely
undocumented, plus the exact SOUNDCNT/DMA programming and the 0x03007FF0 global
pointer convention.