IRQ
Der IRQ (Interrupt ReQuest oder maskierbarer Interrupt) ist wie der NMI eine Interruptleitung der CPU, die "low"-aktiv ist. Im Gegensatz zum NMI kann sich ein Programm durch Setzen des Interrupt-Flags mit dem Assembler-Befehl SEI gegen eine IRQ-Anforderung schützen (maskieren) und zu einem späteren Zeitpunkt eine Unterbrechung wieder mit dem Assembler-Befehl CLI zulassen.
Der Programmteil, der einen IRQ abarbeitet, wird Interrupt Service Routine (ISR) genannt.
Auslösung[Bearbeiten]
Folgende Möglichkeiten bestehen, um einen Low-Pegel (0) auf der IRQ-Leitung zu erzeugen.
- extern über den Expansionsport über Pin 4
- durch den BRK-Befehl
- durch entsprechende Programmierung des Interrupt-Kontrollregisters der CIA-Bausteine (Timer CIA1) bzw. durch den VIC (Sprite/Lightpen/Rasterzeilen-Interrupt)
Das Signal an der IRQ-Leitung wird ab dem 2. Takt bis zum letzten Takt einer Instruktion erkannt.
Unter gewissen Situationen können IRQ-Anforderungen auch verworfen werden, wenn nämlich gleichzeitig ein NMI ansteht.[1]
Das Löschen des I-Flags führt üblicherweise dazu, dass eine etwaige bereits wieder anstehende Anforderung zu berücksichtigen ist. Das passiert aber bei den das I-Flag manipulierenden Instruktionen zu unterschiedlichen Zeitpunkten:[2]
- RTI: unmittelbar nach dem RTI kann bereits zu einer IRQ-Routine verzweigt werden, weil schon während dessen der Status der IRQ-Leitung berücksichtigt wird.
- CLI, PLP, SEI: Hier wird erst in der folgenden Instruktion der Status der IRQ-Leitung überprüft und damit die folgende Instruktion noch abgearbeitet bevor sich der IRQ auswirkt.
Ablauf[Bearbeiten]
- Es wird zunächst der laufende Befehl zu Ende abgearbeitet.
- Der Programmzähler (PC) des unterbrochenen Programms wird auf den Stapel abgelegt.
- Das Statusregister wird auf den Stapel gelegt und anschließend das Interrupt-Flag gesetzt, was eine neuerliche Unterbrechung der ISR selbst verhindert.
- Der Hardware-Vektor $FFFE/$FFFF wird angesprungen (zeigt beim normalen C64-KERNAL auf Adresse $FF48).
- Die Interrupt-Service-Routine ab $FF48 wird abgearbeitet.
- mit dem Befehl RTI folgt der Rücksprung ins unterbrochene Programm.
ISR des KERNAL[Bearbeiten]
- im Gegensatz zur NMI-Routine werden die Register gesichert:
$FF48 PHA ; Akku sichern $FF49 TXA $FF4A PHA ; X-Register sichern $FF4B TYA $FF4C PHA ; Y-Register sichern
- Break-Flag testen:
$FF4D TSX ; Stapelzeiger ins X-Register $FF4E LDA $0104, X ; Break-Flag vom Stapel holen $FF51 AND #$10 ; und testen $FF53 BEQ $FF58 ; nicht gesetzt $FF55 JMP ($0316) ; Break-Routine $FE66
- Sprung in die IRQ-Routine:
$FF58 JMP ($0314) ; IRQ-Routine $EA31
- Standard IRQ-Routine:
$EA31 ... $EA34 ... ... ... $EA81 PLA $EA82 TAY ; Y-Register wiederherstellen $EA83 PLA $EA84 TAX ; X-Register wiederherstellen $EA85 PLA ; Akkumulator wiederherstellen
- mit dem Befehl RTI folgt der Rücksprung ins Hauptprogramm:
$EA86 RTI ; Rücksprung ins Hauptprogramm
Eigene ISR[Bearbeiten]
Bei der originalen ISR wird bei Adresse $FF58 der Befehl JMP ($0314)
ausgeführt. Hier besteht nun die Möglichkeit, diesen Vektor (LSB = $0314 ; MSB = $0315) "umzubiegen", um in eine eigene ISR springen zu können (siehe Beispielprogramm). Alternativ muss bei ausgeblendetem ROM direkt die Adresse der eigenen Interrupt-Service-Routine an den Vektor $FFFE/$FFFF geschrieben werden.
Hardware Vektoren[Bearbeiten]
Vektor-Name | Hardware Vektor | Adresse |
---|---|---|
NMI | $FFFA / $FFFB | $FE43 |
Reset | $FFFC / $FFFD | $FCE2 |
IRQ | $FFFE / $FFFF | $FF48 |
Weblinks[Bearbeiten]
- nesdev.com-Wiki: CPU interrupts, mit genaue Details und Anomalien zur internen Interrupt-Verarbeitung bei einer 6502-CPU und Derivaten.
Referenzen