DEN C64'er AUSGEREIZT (Teil 1)
INTERRUPTKURS
-------------
Mehr als 8 Sprites gleichzeitig, Grafi-
ken 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 he-
ranzuwagen.
Nimmt man sich die Zeit, Laufschriften
von Demos durchzulesen oder lauscht man
der hitzigen Unterhaltung eingefleisch-
ter 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 exi-
stieren dürften. Das es sie aber dennoch
gibt,haben wir einzig und allein der Ex-
perimentierfreudigkeit einiger Freaks
zu verdanken.
Leider muß ich zum Verständnis der abge-
druckten Programme Grundkennnisse der
Hardware, der Maschinensprache und Er-
fahrung 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 Pro-
grammen einsetzen? Dies sind die Fragen,
die in der ersten Folge des Interrupt-
kurses beantwortet werden sollen.
Was ein Interrupt ist,läßt sich einfach
beantworten. Ein Interrupt ist eine ge-
steuerte Unterbrechung und bedeutet, daß
spezielle Chips oder Befehle die Arbeit
des Rechners jederzeit unterbrechen kön-
nen und ihn dazu zwingen,andere Routinen
auszuführen. Insgesamt gibt es VIER ver-
schiedene 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 neuini-
tialisieren 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 ein-
fachen Programmbeispiel den gewöhnlichen
Verlauf eines Interrupts zu demonstrie-
ren. 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 Pro-
grammbeispiel 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 an-
schließend die SPACE-Taste, so meldet
sich der Rechner mit 'READY' wieder.
Nachdem wir unsere Routine gestartet
haben, wird als erstes Lo- und Hi-Byte
des Break-Vektors (welche Bedeutung jene
Register im einzelnen haben, wird an-
schließ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. An-
schließend wird Hi- und Lo-Byte des
PROGRAMMCOUNTERS auf den Stack abge-
legt, 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 Beendi-
gung des Interrups wieder fortsetzen.
In unserem Beispiel merkt er sich also
die Adresse: $100A+$0002=$100C.
Das zu der aktuellen Unterbrechungs-
adresse 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 in-
direkt ü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
FF4A PHA X-Reg.auf Stack retten
FF4B TYA
FF4C PHA Y-Reg.auf Stack retten
FF4D TSX Stackpointer ins X-Reg.
FF4E 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
TIMER- oder, 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 In-
terrupt endgültig zu beenden, gibt es
den Befehl RTI(Return from Interrupt),
was zu deutsch ungefähr soviel bedeu-
tet wie 'Verlassen der Unterbrechung-
sebene'. Trifft der Prozessor nun auf
einen 'RTI' Befehl, dann werden als
erstes STATUSREGISTER und PROGRMM-
COUNTER von Stack geholt und der Pro-
grammablauf kann an der Adresse $100c
fortgesetzt werden.
Im Gegensatz zu anderen IRQ-Arten, bie-
tet der BRK-INTERRUPT in der Praxis re-
lativ wenige Anwendunggebiete.Man könnte
ihn eigentlich problemlos als Unterpro-
grammbefehl 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 be-
stimmten Grund den Prozessor zwingen die
augenblickliche Tätigkeit zu unter-
brechen und eine andere Aufgabe auszu-
führen. Hierzu gehören die beiden CIA-
Chips und der Video-Chip.
Selbstverständlich geschehen diese Un-
terbrechungen 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 Unter-
brechung 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 Schnitt-
stelle vom Betriebsystem für keine be-
stimmte 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 Zwischen-
speicher, während die Lesedaten den
augenblicklichen Stand des Zählers an-
geben. Die beiden Timer können sowohl
unabhängig von einander, als auch im Zu-
sammenhang benutzt werden. Die verschie-
denen Betriebsarten erlauben das Er-
zeugen variabler Zeitverzögerungen.
Ein Intervalltimer ist mit einem Zeit-
laufwerk vergleichbar, das kontinuier-
lich 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 nor-
malen 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 ver-
deutlichen. 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 2
1039 LSR ;prüfen ob Bit 1 gelöscht
103A BCS $103F ;Nein? Dann verzweigen!
103C DEC $D001 ;sonst Sprite aufwärts
103F 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 $104B ;Nein? Dann verzweigen!
1048 DEC $D000 ;sonst Sprite nach links
104B LSR ;prüfen ob Bit 4 gelöscht
104C BCS $1051 ;Nein? Dann verzweigen!
104E 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 mel-
det 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öhn-
liches 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üp-
pel 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'$101D' 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
60mal 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 be-
liebig 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 ab-
gefragt 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. Intervall-
timer A des NMI-Timers wurde als dritte
Unterbrechungsanforderung hinzugezogen,
um ein Musikstück im Interrupt abspielen
zu lassen. Sie sehen das die Interrupt-
programmierung eine Fülle von Möglich-
keiten bietet, die wir für uns nutzen
können. Wenn sie auch noch etwas Zeit
zum Tüfteln investieren, finden Sie be-
stimmt noch eine Menge weiterer Möglich-
keiten.
Damit schließen wir zunächst mal die
Einführung in die Unterbrechungspro-
grammierung 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)