Magic Disk 64

home to index to text: MD9006-KURSE-INTERRUPTKURS_TEIL_1.txt
MD9006-KURSE-INTERRUPTKURS_TEIL_1.koala.png
     DEN C64'er AUSGEREIZT (Teil 1)     
             INTERRUPTKURS              
             

Mehr als 8 Sprites gleichzeitig, Grafiken im Rand des Bildschirms, mehr als 16 Farben, skurrile Verfremdung von Bildern und eine schier endlos scheinende Flut von phantastischen Spezialeffekten gehören heutzutage einfach zum Standard der Programmierkunst auf dem C'64 .
Wer hat da nicht schon einmal mit dem Gedanken gespielt, sich selbst an die Programmierung solcher Wunderdinge heranzuwagen.
Nimmt man sich die Zeit, Laufschriften von Demos durchzulesen oder lauscht man der hitzigen Unterhaltung eingefleischter Freaks, so stößt man immer wieder auf Wörter wie Raster-Routine, Sideborder-Sprites, FLD-, FID-, und DYSP-ROUTINEN, die man auch mit der größter Anstrengung in der angebotenen Fachliteratur einfach nicht finden kann.
Selbstverständlich gibt es Bücher, die sich mit Interrupteigenschaften ihres Gerätes befassen. Sie werden allerdings feststellen, daß die meisten dieses Thema sehr kurz abhandeln und in der Regel ausgerechnet da aufhören, wo es anfängt spannend zu werden. Das völlige Fehlen geeigneter Literatur liegt einerseits an der mangelde Kenntnis des Sachverhaltes und andererseits an der relativ späten Entdeckung dieser Fähigkeiten des C'64 .
Es sei hier noch erwähnt, daß es sich bei einigen Effekten die wir im Laufe dieses Kurses behandeln werden, nur um UNBEABSIGTIGTE Nebeneffekte der Chips handelt, die vom Hersteller nicht geplant waren und offiziell auch gar nicht existieren dürften. Das es sie aber dennoch gibt, haben wir einzig und allein der Experimentierfreudigkeit einiger Freaks zu verdanken.
Leider muß ich zum Verständnis der abgedruckten Programme Grundkennnisse der Hardware, der Maschinensprache und Erfahrung im Umgang mit einem Assembler oder einem Monitor voraussetzen, denn einen IRQ von BASIC aus zu programmieren ist prinzipiell nicht möglich.

 ALLGEMEINES ÜBER DIE INTERRUPTTECHNIK! 

Was ist ein Interrupt? Wie funktioniert er und wie kann ich ihn in meinen Programmen einsetzen? Dies sind die Fragen, die in der ersten Folge des Interruptkurses beantwortet werden sollen.
Was ein Interrupt ist, läßt sich einfach beantworten. Ein Interrupt ist eine gesteuerte Unterbrechung und bedeutet, daß spezielle Chips oder Befehle die Arbeit des Rechners jederzeit unterbrechen können und ihn dazu zwingen, andere Routinen auszuführen. Insgesamt gibt es VIER verschiedene IRQ-Möglichkeiten, die in sich selbst noch unterteilt sind.

  1-RESET                               
  2-BRK (Break) INTERRUPT               
  3-CIA INTERRUPTS (IRQ-CIA und NMI-CIA)
  4-VIDEO INTERRUPT                     
           DER RESET-INTERRUPT          
           

Dieser Interrupt wird gleich nach dem Einschalten des Computers oder nach dem drücken einer Resettaste ausgelöst. Ich möchte aber darauf hinweisen, daß es sich hierbei nicht um eine Unterbrechung im eigentlichen Sinne handelt, sondern wie der Name schon sagt:
to reset= zurücksetzen um einen totalen ABBRUCH eines laufenden Programmes, gefolgt von einem neuinitialisieren des gesamten Rechners. Mit dem RESET als Unterbrechung wollen wir uns im Laufe dieses Kurses auch nicht weiter beschäftigen.

            DER BRK-INTERRUPT           
            

