Skip to content

SWI 0x05 — VBlankIntrWait

  • Entry: 0x00000328 (ARM)
  • Status: verified (hardware-checked 2026-07-08: fixture-driven runs on real GBA via the worker's no-blacklist opcode; see Hardware verification section)

Summary

Convenience wrapper around IntrWait (SWI 04h) that waits for the next VBlank interrupt. It simply preloads the IntrWait parameters and falls through into the IntrWait code, so all of IntrWait's behavior (BIOS flag word at 0x03007FF8, acknowledge-by-clear, dependency on the user IRQ handler) applies.

Parameters

None from the caller. Internally sets: | Reg | Value | Meaning | |-----|-------|---------| | r0 | 1 | discard already-pending flags; wait for a new interrupt | | r1 | 1 | interrupt mask = bit0 = VBlank |

Returns

Returns after the next VBlank interrupt has been serviced and acknowledged.

Clobbered registers

Same as IntrWait: r0r4, ip (r12); r4 restored.

Algorithm

  1. Set r0 = 1 (discard old flags → wait for a fresh VBlank).
  2. Set r1 = 1 (VBlank bit).
  3. Fall through directly into IntrWait at 0x00000330. See swi_04_intrwait.md for the full Halt/poll/acknowledge loop.

Real constants observed: VBlank mask 0x0001; shares IntrWait's 0x03007FF8, REG_IME 0x04000208, HALTCNT 0x04000301.

Edge cases & known bugs

  • Requires the VBlank interrupt to be enabled and the user IRQ handler to set 0x03007FF8. Specifically: DISPSTAT VBlank IRQ enable (0x04000004 bit3), REG_IE bit0, and REG_IME must be configured, and the installed handler at 0x03007FFC must OR bit0 into 0x03007FF8. Otherwise VBlankIntrWait hangs.
  • Because r0 = 1, it always waits for a new VBlank even if one just occurred.

Hardware verification (2026-07-08)

Fixture-driven runs via the worker's no-blacklist opcode (swf), with wake sources / handlers installed through CpuSet pokes. Raw data: results/blacklist_fixtures1.csv.

Fixture: DISPSTAT bit3 (VBlank IRQ enable) + IE bit0 + the minimal user handler. Three runs returned after 1.94 ms, 7.34 ms, and 13.55 ms — always within one frame (16.74 ms), landing on the next VBlank edge (phase-dependent, as expected). Forced blank (DISPCNT.7) does not suppress VBlank IRQs.

Cycle count

Phase-dependent: 32,552 / 123,218 / 227,255 raw cycles observed — uniformly distributed within one 280,896-cycle frame.

Open questions (need hardware verification)

  • None specific beyond those noted for IntrWait.

GBATEK cross-reference

Matches GBATEK SWI 05h VBlankIntrWait, documented as IntrWait(1, 1). Confirmed here as a literal fall-through into the IntrWait entry.