Magic Disk 64

home to index to html: MD9101-KURSE-CIA-KURS_TEIL_3-2.html
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)
Valid HTML 4.0 Transitional Valid CSS!