Als nächstes gibt es die Möglichkeit, mit der Hilfe des Assemblerbefehls ' BRK' einen Interrupt durch den Prozessor selbst auszulösen. Dieser Interrupt wird auch als Software-IRQ bezeichnet. Da es sich hierbei gleichzeitig um einen der einfachsten Unterbrechungsarten handelt, ist sie wie geschaffen, um an einem einfachen Programmbeispiel den gewöhnlichen Verlauf eines Interrupts zu demonstrieren. Für den BRK sind die folgenden Adressen von Bedeutung.
$0316 Lo-Byte des BREAK-Vektors $0317 Hi-Byte des BREAK-Vektors Diese Register befinden sich im RAM und sind somit veränderbar. Das folgende Programmbeispiel soll dies verdeutlichen.
BRK-Demo:

 1000 LDA #$17  Lo-Byte des BRK-Vektors 
 1002 STA $0316 umstellen.              
 1005 LDA #$10  Hi-Byte des BRK-Vektors 
 1007 STA $0317 umstellen.              
 100A BRK       Starten des IRQ         
 --------------------                   
 100B NOP                               
 100C LDA #$0E  Rahmenfarbe rücksetzen  
 100E STA $D020 rücksetzen              
 1011 LDA #$06  Hintergrundfarbe        
 1013 STA $D021 rücksetzen              
 1016 RTS       Rücksprung zu Basic     
 1017 INC $D020 Rahmenfarbe ändern      
 101A LDA $DC01 PORT B auslesen         
 101D CMP #$EF  prüfen ob SPACE gedrückt
 101F BNE LOOP  Nein ?? dann $1017      
 1021 PLA       Y-Reg. vom Stack holen  
 1022 TAY                               
 1023 PLA       X-Reg. vom Stack holen  
 1024 TAX                               
 1025 PLA       Akku vom Stack holen    
 1026 RTI       Interrupt verlassen     

Wird dieses Programm mit ' SYS 4096' gestartet, beginnt sich die Rahmenfarbe fortlaufend zu ändern. Drückt man anschließend die SPACE-Taste, so meldet sich der Rechner mit ' READY' wieder.
Nachdem wir unsere Routine gestartet haben, wird als erstes Lound Hi-Byte des Break-Vektors ( welche Bedeutung jene Register im einzelnen haben, wird anschließend geklärt) auf die Adresse $1017 gerichtet. Der Interrupt wird ausgelöst, sobald der Prozessor auf den BRK Befehl stößt. Was dabei im Rechner vorgeht, läßt sich in vier Punkte gliedern:
1 . Als erstes wird im STATUSREGISTER das BREAK-FLAG gesetzt, um dem Prozessor die Art des Interrups mitzuteilen. Anschließend wird Hiund Lo-Byte des PROGRAMMCOUNTERS auf den Stack abgelegt, d. h. der Prozessor merkt sich die Adresse, an der er den letzten Befehl ausgeführt hat. Das Gleiche geschieht übrigens auch bei einem ' JSR' Befehl.
Dies ist sehr wichtig, denn nur so kann der Rechner seine Arbeit nach Beendigung des Interrups wieder fortsetzen.
In unserem Beispiel merkt er sich also die Adresse:$100 A+$0002=$100 C.
Das zu der aktuellen Unterbrechungsadresse noch der Wert $02 dazuaddiert wird, ist eine Außnahme, die bei anderen Unterbrechungen nicht vorkommt.
2 . Um die FLAGS zu retten, wird zusätzlich noch das komplette STATUSREGISTER auf dem Stack abgelegt.
3 . Anschließend verzweigt der Rechner indirekt über die Adressen $ FFFE/$ FFFF in die ROM-Routine bei $ FF48 . An dieser Stelle findet man folgendes Programm vor.
FF48 PHA Akku auf Stack retten FF49 TXA FF4 A PHA X-Reg. auf Stack retten FF4 B TYA FF4 C PHA Y-Reg. auf Stack retten FF4 D TSX Stackpointer ins X-Reg.
FF4 E LDA $0104, X Statusregister in Akku FF51 AND #$10 BREAK-Flag prüfen FF53 BEQ FF58 nicht gesetzt? Dann FF58 FF55 JMP ($0316) sonst Break-INTERRUPT FF58 JMP ($0314) Timer-IRQ Diese Routine entscheidet, ob es sich bei der Art des Interrups um einen TIMERoder, wie in unserem Fall, um einen BREAK-INTERRUPT handelt. Handelt es sich um den Letzteren, dann wird zu der Routine verzweigt, auf welche die Register $0316/$0317 zeigen. Da wir nun zuvor beide Register auf die Adresse $1017 gerichtet haben, wird nun unsere eigene IRQ-Routine angesprungen. Diese macht sich auch augenblicklich durch ändern der Rahmenfarbe bemerkbar.
4 . Um das Interruptprogramm wieder zu verlassen, drücken wir einfach die Space-Taste. Als erstes werden die Werte für Akku und die beiden Register X und Y vom Stack geholt. Um den Interrupt endgültig zu beenden, gibt es den Befehl RTI( Return from Interrupt), was zu deutsch ungefähr soviel bedeutet wie ' Verlassen der Unterbrechungsebene' . Trifft der Prozessor nun auf einen ' RTI' Befehl, dann werden als erstes STATUSREGISTER und PROGRMM-COUNTER von Stack geholt und der Programmablauf kann an der Adresse $100 c fortgesetzt werden.
Im Gegensatz zu anderen IRQ-Arten, bietet der BRK-INTERRUPT in der Praxis relativ wenige Anwendunggebiete. Man könnte ihn eigentlich problemlos als Unterprogrammbefehl einsetzen, allerdings ist dafür der ' JSR' Befehl wesentlich besser geeignet, da seine Handhabung nicht so umständlich ist. Eine wesentliche Rolle spielt der BRK bei Software-Instrumenten wie z. B. Maschinensprachemonitore. Hier werden die beiden Adressen $0316/$0317 so umgestellt, daß sie als Register-Indikatoren dienen.

           DER CIA-INTERRUPT            
           

