Skip to content

C64 Raster Interrupts: Timing & Techniques

What Are Raster Interrupts?

The VIC-II chip draws the screen line by line, 312 lines per frame on PAL systems (263 on NTSC). A raster interrupt fires when the electron beam reaches a specific scanline, giving your code a precisely-timed entry point to manipulate hardware registers mid-frame.

This is the foundation of virtually every visual effect on the C64 — from stable scroll routines to sprite multiplexing through frame alternation, colour splits, and FLD tricks.

Setting Up a Basic Raster IRQ

The VIC-II register at $D012 holds the current raster line (low 8 bits), while bit 7 of $D011 provides the 9th bit. To request an interrupt at a specific line:

    SEI                 ; disable interrupts
    LDA #$7F
    STA $DC0D           ; disable CIA1 interrupts
    LDA $DC0D           ; acknowledge pending CIA1

    LDA #$01
    STA $D01A           ; enable VIC raster interrupt

    LDA #$80            ; target raster line 128
    STA $D012
    LDA $D011
    AND #$7F            ; clear bit 7 (9th bit of raster)
    STA $D011

    LDA #<irq_handler
    STA $FFFE
    LDA #>irq_handler
    STA $FFFF
    CLI                 ; enable interrupts
    RTS

irq_handler:
    LDA $D019
    STA $D019           ; acknowledge VIC interrupt
    ; --- your effect code here ---
    JMP $EA31           ; return through KERNAL

Stable vs. Unstable Rasters

The 6502 does not stop mid-instruction when an interrupt fires. Depending on which instruction is executing, the actual entry into your handler varies by 0–7 cycles. For colour splits or sprite positioning this jitter is visible.

The classic fix is a double-IRQ technique: the first IRQ sets up a second at the next line, and the second uses a series of NOP slides to align to an exact cycle. More modern approaches use NMI-based timing for guaranteed single-cycle entry.

Chaining Multiple Raster IRQs

Most C64 games chain several interrupts per frame. A typical setup for a scrolling game might include:

Each handler reprograms $D012 and the IRQ vector to point to the next handler in the chain before returning.

Common Pitfalls

Forgetting to acknowledge the VIC interrupt (STA $D019) causes the handler to fire continuously. Leaving CIA interrupts enabled creates conflicts where the system timer steals cycles from your raster chain. And targeting raster lines in the vertical blank (lines 300–312 on PAL) requires the 9th raster bit set via $D011.

For practical examples of raster interrupts driving real game engines, see the Seawolves technical breakdown where multiple chained IRQs handle sprite multiplexing, FLD compensation, and colour cycling simultaneously across 8 game scenes.