Rasterinterrupts: Farbbalken über den Bildschirm
Im letzten Beitrag – Residente Routinen: der IRQ-Hook – haben wir den IRQ-Vektor bei $0314/$0315 umgebogen und rund 60-mal pro Sekunde die Kontrolle bekommen. Ausgelöst hat das der CIA-Timer. Für Effekte auf dem Bildschirm ist der aber zu grob: Er feuert einmal pro Frame, nicht an einer bestimmten Bildschirmzeile.
Genau dafür hat der VIC-II einen eigenen Interrupt: den Rasterinterrupt. Er löst aus, wenn der Elektronenstrahl eine von dir gewählte Rasterzeile erreicht. Damit kannst du den Bildschirm mitten im Bild umfärben, Sprites wiederverwenden oder – wie hier – Farbbalken ziehen.
| Register | Funktion |
|---|---|
| $d012 | gewünschte Rasterzeile (die unteren 8 Bit) |
| $d011 | Bit 7 = das 9. Bit der Rasterzeile |
| $d01a | Bit 0 = 1 → Rasterinterrupt scharf schalten |
| $d019 | Interrupt quittieren (sonst feuert er endlos) |
Den Rasterinterrupt scharf schalten
Der Aufbau ähnelt dem IRQ-Hook aus dem letzten Beitrag: Wir biegen wieder den Vektor bei $0314/$0315 um. Neu sind nur zwei Dinge – wir schalten den CIA-Timer-IRQ ab und stattdessen den Raster-IRQ des VIC-II an. So bekommen wir die Kontrolle nicht mehr einmal pro Frame, sondern exakt an einer Rasterzeile.
sei ; IRQ sperren
lda #<irq
sta $0314
lda #>irq
sta $0315
lda #$7f
sta $dc0d ; CIA-Timer-IRQ aus
lda #$01
sta $d01a ; Raster-IRQ an
lda #100 ; erste Rasterzeile: obere Kante
sta $d012
lda $d011
and #$7f ; Bit 7 = 0 -> Zeile liegt unter 256
sta $d011
lda #$ff
sta $d019 ; einen evtl. anhängigen IRQ quittieren
cli ; IRQ wieder frei
rtsDie Zeile 100 ist die obere Kante unseres Balkens. Weil sie kleiner als 256 ist, muss Bit 7 in $d011 auf 0 stehen – deshalb das and #$7f. Für Zeilen ab 256 (der Bildschirm reicht bis ~311) würdest du dieses Bit setzen.
Der Balken
Ein Farbbalken ist nichts anderes als: an der oberen Kante die Farbe umschalten, an der unteren Kante wieder zurück. Dafür feuert unser IRQ abwechselnd an zwei Zeilen. Eine kleine Merk-Zelle flag sagt der Routine, welche Kante gerade dran ist – und wo der nächste Interrupt liegen soll.
irq lda #$ff
sta $d019 ; Raster-IRQ quittieren!
lda flag
bne unten
oben lda #$02 ; Balken an: Rahmen rot
sta $d020
lda #200 ; untere Kante -> nächster IRQ
sta $d012
lda #$01
sta flag
jmp $ea31 ; weiter zum Kernal
unten lda #$00 ; Balken aus: Rahmen schwarz
sta $d020
lda #100 ; obere Kante -> nächster IRQ
sta $d012
lda #$00
sta flag
jmp $ea31
flag .byte $00Feuert der IRQ bei Zeile 100, färbt er den Rahmen rot und stellt $d012 auf 200. Beim nächsten Durchlauf – Zeile 200 – färbt er zurück auf Schwarz und setzt die Zielzeile wieder auf 100. Ergebnis: ein stabiler roter Balken zwischen den Zeilen 100 und 200.
Das sta $d019 ganz am Anfang der Routine ist Pflicht. Vergisst du es, hält der VIC-II seinen Interrupt weiter für „unerledigt” – und feuert sofort wieder. Der C64 hängt dann in einer IRQ-Endlosschleife fest.
Das jmp $ea31 am Ende übergibt an die normale Kernal-IRQ-Routine, damit Tastatur und Uhr weiterlaufen. Wer den Rahmen komplett übernimmt, kann stattdessen die Register selbst retten und mit rti zurückkehren – dazu mehr im nächsten Teil.
Läuft der Balken erst einmal, hängt er im IRQ und läuft von selbst weiter. Zurück zum READY-Prompt kommst du mit RUN/STOP + RESTORE – das setzt die Interrupt-Vektoren wieder auf den Kernal-Standard.
Wenn die Kante leicht flimmert, liegt das am Raster-Jitter: Je nachdem, welchen Befehl die CPU beim Auslösen gerade abarbeitet, verschiebt sich der Einsprung um ein paar Taktzyklen. Wie man den Balken damit pixelgenau stabil bekommt, ist das Thema von Teil 2.
Wie es weitergeht
In Teil 2 machen wir aus dem einen Balken viele: mehrere Farbwechsel pro Frame, ein sauber stabilisiertes Raster ohne Jitter und bewegte Balken, die über den Schirm wandern. Damit ist die Grundlage für Farbverläufe, Sprite-Multiplexing und klassische Demo-Effekte gelegt.