Die folgenden Interrupt-Typen sind da schon wesentlich interresanter. Hierbei handelt es sich um sogenannte EXTERNE Unterbrechungen. In ihrem C-64 gibt es drei spezielle Chips, die aus einem bestimmten Grund den Prozessor zwingen die augenblickliche Tätigkeit zu unterbrechen und eine andere Aufgabe auszuführen. Hierzu gehören die beiden CIA-Chips und der Video-Chip.
Selbstverständlich geschehen diese Unterbrechungen nicht einfach aus heiterem Himmel, sondern können vom Programmierer kontrolliert und gezielt eingesetzt werden.
Beim BRK-IRQ konnten wir die Adresse, an der ein IRQ ausgelöst wird, ganz genau festlegen. Beim Timer-IRQ ist dies nicht ganz so einfach, weil hier die Unterbrechung nicht mehr vom Prozessor selbst eingeleitet wird sondern von einem Chip, der gleich zweimal vorhanden ist. Gemeint ist der ' Complex Interface Adapter', auch unter der Kurzform CIA bekannt.
Der erste der beiden CIAs wird auch als ' IRQ-TIMER' oder' IRQ-CIA' bezeichnet. Er besitzt die Basisadresse $ DC00 und wird in erster Linie zur Verwaltung einiger Vorgänge im Betriebsystem benutzt.
Den zweiten CIA bezeichnet man als ' NMI-TIMER' . Er besitzt die Basisadresse $ DD00 und wird außer zur Verwaltung einer event. vorhandenen RS232 Schnittstelle vom Betriebsystem für keine bestimmte Aufgabe vorgesehen.
Jeder CIA besitzt zwei Intervalltimer, die aus einem 16- Bit Zähler ( read only) und einem 16- Bit Zwischenspeicher ( write only) bestehen. Daten, die in den Timer geschieben werden, landen im Zwischenspeicher, während die Lesedaten den augenblicklichen Stand des Zählers angeben. Die beiden Timer können sowohl unabhängig von einander, als auch im Zusammenhang benutzt werden. Die verschiedenen Betriebsarten erlauben das Erzeugen variabler Zeitverzögerungen.
Ein Intervalltimer ist mit einem Zeitlaufwerk vergleichbar, das kontinuierlich rückwärts zählt. Ist der COUNTDOWN dieses Zählers abgelaufen, d. h. der Zähler ist beim Wert Null angelangt, so wird ein Interrupt ausgelöst. Diese Möglichkeit wird beispielsweise vom Betriebssystem gezielt eingesetzt, um in regelmäßigen Abständen ( jede 1/60 Sekunde) den normalen Programmablauf zu unterbrechen und indirekt über die Adressen $0314/$0315 in eine ROM-Routine zu springen. Auf diese Weise wird die interne Uhr ( TI$) gestellt, die Tastatur abgefragt und das Blinken des Cursors erzeugt.
Da der C64 zwei CIA-Chips besitz, gibt es also insgesammt vier Intervalltimer, die man völlig unabhängig von einander oder im Zusammenhang einsetzen kann.
Das folgende Beispielprogramm soll die Arbeitsweise einer Timer-Unterbrechung, anhand einer nützlichen Anwendung verdeutlichen. Wir wollen einfach mit dem Joy-Stick in Port 2 ein Sprite über den Bildschirm bewegen. Allerdings soll dies ausschließlich im Interrupt geschehen.

