Hier die Erklärung:
Nachdem wir die Initialisierungsroutine
von vorhin aufgerufen haben, zeigt der
IRQ-Vektor jetzt also auf die Routine
"IRQ". Die CIA1 signalisiert nun einen
Timerunterlauf in Form eines Signals an
den Prozessor. Dieser springt daraufhin
auf die Jobroutine ab $FF47, wo die Pro-
zessorregister auf den Stapel gerettet
werden und über den IRQ-Vektor unsere
Routine angesprungen wird.
Diese erniedrigt nun also den COUNTER
und prüft, ob er schon 0 ist. Das ist
der Fall, da wir den COUNTER ja mit 1
initialisiert hatten, und er soeben auf
0 abgezählt wurde. Das Programm verz-
weigt deshalb also auf das Label "L1".
Dort wird jetzt geprüft, welcher Ausga-
bemodus eingestellt ist. Da MSGMODE auf
1 steht gehts jetzt also gleich weiter
zu "L2", wo zunächst einmal MSGMODE auf
0 gezählt wird. Durch einen Aufruf von
"BLANK" wird die MSG-Zeile gelöscht.
Dies heißt für uns auch, daß einmal ge-
blinkt wurde. Also müssen wir jetzt den
Zähler für die Anzahl der Blinks um 1
erniedrigen. Gehen wir einmal davon aus,
daß wir die Initialisierungsroutine mit
einer 10 im Akku aufgerufen hatten. So-
mit ist der Inhalt von PULSE jetzt, nach
dem Herunterzählen 9. Das heißt, daß die
0 noch nicht unterschritten wurde und
deshalb wird beim folgenden Branch-
Befehl auch gleich auf das Label PRP
verzweigt. Dort steht eine kleine Job-
routine, die unseren IRQ wieder beendet.
Der COUNTER wird hier mit 30 neu geladen
und das Programm verzweigt anschließend
auf den System-IRQ, der nun regulär ab-
gearbeitet wird, und der den Interrupt
wieder beendet, indem er die alten Pro-
zessorregister zurückholt und den Pro-
zessor mittels RTI wieder in das alte
Programm, das bearbeitet wurde, als der
Interrupt auftrat, zurückschickt.
Das Label SYSIRQ beinhaltet also die
Sprungadresse des System-IRQs, wie Sie
anhand des Source-Codes erkennen können.
Ich habe dort nämlich wieder mittels
".EQ" eine Zuweisung an diesen Labelna-
men gemacht.
Bei dem folgenden IRQ, zählt unsere Rou-
tine wieder den COUNTER um 1 herunter.
Diesmal jedoch, ist diese Speicherzelle
noch nicht 0, weshalb die Routine auch
nicht in die Ausgaberoutine ab "L1"
verzweigt, sondern gleich auf den Sy-
stem-IRQ springt. Dies geht nun 30 In-
terrupts lang so weiter, erst dann gibt
es wieder eine 0 im COUNTER. Unsere Rou-
tine verzweigt jetzt wieder in die Aus-
gaberoutine. Dort wird wieder der Ausga-
bemodus geprüft, der diesmal jedoch 0,
also "Text ausgeben" ist. Dort müssen
wir jetzt MSGMODE dann auf 1 hochzählen
und dann mittels DOMSG unsere Mitteilung
auf dem Bildschirm ausgeben. Anschlie-
ßend können wir den Interrupt wieder
über den System-IRQ verlassen.
Diese Vorgänge werden nun solange wie-
derholt, bis PULSE die 0 unterschreitet.
Dann nämlich wird nicht auf PRP ver-
zweigt, sondern es werden gleich die
Befehle hinter dem BPL-Befehl abgearbei-
tet. Sie setzen den IRQ-Vektor wieder
auf den System-IRQ zurück, so daß also
unsere eigene Routine nicht mehr ange-
sprungen wird. Ihre Aufgabe ist nun
erfüllt.
Diesmal brauchen wir das Interrupt-Flag
übrigens nicht zu setzen, da innnerhalb
eines Interrupts dieses Flag ja schon
durch den Prozessor gesetzt wurde (letz-
ten Monat hatte ich das ja genauer
erklärt).
Auch jetzt verzweigen wir wieder auf den
System-IRQ um unseren Interrupt zu been-
den.
Das wäre nun also eine Routine, die in
den System-IRQ eingebunden ist. Das Be-
triebssystem springt sie direkt an, und
sie selbst fährt nach ihrer eigenen Ar-
beit gleich mit dem System-IRQ fort. So
daß dieser also auch weiterhin arbeitet.
Der Vorteil ist schnell ersichtlich.
Laden Sie doch einfach einmal das Pro-
gramm "MSGOUT.CODE" auf der Vorderseite
dieser MD. Es ist ein Assembler-
Programm, das mit "SYS 4096*8", oder
"SYS 32768" aufgerufen wird. Der MSG-
Text "DAS IST EIN IRQ UEBERS BETRIEBS-
SYSTEM!" blinkt nun in der untersten
Bildschirmzeile. Währenddessen haben wir
aber immer noch den Cursor auf dem Bild-
schirm, den wir auch weiterhin benutzen
können. Würden wir unsere IRQ-Routine
nicht über den System-IRQ wieder verlas-
sen, wäre das auch nicht der Fall. Da-
durch können Sie also während Ihren ei-
genen IRQs die Tastatur weiterhin ver-
wenden!
Kommen wir nun zu einem weiteren Pro-
blem. Angenommen, Sie wollten eine Mit-
teilung ausgeben, wärend zum Beispiel
gerade eine Routine damit beschäftigt
ist, im RAM unter dem ROM Daten zu ver-
schieben. In dem Fall können Sie ja
nicht mehr über den System-IRQ springen,
da das Betriebssystem-ROM ja abgeschal-
tet wäre. Man kann dies tun, indem man
einige Bits im Prozessorport verändert.
Dieser wird durch die Speicherzelle
$0001 repräsentiert. Dort steht norma-
lerweise der Wert 55 (=$37), was für den
Prozessor die Speicherkonfiguration:
* BASIC-ROM bei $A000-$BFFF eingeschal-
tet.
* I/O-Bereich bei $D000-$DFFF (wo auch
die Register der beiden CIAs liegen)
eingeschaltet.
* Betriebssystem-ROM bei $E000-$FFFF
eingeschaltet.
Wollen wir nun auf das RAM unter dem
BASIC- und dem Betriebssystem-ROM zu-
greifen, so kann man letztere mit dem
Schreiben des Wertes 53 (=$35) in den
Prozessorport abschalten. Das I/O-ROM,
das wir ja noch brauchen (wegen der
CIA1), bleibt dabei eingeschaltet.
Der System-IRQ ist somit nicht mehr für
uns vorhanden und ebenso auch nicht die
Jobroutine, die über den IRQ-Vektor
$0314/$0315 auf entsprechende IRQ-
Routinen springt.
In dem Fall müssen wir die Steuerung des
Interrupts selbst bewältigen. Das heißt
zunächst einmal, daß wir diesmal die
Prozessorregister selbst retten müssen
(was ja normalerweise die Jobroutine bei
$FF47 macht - siehe Teil 2 des CIA-
Kurses), und sie auch entsprechend wie-
der zurückholen müssen. Als IRQ-Vektor
zählt jetzt auch nicht mehr der bei
$0314/$0315, sondern wir benutzen den
Hardware-Vektor direkt. Da das ROM dort
ja abgeschaltet ist, können wir also
problemlos die Speicherzellen
$FFFE/$FFFF mit einem Vektor auf unsere
IRQ-Routine beschreiben.
Zur Demonstration habe ich Ihnen unsere
MSGOUT-Routine einmal umgeschrieben, so
daß sie auch ohne Betriebssystem aus-
kommt. Der Source-Code hierzu ist eben-
falls auf dieser MD zu finden, unter dem
Namen "MSGOUT-RAM.SRC". Im Prinzip brau-
chen wir nur ein paar Befehle zu der
ROM-Version von MSGOUT hinzuzufügen, um
die RAM-Version zu erhalten. Das wich-
tigste ist hierbei die Initialisierungs-
routine, die ich Ihnen hier nun auffüh-
ren möchte:
------------
SEI Interrupts wie immer speren.
STA PULSE Blinkzähler merken.
STX LOOP1+1 Anfangsadresse des...
STY LOOP1+2 ...Textes merken.
------------
LDX #<(IRQ) Anfangsadresse der neuen...
LDY #>(IRQ) ...IRQ-Routine laden.
STX $FFFE Und den Hardware-Vektor...
STY $FFFF ...darauf ausrichten.
------------
LDA #$35 Wert für "ROM aus" laden...
STA $01 ...und ab in Prozessorport.
------------
LDA #01 Initialisierungswert laden.
STA COUNTER Zähler initialisieren.
STA MSGMODE Modus initialisieren.
CLI IRQs wieder freigeben.
------------
LOOP3:
LDA $01 Prozessorport laden.
CMP #$37 Vergleiche mit "ROM an".
BNE LOOP3 Ungleich, also weiter prü-
fen.
RTS Ansonsten Tschüß!
------------
Viel hat sich hier ja nicht geändert.
Den ersten Abschnitt kennen wir ja noch
von der alten MSGOUT-Routine. Diesmal
müssen wir jedoch noch aus einem zweiten
Grund die Interrupts sperren. Indem wir
nämlich später noch das Betriebssystem-
ROM abschalten, nehmen wir dem Prozessor
die Grundlage für IRQs. Zum Einen ver-
schwindet somit nämlich der Hardware-
Vektor des Betriebssystems, zum Anderen
auch alle Jobroutinen für den System-
IRQ. Der Prozessor springt dann irgendwo
im undefinierten RAM rum und hängt sich
dann unweigerlich auf. Also jetzt geht
nix mehr ab mit IRQs!
Der zweite Abschnitt ist uns auch nicht
so unbekannt. Diesmal setzen wir jedoch
nicht den IRQ-Vektor $0314/$0315, son-
dern den Hardware-Vektor für IRQs bei
$FFFE/$FFFF. Das können wir getrost auch
bei eingeschaltetem ROM tun (wie das
hier der Fall ist), denn die geschriebe-
nen Daten landen auf jedem Fall im RAM,
da der Prozessor ins ROM ja nicht
schreiben kann. Weil er aber irgendwo
hin muß mit seinen Daten, schickt er sie
automatisch ins RAM. Nur der Lesezugriff
kommt aus dem ROM!
Um auch dies zu ändern, verändern wir im
dritten Abschnitt der Initialisierungs-
routine dann auch noch den Prozessorport
so, daß BASIC- und Betriebssystem-ROM
abgeschaltet werden.
Im vierten Abschnitt werden jetzt noch
die variablen Register unserer IRQ-
Routine initialisiert. Hier hat sich
nichts geändert.
Wichtig ist nun noch der letzte Ab-
schnitt. Wir können nämlich unsere Ini-
tialisierungsroutine nicht einfach so
verlassen - zumindest nicht in diesem
Beispiel. Denn normalerweise, wenn Sie
sich im Eingabemodus des 64ers befinden,
wird eine Eingabeschleife des BASICs
durchlaufen, die ständig auf Eingaben
prüft und dann bei entsprechenden BA-
SIC-Befehlen, diese aufruft. Wenn Sie
also mit SYS unsere IRQ-Routine starten,
dann wird die Initialisierngsroutine
nach ihrer Arbeit wieder in die BASIC-
Eingabeschleife zurückkehren wollen. Die
ist jetzt jedoch nicht mehr verfügbar,
weil wir ja das BASIC-ROM abgeschaltet
haben. Auch hier springt der Prozessor
dann mitten ins leere RAM, verläuft sich
dort und stürzt vor lauter Kummer ein-
fach ab. Da ich die IRQ-Routine nun aber
so programmiert habe, daß sie automa-
tisch, wenn sie genug geblinkt hat, BA-
SIC und Betriebssystem wieder einschal-
tet, können wir dies als Kennzeichen
dafür nehmen, daß die Grundvoraussetzun-
gen für ein Verlassen der Initialisie-
rungsroutine wieder gegeben sind. Des-
halb also, habe ich eine Warteschleife
hier eingebaut, die immer nur prüft, ob
die ROMs mittlerweile wieder da sind.
Erst wenn dieser Fall eintritt, wird
zurückgesprungen!
Soviel zur Initialisierung für eine Ar-
beit unter dem ROM. Kommen wir nun zur
Interrupt-Routine selbst. Auch sie muß
leicht modifiziert werden. Auch hier
will ich einen kurzen Abriß der hinzu-
gefügten Befehle geben:
------------
IRQ PHA Akku retten.
TXA X-Reg. in Akku schieben...
PHA ...und retten.
TYA Y-Reg. in Akku schieben...
PHA ...und retten.
------------
(etc...)
So fängt nun die neue IRQ-Routine an.
Anschließend folgen genau die Befehle,
die auch in MSGOUT-ROM verwedet wurden.
Bis auf einen Unterschied: wenn es näm-
lich darum geht, den Interrupt wieder
abzuschalten, weil wir oft genug ge-
blinkt haben, lautet die Abschaltroutine
folgendermaßen:
------------
LDA #$37 Alte Speicherkonfiguration
STA $01 wieder einschalten.
JMP SYSIRQ Und IRQ beenden,
------------
Hier wird einfach das ROM wieder einge-
schaltet. Ein Zurückbiegen von Vektoren
entfällt, da das ROM ja nun wieder da
ist, und von nun an der System-IRQ wie-
der treu seine Dienste leistet, so, als
wäre nichts geschehen.
Nach dieser Änderung des Prozessorports
ist auch die Bedingung der Warteschleife
der Initialisierungsroutine erfüllt,
womit diese sogleich wieder zum guten
alten BASIC zurückspringt.
Eins muß ich jedoch noch hinzufügen. Wie
sie ja noch wissen, verzweigt die ganze
Routine ja noch öfter auf den System-
IRQ, der dann ja gar nicht da ist! Dem-
nach hätte ich diese Verzweigungen, die
ich vorhin so leichtfertig übersprungen
habe, ja erwähnen müssen!
Nun, ich habe dieses Problem anders
gelöst. Ich habe nämlich den ".EQ"-
Pseudo-Opcode von "HYPRA-ASS", mit dem
ich dem Label "SYSIRQ" die Adresse
"$EA31" zuwies aus dem Source-Code ent-
fernt, und dafür eine eigene SYSIRQ-
Routine geschrieben. Der Name entspricht
zwar nicht mehr dem, was vorher die Be-
deutung war (SYStem-IRQ), aber so ging
es halt am einfachsten.
Diese neue Routine tut nun nichts ande-
res, als den Interrupt ordnungsgemäß zu
beenden. Wie wir ja noch aus dem letzten
CIA-Kurs wissen, tut dies der System-IRQ
am Ende auch. Die entsprechenden Befehle
hierzu stehen ab Adresse $EA7E. Genau
die habe ich nun in die neue "IRQ-
Beenden"-Routine übernommen:
-----------------
SYSIRQ LDA $DC0D ICR von CIA1 löschen.
PLA Altes Y-Reg. vom Sta-
pel in Akku holen...
TAY ...und zurück in Y-
Reg. schieben.
PLA Altes X-Reg. vom Sta-
pel in Akku holen...
TAX ...und zurück in X-
Reg. schieben.
PLA Alten Akkuinhalt vom
Stapel holen.
RTI Und Interrupt beenden.
-----------------
Die Bedeutung dieser Befehle sollte Ih-
nen ja noch bekannt sein. Zunächst müs-
sen wir weitere IRQs durch Löschen des
ICR-Registers der CIA1 wider ermöglichen
(dadurch werden ja die Interrupt-
Quellen-Flags gelöscht, wie wir aus Teil
1 dieses Kurses noch wissen). Dann holen
wir uns in umgekehrter Reihenfolge die
Prozessorregister wieder vom Stapel run-
ter, bevor wir den Interrupt mit RTI
beenden.
So. Das war's dann mal wieder für diesen
Monat. Noch einen Hinweis zu den Pro-
grammen bezüglich dieses Kurses:
* Die beiden Source-Codes der MSGOUT-
Routine können Sie übrigens auch le-
sen, wenn sie nicht den HYPRA-ASS be-
sitzen. Laden Sie hierzu ein Source-
Code-File einfach an den BASIC-Anfang
(also mit ",8" am Ende) und geben Sie
LIST ein. Jetzt wird der Text zwar
nicht automatisch formatiert, so wie
HYPRA-ASS das normalerweise tut, aber
lesen kann man das ganze schon. Zur
Anschauung genügt es zumindest.
* Das File "MSGOUT-CODE" beinhaltet bei-
de Versionen von MSGOUT. Laden Sie es
bitte absolut (also mit ",8,1") und
starten Sie die einzelnen Routinen
mit:
- SYS 32768 für MSGOUT-ROM
- SYS 32777 für MSGOUT-RAM
Ich will mich jetzt von Ihnen verab-
schieden. Nächsten Monat wollen wir uns
dann einmal um die Kupplung von Timer A
und Timer B einer CIA kümmern und auch
noch den BRK-Interrupt behandeln. Bis
dahin noch viel Spaß beim Herumprobieren
mit IRQs.
(ub)