Magic Disk 64

home to index to text: MD9101-KURSE-CIA-KURS_TEIL_3-2.txt

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 Prozessorregister 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 verzweigt deshalb also auf das Label " L1" .
Dort wird jetzt geprüft, welcher Ausgabemodus 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 geblinkt 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. Somit 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 Jobroutine, 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 abgearbeitet wird, und der den Interrupt wieder beendet, indem er die alten Prozessorregister zurückholt und den Prozessor 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 Labelnamen gemacht.
Bei dem folgenden IRQ, zählt unsere Routine 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 System- IRQ springt. Dies geht nun 30 Interrupts lang so weiter, erst dann gibt es wieder eine 0 im COUNTER. Unsere Routine verzweigt jetzt wieder in die Ausgaberoutine. Dort wird wieder der Ausgabemodus 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 wiederholt, bis PULSE die 0 unterschreitet.
Dann nämlich wird nicht auf PRP verzweigt, sondern es werden gleich die Befehle hinter dem BPL-Befehl abgearbeitet. Sie setzen den IRQ-Vektor wieder auf den System-IRQ zurück, so daß also unsere eigene Routine nicht mehr angesprungen 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 ( letzten Monat hatte ich das ja genauer erklärt) .
Auch jetzt verzweigen wir wieder auf den System-IRQ um unseren Interrupt zu beenden.
Das wäre nun also eine Routine, die in den System-IRQ eingebunden ist. Das Betriebssystem springt sie direkt an, und sie selbst fährt nach ihrer eigenen Arbeit gleich mit dem System-IRQ fort. So daß dieser also auch weiterhin arbeitet.
Der Vorteil ist schnell ersichtlich.
Laden Sie doch einfach einmal das Programm " 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 Bildschirm, den wir auch weiterhin benutzen können. Würden wir unsere IRQ-Routine nicht über den System-IRQ wieder verlassen, wäre das auch nicht der Fall. Dadurch können Sie also während Ihren eigenen IRQs die Tastatur weiterhin verwenden!
Kommen wir nun zu einem weiteren Problem. Angenommen, Sie wollten eine Mitteilung ausgeben, wärend zum Beispiel gerade eine Routine damit beschäftigt ist, im RAM unter dem ROM Daten zu verschieben. In dem Fall können Sie ja nicht mehr über den System-IRQ springen, da das Betriebssystem-ROM ja abgeschaltet wäre. Man kann dies tun, indem man einige Bits im Prozessorport verändert.
Dieser wird durch die Speicherzelle $0001 repräsentiert. Dort steht normalerweise der Wert 55(=$37), was für den Prozessor die Speicherkonfiguration:

* BASIC-ROM bei $ A000-$ BFFF eingeschaltet.

* 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 BASICund dem Betriebssystem-ROM zugreifen, 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 wieder 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 auskommt. Der Source-Code hierzu ist ebenfalls auf dieser MD zu finden, unter dem Namen " MSGOUT-RAM. SRC" . Im Prinzip brauchen wir nur ein paar Befehle zu der ROM-Version von MSGOUT hinzuzufügen, um die RAM-Version zu erhalten. Das wichtigste ist hierbei die Initialisierungsroutine, die ich Ihnen hier nun aufführen 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 verschwindet 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, sondern 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 geschriebenen 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 Initialisierungsroutine dann auch noch den Prozessorport so, daß BASICund 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 Abschnitt. Wir können nämlich unsere Initialisierungsroutine nicht einfach so verlassen - zumindest nicht in diesem Beispiel. Denn normalerweise, wenn Sie sich im Eingabemodus des 64 ers 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 einfach ab. Da ich die IRQ-Routine nun aber so programmiert habe, daß sie automatisch, wenn sie genug geblinkt hat, BA-SIC und Betriebssystem wieder einschaltet, können wir dies als Kennzeichen dafür nehmen, daß die Grundvoraussetzungen für ein Verlassen der Initialisierungsroutine wieder gegeben sind. Deshalb 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 Arbeit unter dem ROM. Kommen wir nun zur Interrupt-Routine selbst. Auch sie muß leicht modifiziert werden. Auch hier will ich einen kurzen Abriß der hinzugefü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ämlich darum geht, den Interrupt wieder abzuschalten, weil wir oft genug geblinkt 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 eingeschaltet. Ein Zurückbiegen von Vektoren entfällt, da das ROM ja nun wieder da ist, und von nun an der System-IRQ wieder 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! Demnach 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 entfernt, und dafür eine eigene SYSIRQ-Routine geschrieben. Der Name entspricht zwar nicht mehr dem, was vorher die Bedeutung war ( SYStem-IRQ), aber so ging es halt am einfachsten.
Diese neue Routine tut nun nichts anderes, 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 $ EA7 E. 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 Ihnen 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 runter, bevor wir den Interrupt mit RTI beenden.
So. Das war' s dann mal wieder für diesen Monat. Noch einen Hinweis zu den Programmen bezüglich dieses Kurses:

* Die beiden Source-Codes der MSGOUT-Routine können Sie übrigens auch lesen, wenn sie nicht den HYPRA-ASS besitzen. 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 beide 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 verabschieden. 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)

Valid HTML 4.0 Transitional Valid CSS!