Assembler-Kurs Teil 10
Wie versprochen, handelt der letzte Teil
dieses Kurses von en Interrupts.
Interrupt bedeutet soviel wie " Unterbrechung" des laufenden Programms. Der
C64 reagiert auf verschiedene Arten von
Interrupts, die man in Hardund Softwareinterrups unterteilen kann.
Hardware-Interrupts
Es gibt zwei unterschiedliche Arten von
Hardware-Interrupts, den IRQ ( interrupt
request = Interrupt Anforderung) und den
NMI ( non maskable interrupt = Nicht
maskierbarer Interrupt) . Beide sind
eigentlich Pins am Prozessor, an denen
durch ein Impuls ein entsprechender
Interrupt ausgelöst werden kann. Die
Reaktion des Prozessors auf beide
Interrupts ist etwas unterschiedlich.
Grundsätzlich sagt man, daß der NMI die
höhere Priorität beider Interrupt-Arten hat und somit für die für das System
wichtigen Aufgaben eingesetzt wird.
a) Ablauf eines NMI:
1 . Der momentan zu bearbeitende Befehl
des laufenden Programms wird noch ausgeführt.
2 . Der Programmzähler ( program counter), d. h. das Register, das immer auf den nachfolgenden Befehl eines Programms zeigt, wird auf den
Stack geschoben. Dabei wird zuerst das höherwertige und dann das niederwertige Byte des Programmzählers abgelegt.
3 . Das Statusregister, das alle Flags enthält, wird auf den Stack gebracht.
4 . Der Inhalt der Adressen $ FFFA ( als niederwertiges Byte) und $ FFFB ( als
höherwertiges Byte) wird zusammengesetzt und als neuer Programmzähler benutzt. Ab jetzt wird also
das ( unterbrechende) Programm an der Stelle ausgeführt, auf die der neue Programmzähler zeigt.
b) Ablauf eines IRQ:
1 . Zunächst scheint der IRQ genauso zu verlaufen, wie der NMI. Der augenblicklich zu bearbeitende Befehl des laufenden Programms wird
noch vollständig abgearbeitet.
2 . Anschließend erfolgt eine Überprüfung des Interrupt-Flags ( Bit 2 des Statusregisters) . Wenn das Bit gesetzt ist, dann wird die Interrupt-Anforderung einfach ignoriert, und der Prozessor fährt fort, als ob nichts geschehen wäre.
Ist das Interrupt-Bit jedoch gelöscht, so wird der IRQ ausgeführt.
3 . Der Programmzähler wird auf den Stack geschrieben.
4 . Das Statusregister wird gestackt.
5 . Nun wird das Interrupt-Flag gesetzt, so daß alle nachfolgenden Interrupt-Anforderungen ignoriert werden. Man bezeichnet diesen Vorgang als ' Sperren' des IRQ.
6 . Der Inhalt der Adressen $ FFFE und $ FFFF wird zusammengesetzt und als neuer Programmzähler benutzt.
Der Hauptunterschied zwischen NMI und
IRQ liegt darin, daß der IRQ maskiert
( d. h. gesperrt) werden kann.
Wie oben bereits beschrieben, wird beim
IRQ zuerst das I-Flag untersucht und
erst daraufhin entschieden, ob ein
Interrupt auszuführen ist, oder nicht.
Dieses Interrupt-Flag des maskierten
Interrupts IRQ kann vom Programmierer
selbst direkt beeinflußt werden.
Mit dem Befehl SEI ( SEt Interrupt mask) wird das I-Flag gesetzt und somit werden
alle folgenden IRQs gesperrt. Durch CLI( CLear Interrupt mask) kann dieser
Zustand wieder aufgehoben werden, indem
das I-Flag gelöscht wird. Ein IRQ ist
nun für den nachfolgenden Programmteil
wieder zugelassen. Häufige Anwendung
finden diese beiden Befehle auch beim
Umschalten der Speicherkonfiguration
durch den Prozessorport. Ohne das
vorherige Abschalten der Interrupts
mittels SEI kann es beim Ausschalten von
ROM-Berichen zum Systemabsturz kommen.
Wodurch können die Interrupt IRQ und NMI
ausgelöst werden ?
Selbstverständlich nur durch die Hardware des Computers:
IRQ: a) durch den Videocontroller VIC b) durch den CIA-Baustein ($ DC00)
NMI: a) durch den CIA-Baustein ($ DD00) b) durch die RESTORE-Taste
Der Software-Interrupt
Software-Interrupts werden durch den
Befehl BRK ( BReaK) ausgelöst. Das war
einer der ersten Befehle, die wir in
diesem Kurs kennengelernt haben. Nun
wollen wir untersuchen, was genau
passiert, wenn der Prozessor auf einen
BRK-Befehl im Programm stößt:
1 . Das Break-Flag ( Bit 4 des Statusregisters) wird gesetzt.
2 . Der Programmzähler wird auf den Stack
gebracht.
3 . Das Statusregister wird gestackt.
4 . Nun wird das Interrupt-Flag gesetzt, so daß alle IRQs gesperrt werden.
5 . Der Inhalt der Adressen $ FFFE und $ FFFF ( dieselben Adressen wie beim IRQ) wird zusammengesetzt und als neuer Programmzähler benutzt.
Meistens wird der BRK-Interrupt von den
Assembler-Monitoren dazu genutzt, um das laufende Programm abzubrechen und das
Statusregister mit den aktuellen Flags
anzuzeigen. Es wäre aber auch eine
andere Nutzung dieses Interrupts
möglich.
Der Software-Interrupt BRK wird also
im Gegensatz zu den Hardware-Interrupts
durch einen Assembler-Befehl ausgelöst.
Egal, ob IRQ, NMI oder der Softwareinterrupt BRK. Eines haben alle
gemeinsam. Sie lesen alle einen Zeiger
aus ($ FFFE/ FFFF bei IRQ, BRQ;$ FFFA/$ FFFB
bei NMI) der auf eine ROM-Routine weist.
Diese ROM-Routinen werden nun als
Interruptprogramm abgearbeitet und
führen am Ende einen unbedingten Sprung
aus. Dieser unbedingt e Sprung beruft
sich auf einen Zeiger, der im RAM steht.
Diese Zeiger sind: für IRQ $0314/$0315 für BRK $0316/$0317 für NMI $0318/$0319
Diese Zeiger sind schon mit einem
bestimmten Wert initialisiert, so daß
der Sprung ohne unser Eingreifen bestens
funktioniert. Wie Sie schon ahnen
werden, müssen wir diesen Zeiger
lediglich auf unsere selbstgeschriebenen
Routinen umbiegen, und schon haben wir
eigene Interruptroutinen.
Das Ende der Interrupts: RTI
Wenn das Programm durch einen Interrupt
unterbrochen wurde und der Prozessor nun
eine Interrupt-Routine bearbeitet, dann
muß ihm auch irgendwie kenntlich gemacht
werden, wann diese Unterbrechung beendet
werden soll. Auch die Interruptroutinen
benötigen daher ein Programmende. Für
' normale' Programme haben wir als
Kennzeichnung für das Programmende immer
den RTS-Befehl ( ohne vorherigen
JSR-Befehl) im Hauptprogramm benutzt, wodurch wir zurück ins BASIC kamen.
Der Befehl für das Ende unser selbstgeschriebenen Interrupt-Routine lautet RTI
( ReTurn from Interrupt) . Bei der Bearbeitung dieses Befehls läuft der
umgekehrte Prozeß des Interrupt-Aufrufs
ab.
1 . Das Statusregister muß vom Stack geholt werden.
2 . Der Programmzähler wird vom Stack geholt und wieder als aktueller Zähler benutzt.
3 . An der Stelle, auf die der Programmzähler zeigt, wird das unterbrochene Programm fortgeführt.
Der Hauptunterschied zwischen RTS und
RTI liegt darin, daß beim RTI zusätzlich
zum Programmzähler auch noch das Statusregister vom Stack geholt werden muß.
Ein Interrupt hat doch einige Ähnlichkeiten mit einem Unterprogrammaufruf.
Ein Unterprogramm wird jedoch von einer klar definierten Stelle im Hauptprogramm
( durch den JSR-Befehl) aufgerufen. Die
Interrupts NMI und IRQ werden jedoch
hardwaremäßig ausgelöst, so daß die
Unterbrechung des Hauptprogramms an
jeder beliebigen Stelle stattfinden
kann. Diese Eigenschaft erweckt den
Eindruck, daß die Interruptroutine und
das Hauptprogramm parallel arbeiten, was
aber natürlich nicht der Fall ist.
In dem Begleitprogramm
"ASSEMBLER-KURS10"
werden wir eigene Interrupt-Routinen
schreiben. Dabei geht es um die
Benutzung des Systeminterrupts und der
Interrupts durch den Videocontroller
( Rasterzeilen-Interrupt) .
Dies war der letzte Teil des Assembler-Kurses. Ich hoffe, er konnte Ihnen
einige Kenntnisse und Anregungen
verschaffen. rt/wk