Skip to content

BIOS IRQ Dispatcher, Boot/Reset Path, and IWRAM State Area

  • Status: draft (static analysis only)

This note documents the low-level machinery the reset/halt/wait SWIs interact with: the exception vectors, the IRQ dispatcher, the boot/reset entry, the SWI dispatcher, and the reserved IWRAM state region near the top of on-chip RAM.

Exception vectors (0x000x1C)

Addr Vector Target
0x00 Reset 0x68
0x04 Undefined 0x1C
0x08 SWI 0x140
0x0C Prefetch Abort 0x1C
0x10 Data Abort 0x1C
0x14 (reserved) 0x1C
0x18 IRQ 0x128
0x1C FIQ 0x1C

IWRAM state area (top of on-chip WRAM)

On-chip WRAM is 0x030000000x03007FFF (32 KB) and is mirrored every 0x8000 bytes; the BIOS frequently reaches it via the mirror just below the I/O base (0x04000000), e.g. [0x04000000 - 8] == 0x03007FF8. The reserved top 0x200 bytes hold:

Address Purpose
0x03007F00 Default USER/SYSTEM stack top (grows down)
0x03007FA0 Default IRQ stack top (grows down)
0x03007FE0 Default SVC (supervisor) stack top (grows down)
0x03007FF8 BIOS interrupt-flag word (16-bit). Polled and acknowledged by IntrWait/VBlankIntrWait; must be set by the user IRQ handler — the BIOS dispatcher does not write it.
0x03007FFA SoftReset (SWI 00h) return-target flag byte: 0 → ROM 0x08000000, nonzero → RAM 0x02000000.
0x03007FFC User IRQ handler pointer, invoked by the BIOS IRQ dispatcher.

Boot / reset path (0x68, shared with HardReset 0x8C)

Reset vector branches to 0x68, which checks the low byte of POSTFLG (0x04000300). If it reads 1 (post-boot / soft-reset marker), it masks IRQ+FIQ in CPSR and diverts to the exception handler at 0x1C; otherwise it falls into the cold-boot sequence at 0x8C (also reached as SWI 26h HardReset):

  1. Enter System mode, IRQ+FIQ disabled (CPSR mode value 0xDF).
  2. Write 0 to REG_IME (0x04000208).
  3. Initialize the three mode stacks via the routine at 0xE0: SVC = 0x03007FE0, IRQ = 0x03007FA0, SYS/USR = 0x03007F00.
  4. Store a default IRQ handler pointer into 0x03007FFC.
  5. Jump to the BIOS boot/post-boot routine at 0x00001929 (intro + cartridge launch).

Exception handler (0x1C, Undefined/Abort/FIQ/reserved)

Saves state, then checks a marker byte in the cartridge header at 0x0800009C for the value 0xA5. If present, it dispatches to a cartridge-supplied debug exception handler (addresses 0x09FE2000 / 0x09FFC000 selected by a header bit); otherwise it restores state and returns. This is a developer/debug hook, not used by normal cartridges.

IRQ dispatcher (0x128)

  1. Push {r0-r3, ip, lr} onto the IRQ stack.
  2. Load the user handler pointer from 0x03007FFC (via mirror [0x04000000 - 4]) and jump to it with return address set.
  3. On return, pop the saved registers and return from IRQ (subs pc, lr, #4).

The dispatcher does not read/acknowledge REG_IF or update the 0x03007FF8 flag word — that is entirely the responsibility of the installed user handler. This is why IntrWait/VBlankIntrWait only work when the game's handler ORs serviced-interrupt bits into 0x03007FF8.

SWI dispatcher (0x140)

  1. Push {fp, ip, lr}.
  2. Read the SWI comment-field byte from [lr - 2] (bits 16–23 of the ARM SWI instruction) to get the SWI number N.
  3. Index the jump table at 0x000001C8: handler = table[N]. Odd (low bit set) → THUMB entry, even → ARM.
  4. Switch to System mode (preserving the caller's I flag from SPSR) so handlers run on the user stack and can be re-entered.
  5. bx to the handler; on return, restore SVC mode, SPSR, and the saved registers, then return from the SWI (movs pc, lr).

Real constants: jump table base 0x000001C8; POSTFLG 0x04000300; REG_IME 0x04000208; boot routine 0x00001929.

Open questions (need hardware verification)

  • Exact behavior when POSTFLG == 1 at reset (diversion to 0x1C).
  • Confirm the cartridge debug-handler hook addresses (0x09FE2000 / 0x09FFC000) and the header marker semantics at 0x0800009C/0x080000B4.