1000 SEI       ;IRQ-sperren             
1001 LDX #$01  ;SPRITE Nr.1             
1003 STX $D015 ;einschalten             
1006 STX $D027 ;Farbe = weiß            
1009 LDA #$3F  ;SPRITE DATAS            
100b STA $07F8 ;von $3F*64 = $0FC0 holen
100e LDA #$64  ;X-,und Y-Position von   
1010 STA $D000 ;Sprite Nr.1 auf $64     
1013 STA $D001 ;setzen                  
1016 LDX #$0E  ;Rahmen und              
1008 LDY #$06  ;Hintergrund             
101a STX $D020 ;auf 'blau' setzen       
101d STY $D021                          
1020 LDX #$36  ;Lo-und Hi-byte          
1022 LDY #$10  ;des IRQ-Vektors auf die 
1024 STX $0314 ;Interrupt-Routine       
1027 STY $0315 ;richten                 
102a LDX #$25  ;Lo-und Hi-Byte          
102c LDY #$40  ;von Intervalltimer A    
102e STX $DC04 ;setzen                  
1031 STY $DC05                          
1034 CLI       ;Interrupt erlauben      
1035 RTS       ;Rücksprung zu Basic     

1036 LDA $ DC00 ; Joy-Stick Register 21039 LSR ; prüfen ob Bit 1 gelöscht 103 A BCS $103 F ; Nein? Dann verzweigen!
103 C DEC $ D001 ; sonst Sprite aufwärts 103 F LSR ; prüfen ob Bit 2 gelöscht 1040 BCS $1045 ; Nein? Dann verzweigen!
1042 INC $ D001 ; sonst Sprite abwärts 1045 LSR ; prüfen ob Bit 3 gelöscht 1046 BCS $104 B ; Nein? Dann verzweigen!
1048 DEC $ D000 ; sonst Sprite nach links 104 B LSR ; prüfen ob Bit 4 gelöscht 104 C BCS $1051 ; Nein? Dann verzweigen!
104 E INC $ D000 ; sonst Sprite nach rechts 1051 JMP $ EA31 ; Sprung zum IRQ-Ende!
Starten sie dieses Programm mit ' SYS 4096', dann erscheint ein Sprite links im Bildschirm und der Rechner meldet sich mit ' READY' und einem blinkendem Cursor wieder. Außer einem Sprite und einem blauen Bildschirm läßt sich auf den ersten Blick auch nichts ungewöhnliches erkennen. Was man jedoch noch nicht sehen kann, ist, daß analog zu den Standardfunktionen eine kleine Routine im Interrupt abläuft, die nur auf ein Signal vom Joy-Stick wartet.
Bewegen Sie einfach mal den Steuerknüppel und Sie werden merken, daß sich das Sprite in alle Richtungen steuern läßt.
Was sie hier sehen ist, eine typische, kontrollierte Unterbrechung, wie sie zu Beginn des Artikels beschrienen wurde.
Man hat den Eindruck, daß Eingaben über die Tastatur und die Joy-Stick Abfrage, quasi gleichzeitig ablaufen. Daß dies nicht der Fall ist, werden wir gleich erkennen.
Die ersten Befehle, bis einschließlich Adresse'$101 D' initialisieren Sprite und Hintergrundfarbe und dürften uns keine Schwierigkeit bereiten. Gleich darauf werden die Vektoren des Timer-Interrups umgestellt. Waren bei der Programmierung des BRK-Interrupts die Adressen $0316 und $0317 von großer Bedeutung, so sind es beim Timer-Interrupt die Adressen $0314 und $0315 .
In unserem Demo-Programm richten wir diesen Vektor auf Adresse $1036 . Auf diese Weise können wir unsere Joy-Stick Abfrage einfach in den normalen Verlauf des Betriebsystems einbinden.
Der voreingestellte Wert in $0314/$0315 ist $ EA31 . An dieser Adresse befindet sich eine Routine, die im Normalfall 60 mal pro Sekunde angesprungen wird, um die Uhr weiterzustellen und die Tastatur abzufragen. Aus diesem Grund sollte zum Abschluß einer ' seriösen' IRQ-Routine ein Sprung nach $ EA31 folgen.
Somit hätten wir alles geklärt bis auf die Funktion der beiden CIA Register $ DC04/$ DC05 . Zuvor haben wir einiges über Intervalltimer erfahren und angedeutet, daß man damit Zeitverzögerungen erzeugen kann.
Gemeint war damit, daß man die Zeit zwischen den Interruptanforderungen beliebig verändern kann.
Wem die Joy-Stick Abfrage bisher zu langsam war, der sollte einfach einen kleineren Wert ausprobieren.
z. B.$1025( statt $4025) Nun ist die Joy-Stick Abfrage viel flotter. Alle anderen Funktionen wurden aber ebenfalls beschleunigt und dies ist in Bezug auf die Cursor Steuerung eher negativ, da man nicht mehr so genau schreiben kann.
Der Grund für dieses allgemeine ' Speed up' liegt daran, daß Intervalltimer A bereits vom Betriebsystem benutzt wird.
Nun gibt es aber die Möglichkeit, die Joy-Stick Abfrage von einem anderem Intervalltimer abarbeiten zu lassen.
Gleich zu Beginn haben wir erfahren, das der C64 mit Intervalltimer reichlich bestückt ist, denn immerhin gibt es gleich vier verschliedene davon.
Weitere Routinen finden Sie auf der Rückseite der MAGIC-DISK, die man mit Hilfe eines MONITORS einladen kann.
" TIMER-DEMO 2" ist identisch mit dem zuletzt besprochenen Listing, nur das der Joy-Stick über Intervalltimer B abgefragt wird. Zu diesem Zweck, mußten folgende Befehle hinzugefügt werden.

 1034 LDX #$80       ;Lo-und Hi-Byte von
 1036 LDY #$10       ;Intervalltimer B  
 1038 STX $DC06      ;setzen            
 103B STY $DC07                         
 103E LDA #%10000011 ;IRQ-Quelle        
 1040 STA $DC0D      ;In ICR schreiben  
 1043 LDA #%00010001 ;Intervalltimer B  
 1045 STA $DC0F      ;starten           

Im " TIMER-DEMO 3" haben wir die letzte Routine nochmals erweitert. Intervalltimer A des NMI-Timers wurde als dritte Unterbrechungsanforderung hinzugezogen, um ein Musikstück im Interrupt abspielen zu lassen. Sie sehen das die Interruptprogrammierung eine Fülle von Möglichkeiten bietet, die wir für uns nutzen können. Wenn sie auch noch etwas Zeit zum Tüfteln investieren, finden Sie bestimmt noch eine Menge weiterer Möglichkeiten.
Damit schließen wir zunächst mal die Einführung in die Unterbrechungsprogrammierung ab. Da wir in diesen Teil schon fast alle IRQ-Arten angesprochen haben, wollen wir uns in der nächsten und allen weiteren Ausgaben nur noch mit dem wichtigsten Typ des Interrupts befassen: dem RASTER-Interrupt.

                            (IVO HERZEG)

Valid HTML 4.0 Transitional Valid CSS!