IRQ
Der IRQ (Interrupt ReQuest oder maskierbarer Interrupt) ist wie der NMI eine Interruptleitung der CPU. Im Gegensatz zum NMI ist die Leitung Low-aktiv, und der Prozessor ignoriert bei gesetztem Interrupt-Flag die IRQ-Leitung. Dieses Flag kann mit dem Assembler-Befehl SEI gesetzt und per CLI gelöscht werden. Außerdem setzt die CPU das Flag automatisch bei der Auslösung eines IRQs.
Der Programmteil, der einen IRQ abarbeitet, wird Interrupt Service Routine (ISR) genannt.
Auslösung[Bearbeiten | Quelltext bearbeiten]
Folgende Möglichkeiten bestehen, um einen Low-Pegel (0) auf der IRQ-Leitung zu erzeugen.
- extern über den Expansionsport über Pin 4
- durch entsprechende Programmierung des Interrupt-Kontrollregisters der CIA-Bausteine (Timer CIA1) bzw. durch den VIC (Sprite/Lightpen/Rasterzeilen-Interrupt)
- die Leitung READ des Kassettenports und SRQ der seriellen Schnittstelle können einen IRQ auslösen, sofern CIA1 entsprechend konfiguriert ist
Ferner löst der BRK-Befehl einen Interrupt aus, zieht aber nicht die IRQ-Leitung auf Low.
Das Signal an der IRQ-Leitung wird ab dem 2. Takt bis zum letzten Takt einer Instruktion erkannt.
Eine zeitgleich mit einer IRQ-Anforderung anliegende NMI-Anforderung hat Vorrang.[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 | Quelltext 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 | Quelltext 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 | Quelltext 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 | Quelltext bearbeiten]
Vektor-Name | Hardware Vektor | Adresse |
---|---|---|
NMI | $FFFA / $FFFB | $FE43 |
Reset | $FFFC / $FFFD | $FCE2 |
IRQ | $FFFE / $FFFF | $FF48 |
Weblinks[Bearbeiten | Quelltext bearbeiten]
- nesdev.com-Wiki: CPU interrupts, mit genaue Details und Anomalien zur internen Interrupt-Verarbeitung bei einer 6502-CPU und Derivaten.
Referenzen