SWI 0x04 — IntrWait¶
- Entry:
0x00000330(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¶
Repeatedly Halts the CPU until one or more of a caller-specified set of
interrupts has been serviced, tracked through the BIOS interrupt-flag word at
0x03007FF8. The flag word is maintained by the user's IRQ handler (the BIOS
IRQ dispatcher does not set it), and IntrWait acknowledges (clears) the bits it
was waiting for before returning. This is the building block for
VBlankIntrWait (SWI 05h).
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| r0 | discard-old flag | 0 = return as soon as a matching flag is (or already was) set; nonzero = clear any already-pending matching flags first, then wait for a fresh interrupt. |
| r1 | interrupt mask | Bitmask of interrupts to wait for, in the same bit layout as REG_IE/REG_IF (bit0 = VBlank, etc.). |
Returns¶
Returns once at least one requested bit has been seen and acknowledged. No explicit return value in registers.
Clobbered registers¶
r0–r4, ip (r12) are used as scratch. r4 is callee-saved/restored.
Algorithm¶
Uses a check-and-acknowledge helper (0x00000358) that runs with interrupts
briefly masked:
1. Write 0 to REG_IME (0x04000208) to block IRQs during the read-modify-write.
2. Read the 16-bit BIOS flag word from 0x03007FF8 (accessed via IWRAM mirror
[0x04000000 - 8]).
3. Compute matched = mask(r1) & flags. If matched != 0, clear those bits in
the flag word (flags ^= matched) and write the result back to 0x03007FF8.
4. Write 1 to REG_IME to re-enable IRQs.
5. Return with the CPU Z-flag reflecting whether anything matched (Z set = no
match yet).
Main loop:
1. If r0 != 0, call the helper once up front to clear any already-pending
requested flags (so the wait blocks until a new interrupt arrives).
2. Halt the CPU by writing 0 to HALTCNT (0x04000301); the CPU sleeps until
any enabled interrupt fires.
3. After wake-up, call the helper to test/acknowledge the requested bits.
4. If none of the requested bits were set, loop back to step 2 (Halt again).
Otherwise return.
Real constants observed: BIOS flag word 0x03007FF8; REG_IME = 0x04000208;
HALTCNT 0x04000301.
Edge cases & known bugs¶
- Requires a cooperating IRQ handler. IntrWait only works if the program's
installed IRQ handler ORs serviced interrupt bits into
0x03007FF8. If the handler does not, the requested bit is never observed and IntrWait halts forever. (The BIOS IRQ dispatcher at0x128merely calls the user handler at0x03007FFC; it does not touch0x03007FF8itself.) r0 = 0first-iteration quirk. On ther0 = 0path the initial helper call is skipped, soip(the I/O base) is not yet loaded when the first HALTCNT store executes; at that pointipstill holds the handler entry address passed by the SWI dispatcher, so the first "Halt" write lands in ROM and does nothing (no true halt). The routine then polls the flag word once and returns immediately if a match already exists; only from the second iteration onward (after the helper setsip = 0x04000000) does a real Halt occur. Net effect matches the documented "return immediately if already requested" behavior, but the mechanism is subtle — flagged for verification.- Only the low 16 bits of the mask are meaningful (matches
REG_IFwidth).
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.
Timer-2 IRQ fixture with a minimal user handler (acks IF and mirrors bits
into 0x03007FF8), results/blacklist_fixtures1.csv:
- r0=1, r1=TIMER2: slept until the next TM2 IRQ (measured 839,179 cycles
= the phase remainder of the running timer), consumed the matched BIOS_IF
bit, and returned. IME was left = 1 afterwards (IntrWait force-enables
it and does not restore).
- r0=0 with the requested bit already pending in 0x03007FF8: returned
in 95 cycles — immediate return, no halt, flag consumed. This is the
caller-visible behavior predicted by the first-iteration HALTCNT-quirk
analysis (95 cycles is far too fast for any real halt/IRQ round trip).
- r0=0 with the flag clear: slept until the next IRQ exactly like r0=1.
Cycle count¶
95 cycles (raw) for the r0=0 already-pending immediate return; otherwise sleep-until-IRQ (externally determined).
Open questions (need hardware verification)¶
- Confirm the
r0 = 0first-iteration ROM-write behavior described above on real silicon. - Confirm the flag word is treated as 16-bit and that upper bits of
r1are ignored.
GBATEK cross-reference¶
Matches GBATEK SWI 04h IntrWait: polls [3007FF8h], acknowledges by clearing
the matched bits, and depends on the user IRQ handler maintaining that word.
This doc adds the concrete IME-masked read-modify-write sequence and the
r0 = 0 first-iteration detail.