Assembler-Kurs Teil 10 Wie versprochen, handelt der letzte Teil dieses Kurses von en Interrupts. Interrupt bedeutet soviel wie "Unter- brechung" des laufenden Programms. Der C64 reagiert auf verschiedene Arten von Interrupts, die man in Hard- und Soft- wareinterrups 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 Programm- zä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 zusammen- gesetzt und als neuer Programm- zä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 Hard- ware 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 Status- registers) 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 Software- interrupt 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 selbstge- schriebenen Interrupt-Routine lautet RTI (ReTurn from Interrupt). Bei der Bear- beitung 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 Programm- zä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 Status- register vom Stack geholt werden muß. Ein Interrupt hat doch einige Ähnlich- keiten 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