Skip to content

SWI 0x01 — RegisterRamReset

  • Entry: 0x000009C2 (THUMB; table lists 0x000009C3 with the THUMB low bit set)
  • 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

Selectively clears blocks of RAM and resets groups of I/O registers to a known state, chosen by an 8-bit flag mask in r0. RAM clears are done by zero-filling via the BIOS CPU-fill routine (fixed zero source). Two things happen unconditionally, regardless of the flags: the display is forced blank (DISPCNT := 0x80) at entry, and a pair of serial-I/O register writes occur — the source of the well-known RegisterRamReset SIO/register-corruption bug.

Parameters

Reg In Meaning
r0 reset flag mask Bitmask selecting which regions/registers to reset (see table).

Flag bits (each independently selectable): | Bit | Value | Effect | |-----|-------|--------| | 0 | 0x01 | Zero-fill 256 KB external work RAM at 0x02000000 (0x40000 bytes) | | 1 | 0x02 | Zero-fill on-chip work RAM at 0x03000000, 0x7E00 bytes — i.e. all 32 KB except the top 0x200 reserved for stacks/BIOS state | | 2 | 0x04 | Zero-fill 1 KB palette RAM at 0x05000000 | | 3 | 0x08 | Zero-fill 96 KB VRAM at 0x06000000 (0x18000 bytes) | | 4 | 0x10 | Zero-fill 1 KB OAM at 0x07000000 | | 5 | 0x20 | Reset serial I/O (SIO) registers | | 6 | 0x40 | Reset sound registers | | 7 | 0x80 | Reset "all other" registers (display, DMA, timers, IE/IF/IME, etc.) |

Returns

No return value; registers restored except scratch.

Clobbered registers

r0r7, lr used internally (THUMB, saved/restored via the routine's push/pop). Uses one stack word as the zero fill-source.

Algorithm

  1. Unconditionally write 0x80 to DISPCNT (0x04000000), forcing the screen blank for the duration of the reset.
  2. Prepare a zero word on the stack to use as the fixed fill source, and a CPU-fill control value (0x85000000 OR'd with the word count) that drives a fixed-source 32-bit fill through the shared fill routine near CpuFastSet.
  3. For each flag bit in r0, if set, zero-fill the corresponding RAM block or reset the corresponding register group (see table). RAM sizes in words: EWRAM 0x10000, IWRAM 0x1F80, palette 0x100, VRAM 0x6000, OAM 0x100.
  4. Bit 7 zero-fills large runs of the display/DMA/timer register file (0x040000000x0400005F region) and the interrupt/system registers around 0x04000200 (IE/IF/WAITCNT/IME), plus a couple of undocumented slots (e.g. 0x040001E2, 0x04000410).
  5. Bit 6 reprograms the sound registers (SOUNDCNT block at 0x04000080, master-enable, and masks SOUNDBIAS at 0x04000088 to its low bits) using the constant 0x880E0000.

Real constants observed: DISPCNT 0x04000000 := 0x80; RAM bases 0x02000000/0x03000000/0x05000000/0x06000000/0x07000000; IWRAM clear size 0x7E00 bytes; fill control 0x85000000; sound reset word 0x880E0000; IE/IF/IME block base 0x04000200.

Edge cases & known bugs

  • Unconditional SIO/register corruption (the classic bug). Regardless of which flags are passed, the routine performs two writes into the serial-I/O register block: it stores the halfword 0x8000 to 0x04000114 and the byte 0x07 to 0x04000120 (SIODATA32 area). These occur even if bit 5 (Reset SIO) is clear, so calling RegisterRamReset for an unrelated purpose (e.g. clearing VRAM) will silently disturb serial/SIO state. This matches the well-known GBATEK caveat that RegisterRamReset must be used with care around serial I/O.
  • DISPCNT is always forced blank on entry; callers relying on display state must restore DISPCNT afterward.
  • Bit 1 deliberately preserves the top 0x200 bytes of IWRAM (stack pointers, IRQ handler pointer at 0x03007FFC, IntrWait flag word at 0x03007FF8, etc.), so it is safe to call from normal code without destroying BIOS state.

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.

Per-flag runs with seeded readable registers and palette/VRAM/OAM sentinels (results/blacklist_rrr.csv):

flags raw cycles observed effect
0x00 198 no observable register change; all seeds survived
0x04 934 palette cleared; nothing else
0x08 64774 VRAM cleared (0x6000-word fill dominates); nothing else
0x10 678 OAM cleared; nothing else
0x20 (response lost) SIO register block reset killed the link permanently — remote recovery (nudge/sync) failed; physical power-cycle + re-multiboot required
0x40 401 sound only: SOUND1CNT_H→0, SOUNDCNT_L→0, SOUNDCNT_H readback 0x030E→0x000E (consistent with the static 0x880E write), SOUNDCNT_X→0; a SOUNDBIAS seed of 0x0155 survived
0x80 431 BG0/BG1CNT, WININ/WINOUT, BLDCNT/BLDALPHA, DMA0CNT_H, TM3CNT_H, KEYCNT, IE, WAITCNT all →0; sound registers untouched

The unconditional 0x8000→0x04000114 / 0x07→0x04000120 writes are not observable via readback (0x114 reads as 0; SIODATA32 is overwritten by the link protocol immediately), so they remain a static-analysis finding. Bits 0/1 (EWRAM/IWRAM clear) were deliberately not run — they would erase the worker itself.

Cycle count

flags=0: 198 cycles; palette 934; VRAM 64774; OAM 678; sound 401; other-regs 431 (raw). See the table above.

Open questions (need hardware verification)

  • Confirm the exact register-level meaning and intent of the unconditional writes to 0x04000114 (0x8000) and 0x04000120 (0x07), and enumerate the full set of registers touched by bit 7 on real hardware.
  • Confirm the precise sound-register values left by bit 6.

GBATEK cross-reference

Flag semantics match GBATEK SWI 01h RegisterRamReset. This doc adds the concrete IWRAM clear size (0x7E00), the forced DISPCNT := 0x80, the fill-control constant, and the exact addresses/values of the unconditional SIO writes behind the documented register-corruption bug.