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:
- Line 0–50: Top status bar — set background colour, render score
- Line 50: Open top border for vertical parallax effects
- Line 250: Bottom section — trigger bank-switched double buffer scroll
- Line 310: End-of-frame housekeeping — update music, read joystick
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.