SWI 0x1D — SoundDriverVSync¶
- Entry:
0x0000210C(THUMB; SWI table stores0x0000210D) - Status: verified (hardware-checked 2026-07-08: cycle counts and return registers measured on real GBA; struct layouts remain from static analysis)
Summary¶
Called once per V-blank interrupt. Keeps the sound-FIFO DMA phase-locked to the PCM mixer's multi-frame output buffer by counting down a frame counter and, when it expires, restarting DMA1 and DMA2 so their read pointer jumps back to the start of the mix buffer at the exact moment the mixer wraps. Must be called with tight timing (as early as possible in V-blank) to avoid FIFO glitches.
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| — | — | Operates on the global SoundArea at [0x03007FF0]; no explicit args |
Returns¶
| Reg | Out | Meaning |
|---|---|---|
| — | — | DMA possibly restarted; frame counter updated |
Clobbered registers¶
r0–r3.
Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0 = 0, r1 = 0xB600 (DMA enable value), r3 = 0x040000D2 (DMA2 control address). 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.
Algorithm¶
- Load SoundArea via
[0x03007FF0]; if identity word ≠0x68736d53, return. - Decrement the byte counter
pcmDmaCounter(SoundArea+0x04). If it is still > 0, return (this frame does not restart DMA). - When it reaches 0, reload it from
pcmDmaPeriod(SoundArea+0x0B) and restart the FIFO DMA: - Write
0toDMA1CNT_H(0x040000C6) andDMA2CNT_H(0x040000D2) to stop both channels. - Write
0xB600toDMA1CNT_HandDMA2CNT_Hto re-enable them: enable (bit15) + repeat (bit9) + 32-bit transfer (bit10) + start-timing = special / Sound-FIFO (bits12–13 = 11), destination fixed. This re-arms both channels to feed FIFO A and FIFO B starting again fromDMA1SAD/DMA2SAD(the mix buffer bases set by SoundDriverInit).
Edge cases & known bugs¶
- No-op if the SoundArea identity word is wrong.
- Timing-critical: the stop-then-restart of DMA must happen within the same V-blank slice, otherwise the FIFO under/overflows and audio clicks.
- Only every
pcmDmaPeriod-th call performs the restart; intervening frames just decrement the counter.
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).
82 cycles steady-state (106 observed on the first call after driver reconfiguration).
Open questions (need hardware verification)¶
- Exact
0xB600field decode vs. real DMA behavior (destination-control bits). - Interaction if the user's V-blank handler is late — how many cycles of slack exist.
GBATEK cross-reference¶
Details GBATEK's SoundDriverVSync: the pcmDmaCounter/pcmDmaPeriod countdown and
the precise DMA1/DMA2 stop→0xB600 restart sequence.