CIA-Kurs: "Die Geheimnisse des Secret Service..." (Teil 2)
Herzlich willkommen zur zweiten Runde
unseres CIA-Kurses. Nachdem ich Sie
letzten Monat ja lange genug mit der
trockenen Theorie von der Bedienung der
Timer der CIAs gelangweilt habe, will
ich jetzt einmal den Grundstein zur Praxis legen. Ich möchte mich diesmal mit
dem eigentlichen Ablauf eines Interrupts
beschäftigen und Ihnen einen solchen
auch haarfitzelgenau anhand des Systeminterrupts erklären.
1) Der Prozessor und ein Interrupt.
Wie ich schon im letzten Teil erwähnte, wird der Systeminterrupt vom Betriebs
system des 64 ers zur Erledigung verschiedener zyklischer Aufgaben genutzt.
Er wird 60 mal in der Sekunde aufgerufen
und von Timer A der CIA1 erzeugt. Dem- nach haben wir also einen IRQ ( wir erinnern uns: CIA1 erzeugt Impulse an der
IRQ-Leitung des Prozsessors, CIA2 an der
NMI-Leitung) . Die Timerregister TALO und
TAHI beinhalten die Werte 37 und 64 . Der
Timer zählt also von 16421(= HI*256+ LO) bis 0 herunter und löst dann einen Interrupt aus. Das ist auch ganz logisch, denn wenn wir ja 60 Interrupts in der
Sekunde haben wollen, dann müssen wir ja
den Systemtakt durch 60 dividieren. Das
Ergebnis hiervon ist 16420 .8, aufgerundet 16421 ! Ich hoffe Sie verstehen
jetzt, warum ich mich zunächst um die
Timer selbst gekümmert hatte, da Sie nun
auch besseren Einblick in den Systeminterrupt haben. Wenn Sie einmal ein bisschen rumprobieren möchten, bitte:
Schreiben Sie doch einfach einmal mittels POKE einen höheren oder niedrigeren
Wert als 64 in TAHI ( Reg.5 von CIA1) .
Das Ergebnis sehen Sie dann am Cursorblinken, was ebenfalls vom Systeminterrupt erledigt wird. Der Cursor sollte nun entweder schneller ( bei niedrigerem
Wert) oder langsamer ( bei höherem Wert) blinken. Übertreiben Sie die Werte jedoch nicht übermäßig, da auch die Tastaturabfrage vom Systeminterrupt erledigt
wird, und Sie so entweder einen Turbo-Cursor haben, mit dem bei eingeschaltetem Key-Repeat ( das ist bei meinem
Floppy-Speeder- Betriebssystem nämlich
der Fall, und ich bin eben beim Ausprobieren natürlich prompt wieder darauf
hereingefallen. . .) keine vernünftigen
Eingaben gemacht werden können, ebenso
wie bei einem ultralangsamen Cursor, wo
es noch bis morgen dauern würde, einen
rücksetzenden POKE-Befehl einzugeben.
Dieser Trick wird übrigens oft benutzt, um Programme schneller zu machen. Je
öfter nämlich ein Interrupt pro Sekunde
auftritt, desto weniger Zeit hat der
Prozessor, das momentan laufende Hauptprogramm abzuarbeiten. Setzt man jedoch
die Zahl der Interrupts pro Sekunde herunter, oder schaltet man ihn sogar ganz ab ( indem man den Timer einfach anhält, oder mittels des Assemblerbefehls SEI
Interrupts ganz sperrt), so läuft das
Hauptprogramm logischerweise schneller
ab. Dies nur ein Tip am Rande.
Was geht nun eigentlich in unserem 64 er
vor, wenn ein Interrupt abgearbeitet
werden soll? Nun, zunächst einmal haben
wir da einen Unterlauf von Timer A der
CIA1 . Diese legt sodann auch gleich ein
Signal an die IRQ-Leitung des Prozessors
an und markiert die Interruptquelle " Timer A" in ihrem ICR.
Folgende Prozesse gehen nun im Prozessor
vor:
1) Der Prozessor überprüft nun nach jedem abgearbeiteten Befehl den Zustand
der Unterbrechungsleitungen ( IRQ, NMI) . Ist eine davon gesetzt, und ist
der zugehörige Interrupt auch freigegeben, so beginnt er damit, die Unterbrechung zu bearbeiten. Hierzu
müssen zunächst die wichtigsten Daten
auf den Stapel gerettet werden. Das sind in der hier gezeigten Reihenfol- ge: * HI-BYTE des Programmzählers * LO-BYTE des Programmzählers * Prozessorstatusregister
Der Programmzähler ist ein Prozessorinternes Register, das anzeigt, an
welcher Speicheradresse, der nächste
zu bearbeitende Befehl liegt. Das
Prozessorstatusregister beinhaltet
die Flaggen, die dem Prozessor bei
Entscheidungen weiterhelfen ( ich verweise da auf die letzten Kursteile
des Assemblerkurses meines Kollegen
RALF TRABHARDT) .
2) Der Prozessor setzt sich selbst das
Interrupt-Flag und verhindert so, daß er durch weitere Interrupts
gestört wird.
3) Ganz am Ende des Speichers ( in den
Adressen $ FFFA-$ FFFF) sind 6 Bytes
für das Interrupt-Handling reser- viert. Dort stehen insgesamt 3 Vektoren, die dem Prozessor zeigen, bei
welcher Unterbrechung er wohin springen muß, um einen Interrupt zu bearbeiten. Diese Vektoren heißen im
Fachjargon übrigens auch Hardware-Vektoren. Hier einmal eine Auflistung:
Interrupt Vektor Adresse
NMI $FFFA/$FFFB $FE43 (65091) RESET $FFFC/$FFFD $FCE2 (64738) IRQ,BRK $FFFE/$FFFF $FF48 (65352)
Da wir ja einen IRQ behandeln, holt
sich der Prozessor jetzt also die
Adresse, auf die der Vektor in
$ FFFE/$ FFFF zeigt in den Programmzähler und beginnt so damit eine Jobroutine für den IRQ abzuarbeiten.
Diese Jobroutine wollen wir uns jetzt einmal genauer ansehen. Vorher jedoch
noch eine kleine Erläuterung. Wie Sie ja
sehen, wird der Vektor für den IRQ auch
als Vektor für BRK-Unterbrechungen benutzt. Der BRK-Befehl sollte Ihnen ja
vielleicht bekannt sein ( wenn Sie sich
mit Maschinensprache auskennen) . Er hat
ansich ja keinen direkten Verwendungszweck, jedoch wird er von vielen Monitor- Programmen zum Debuggen benutzt. Wie
Sie ebenfalls sehen können, hat er gleiche Priorität wie ein IRQ, und man kann
Ihn also auch als eigenen Interrupt ansehen. Vielmehr ist der BRK-Befehl die
Unterbrechungsquelle für BRK-Interrupts.
Wie man mit ihm umgeht, will ich Ihnen
später zeigen.
Werfen wir nun jedoch einmal einen Blick
auf die Jobroutine ab $ FF48- diese befindet sich natürlich im Betriebssystem-ROM, weshalb ich Ihnen hier auch einen
Auszug daraus liefern möchte ( ich habe
dies in Form einer Grafik getan, damit ich ausführlichere Kommentare zu den
einzelnen Programmschritten geben kann) .
Bitte laden Sie hierzu den 2 . Teil des
CIA-Kurses.