OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
interrupt.h File Reference

SNES Interrupt Handling. More...

#include <snes/types.h>

Go to the source code of this file.

Macros

#define IRQ_HTIMER   0x10
 Fire an IRQ when the H counter reaches the HTIME value (every scanline).
#define IRQ_VTIMER   0x20
 Fire an IRQ when the V counter reaches the VTIME value (once per frame).

Typedefs

typedef void(* VBlankCallback) (void)
 VBlank callback function pointer type.

Functions

void irqClear (void)
 Restore the default IRQ handler (acknowledge + return).
void irqDisable (void)
 Disable H/V timer IRQs.
void irqEnable (u8 flags)
 Enable H/V timer IRQs and unmask interrupts (CLI).
void irqSet (void *handler)
 Install a raw hardware IRQ handler (H/V timer interrupts).
void irqSetBank (void *handler, u8 bank)
 irqSet() with an explicit ROM bank for the handler
void irqSetHTimer (u16 h)
 Set the H-timer target (0-339 dots).
void irqSetVTimer (u16 v)
 Set the V-timer target (0-261 scanlines NTSC).
void nmiClear (void)
 Clear the VBlank callback.
void nmiSet (VBlankCallback callback)
 Register a VBlank callback function.
void nmiSetBank (VBlankCallback callback, u8 bank)
 Register a VBlank callback with explicit bank.

Detailed Description

SNES Interrupt Handling.

Manages NMI (VBlank), IRQ, and other interrupts.

Author
OpenSNES Team

Macro Definition Documentation

◆ IRQ_HTIMER

#define IRQ_HTIMER   0x10

Fire an IRQ when the H counter reaches the HTIME value (every scanline).

◆ IRQ_VTIMER

#define IRQ_VTIMER   0x20

Fire an IRQ when the V counter reaches the VTIME value (once per frame).

Typedef Documentation

◆ VBlankCallback

typedef void(* VBlankCallback) (void)

VBlank callback function pointer type.

Functions of this type can be registered with nmiSet() to be called automatically during every VBlank interrupt.

Function Documentation

◆ irqClear()

void irqClear ( void )

Restore the default IRQ handler (acknowledge + return).

◆ irqDisable()

void irqDisable ( void )

Disable H/V timer IRQs.

Clears both timer bits in the NMITIMEN shadow. The I flag is left clear — with no timer source enabled, no IRQ can fire.

◆ irqEnable()

void irqEnable ( u8 flags)

Enable H/V timer IRQs and unmask interrupts (CLI).

Sets the requested timer bits in the NMITIMEN shadow (NMI and auto-joypad bits are preserved) and clears the CPU I flag. Install the handler with irqSet() and program the timer with irqSetHTimer()/irqSetVTimer() BEFORE calling this.

Parameters
flagsIRQ_HTIMER, IRQ_VTIMER, or both

◆ irqSet()

void irqSet ( void * handler)

Install a raw hardware IRQ handler (H/V timer interrupts).

The crt0 IRQ vector does a single JML [irq_callback] into your handler — nothing is saved, acknowledged, or set up for you. This is deliberate: an H-timer IRQ fires EVERY SCANLINE (~15.7 kHz) and cannot afford a C prologue, so the SDK imposes zero overhead and zero policy.

Warning
ASM handlers only. The handler contract:
  • Save and restore every register it touches (A/X/Y, DP, DBR — the interrupted code is arbitrary C). P is restored by RTI automatically.
  • Read REG_TIMEUP ($4211) to acknowledge the IRQ, or it re-fires forever.
  • Return with rti.
  • After any rep/sep, add explicit .ACCU/.INDEX directives (WLA-DX tracking rule). A C function pointer passed here WILL corrupt the main thread — cc65816 C prologues assume the tcc register file, which the raw vector does not bank-switch (unlike the NMI path's DP isolation).
A handler that fires general DMA owns that channel: don't call lib DMA helpers (dmaCopyVram etc.) from the main loop while such a handler is armed — the channel registers are shared state.
Parameters
handlerAddress of the ASM handler (see examples/graphics/effects/ hicolor_1792/irq_stream.asm for the canonical shape)

◆ irqSetBank()

void irqSetBank ( void * handler,
u8 bank )

irqSet() with an explicit ROM bank for the handler

Parameters
handlerAddress of the ASM handler
bankROM bank containing the handler

◆ irqSetHTimer()

void irqSetHTimer ( u16 h)

Set the H-timer target (0-339 dots).

With IRQ_HTIMER enabled, the IRQ fires at this horizontal position on every scanline. Values near the end of the visible line (e.g. 190) let a short handler's PPU writes land in H-blank.

◆ irqSetVTimer()

void irqSetVTimer ( u16 v)

Set the V-timer target (0-261 scanlines NTSC).

With IRQ_VTIMER enabled, the IRQ fires once per frame at this scanline (combined with IRQ_HTIMER: at that exact H/V position).

◆ nmiClear()

void nmiClear ( void )

Clear the VBlank callback.

Equivalent to nmiSet(NULL).

◆ nmiSet()

void nmiSet ( VBlankCallback callback)

Register a VBlank callback function.

The registered callback will be called during every VBlank interrupt, BEFORE the vblank_flag is set. This allows time-critical operations (like DMA transfers) to be performed reliably during VBlank.

Parameters
callbackFunction to call during VBlank, or NULL to disable
void myVBlankHandler(void) {
// DMA transfer, scroll updates, etc.
}
int main(void) {
nmiSet(myVBlankHandler);
while (1) {
// Game logic here
}
}
int main(void)
Definition main.c:66
void consoleInit(void)
Initialize SNES hardware.
void WaitForVBlank(void)
Wait for next VBlank period.
void nmiSet(VBlankCallback callback)
Register a VBlank callback function.
Note
Keep callbacks short! VBlank time is limited (~2200 CPU cycles on NTSC)
Callback runs with interrupts disabled
The callback function must be in the same ROM bank as the main code (bank 0). For larger projects, use nmiSetBank() to specify the bank explicitly.

◆ nmiSetBank()

void nmiSetBank ( VBlankCallback callback,
u8 bank )

Register a VBlank callback with explicit bank.

Use this when the callback function might not be in bank 0.

Parameters
callbackFunction to call during VBlank
bankROM bank where the callback is located (0-255)