Skip to main content

interrupt

Attribute Macro interrupt 

#[interrupt]
Expand description

Install an interrupt handler directly at its vector.

Takes the vector name and binds the function to the matching _on_* symbol:

ArgumentSymbol
VBlank_on_vblank
LcdStat_on_lcd_stat
Timer_on_timer
Serial_on_serial
Joypad_on_joypad

The vector jumps straight to the handler, which the z80-interrupt calling convention compiles to save only the register pairs it clobbers and to return with reti. The exported symbol is strong, so it wins over any weak or PROVIDE default for that vector. The defining crate needs #![feature(abi_z80_interrupt)]:

#![feature(abi_z80_interrupt)]

#[gb_rt::interrupt(LcdStat)]
fn wobble() {
    // runs on each STAT interrupt
}

§Critical section

A handler may take one CriticalSection parameter.

The CPU clears IME when it dispatches an interrupt, so the handler already runs with interrupts off. The token records that and unlocks anything guarding state shared with the main loop.

#[gb_rt::interrupt(Timer)]
fn tick(cs: CriticalSection) {
    TICKS.set_cs(cs, TICKS.get_cs(cs).wrapping_add(1));
}

Enabling interrupts inside such a handler invalidates the token while it is still in scope and can cause undefined behavior.