Skip to content

SWI 0x1D — SoundDriverVSync

  • Entry: 0x0000210C (THUMB; SWI table stores 0x0000210D)
  • 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

  1. Load SoundArea via [0x03007FF0]; if identity word ≠ 0x68736d53, return.
  2. Decrement the byte counter pcmDmaCounter (SoundArea+0x04). If it is still > 0, return (this frame does not restart DMA).
  3. When it reaches 0, reload it from pcmDmaPeriod (SoundArea+0x0B) and restart the FIFO DMA:
  4. Write 0 to DMA1CNT_H (0x040000C6) and DMA2CNT_H (0x040000D2) to stop both channels.
  5. Write 0xB600 to DMA1CNT_H and DMA2CNT_H to 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 from DMA1SAD/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 0xB600 field 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.