Interruptkurs (Teil6 - 2.Hälfte)
----------------------------------------
Kommen wir nun zur ersten FLD-Routine.
In ihr wird der Interrupt geglättet, was
eine besonders trickreiche Angelegenheit
ist. Sehen Sie sich hierzu einmal den
Sourcecode an:
;*** FLD-Routine mit Glättung ($1100)
FLD1 pha ;Akku, X- u. Y-Reg.
txa ; retten
pha
tya
pha
dec $d019 ;neue IRQs erlauben
inc $d012 ;nächte Raster.=Ausl.
lda #<FLD2 ;Lo-Byte von FLD-IRQ2-
sta $fffe ;Routine setzen
cli ;IRQs erlauben
WIRQ nop ;13 NOPs
nop ; (innerhalb dieser
nop ; Schleife wird der
nop ; Interrupt ausge-
nop ; löst werden!!)
nop
nop
nop
nop
nop
nop
nop
nop
jmp QIRQ
FLD2 pla ;Programmzähler und
pla ; Statusreg. gleich
pla ; wieder v. Stack holen
nop ;19 NOPs zum Verzögern
nop ; bis zum tatsächlichen
nop ; Charakterzeilen-
nop ; anfang
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lda $d012 ;Den letzten Zyklus
cmp $d012 ; korrigieren
bne cycle
cycle ... ;eigentlicher IRQ
Hier werden Ihnen einige Dinge etwas
merkwürdig vorkommen (vor allem die vie-
len NOPs). Beginnen wir von Anfang an:
In der Borderroutine hatten wir die Ra-
sterzeile festgelegt, in der die FLD1-
Routine angesprungen werden soll. Dies
war Zeile 61 ($3D), die genau zwei Ra-
sterzeilen vor der eigentlichen IRQ-
Rasterzeile liegt. In diesen zwei Zei-
len, die wir den IRQ früher ausgelöst
haben, werden wir ihn jetzt glätten. Wie
in jedem Interrupt retten wir zunächst
die Prozessorregister. Daran anschlie-
ßend wird das Low-Byte der Routine
"FLD2" in das Low-Byte des IRQ-Vektors
geschrieben, und die nächste Rasterzeile
(durch den INC-Befehl) als nächster In-
terruptauslöser festgelegt. Beachten Sie
hierbei, daß die diese Routine dasselbe
High-Byte in der Adresse haben muß, wie
die erste FLD-Routine. Das kann man da-
durch erzielen, daß "FLD1" an einer
Adresse mit 0-Lowbyte ablegt wird und
sofort danach die Routine "FLD2" folgt
(im Beispiel ist FLD1 an Adresse $1100).
Um einen neuen Interrupt zu ermöglichen,
müssen noch das ICR des VIC und das In-
terrupt-Flag des Prozessors gelöscht
werden (beachten Sie, daß letzteres vom
Prozessor automatisch bei Auftreten des
IRQs gesetzt wurde).
Es folgt nun der eigentliche "Glät-
tungs-teil". Hierzu lassen wir den Pro-
zessor ständig durch eine Endlos-
Schleife mit NOP-Befehlen laufen. Da-
durch wird sichergestellt, daß der Ra-
ster-IRQ der nächsten Rasterzeile in
jedem Fall während der Ausführung eines
NOP-Befehls auftritt. Da dieser Befehl
nur 2 Taktzyklen verbraucht, kann die
Verzögerung des Interupts nur 0 oder 1
Taktzyklen lang sein. Diesen einen Zy-
klus zu korrigieren ist nun die Aufgabe
des zweiten FLD-IRQs. Nachdem er ange-
sprungen wurde holen wir gleich wieder
die, vom Prozessor automatisch gerette-
te, Programmzähleradresse und das Sta-
tusregister vom Stapel, da sie nur zum
ersten FLD-Interrupt gehören, in den
nicht mehr zurückgekehrt werden soll.
Danach folgen 19 NOP-Befehle, die nur
der Verzögerung dienen, um das Ende der
Rasterzeile zu erreichen. Die letzten
drei Befehle sind die Trickreichsten!
Sie korrigieren den einen möglichen
Verzögerungs-Zyklus. Zum besseren
Verständnis sind sie hier nochmal aufge-
listet:
lda $d012 ;Den letzten Zyklus
cmp $d012 ; korrigieren
bne cycle
cycle ... ;eigentlicher IRQ
Obwohl diese Folge recht unsinnig er-
scheint, hat sie es ganz schön in sich:
Wir laden hier zunächst den Akku mit dem
Inhalt von Register $D012, das die Num-
mer der aktuell bearbeiteten Rasterzeile
beinhaltet, und vergleichen ihn sofort
wieder mit diesem Register. Danach wird
mit Hilfe des BNE-Befehls auf die Fol-
geadresse verzweigt, was noch unsinniger
erscheint.
Der LDA-Befehl befindet sich nun durch
die NOP-Verzögerung genau an der Kippe
zur nächsten Rasterzeile, nämlich einen
Taktzyklus bevor diese Zeile beginnt.
Sollte nun der FLD2-IRQ ohne den einen
Taktzyklus Zeitverzögerung ausgeführt
worden sein, so enthält der Akku z.B.
den Wert 100. Der CMP-Befehl ist dann
ein Vergleich mit dem Wert 101, da der
Rasterstahl nach dem LDA-Befehl schon in
die nächste Zeile gesprungen ist. Da-
durch sind die beiden Werte ungleich,
womit das Zero-Flag gelöscht ist, und
der Branch tatsächlich ausgeführt wird.
Beachten Sie nun, daß ein Branch-Befehl
bei zutreffender Bedingung durch den
Sprung einen Taktzyklus mehr Zeit ver-
braucht, als bei nicht zutreffender Be-
dingung (3 Zyklen!). War der FLD2-IRQ
allerdings mit dem einem Taktzyklus
Verzögerung aufgetreten, so wird der
LDA-Befehl genau dann ausgeführt, wenn
Register $D012 schon die Nummer der
nächsten Rasterzeile enthält, womit der
Akku den Wert 101 beinhaltet. Durch den
Vergleich mit dem Register, das dann
immer noch den Wert 101 enthält, wird
das Zero-Flag gesetzt, da die beiden
Werte identisch sind. Dadurch trifft die
Bedingung des BNE-Befehls nicht zu, und
er verbraucht nur 2 Taktzyklen! Dies
gewährleistet, daß in beiden Fällen im-
mer die gleiche Zyklenzahl verbraucht
wird! War der FLD2-IRQ ohne Verzögerung,
so verbracht die Routine einen Zyklus
mehr, als wenn er mit einem Zyklus
Verspätung auftrat!
Hiermit hätten wir den IRQ also geglät-
tet und können die eigentliche FLD- und
Farbsetz-Routine ausführen. Beachten Sie
für Folgebeispiele, daß wir in Zukunft
auf diese Weise die IRQs immer glätten
werden müssen, um saubere Ergebnisse zu
erzielen. Hierzu wird immer wieder diese
Routine verwandt, wobei das eigentliche
IRQ-Programm dann nach dem Branch-Befehl
eingesetzt wird. Gleichmäßiger kann man
Raster-IRQ nun wirklich nicht mehr
ausführen!
Nach dem Glätten folgt die eigentliche
Interruptroutine, und zwar direkt nach
dem Label "Cycle". Sie setzt Rasterzeile
$F8 als Interruptauslöser fest und ver-
biegt den IRQ-Vektor wieder auf die Bor-
derroutine, womit der Kreislauf von
Neuem beginnt. Gleichzeitig setzt Sie
die Darstellung auf 25 Zeilen zurück,
damit der Bordereffekt auch funktio-
niert. Anschließend wird der FLD-Effekt
durchgeführt, indem der Zeilenanfang vor
dem Rasterstrahl hergeschoben wird. Wäh-
renddessen werden die Vorder- und Hin-
tergrundfarbe nach zwei Farbtabellen bei
$1200 und $1300 verändert. Der Raster-
split wird durch ausreichende Verzöge-
rung bis zur Mitte einer Rastezeile er-
zeugt. Zum Schluß des IRQs wird noch bis
zum Ende der Rasterzeile verzögert, und
die Standardfarben zurückgesetzt, bevor
die ursprünglichen Inhalte der Prozes-
sorregister, wie sie vor dem Auftreten
des FLD1-IRQs vorhanden waren, zurückge-
holt werden und der IRQ beendet wird:
Cycle dec $d019 ;VIC-ICR löschen
lda #$18 ;25-Zeilen-Darst. ein-
sta $d011 ; schlaten (Bordereff.)
lda #$f8 ;Rasterz. $F8 ist näch-
sta $d012 ; ster IRQ-Auslöser
ldx #<Bord ;IRQ-Vektor
ldy #>Bord ; auf
stx $fffe ; Border-Routine
sty $ffff ; verbiegen
nop ;Verzögern
lda $02 ;FLD-Zähler laden
beq FDEnd ; Wenn 0, kein FLD!
ldx #$00 ;Zählreg.f.Farben init.
clc
FDLop lda $d012 ;FLD-Sequenz (Zeilen-
adc #$02 ; anfang vor Raster-
and #$07 ; strahl herschieben
ora #$18
sta $d011
lda $1200,x;Farbe links holen
sta $d020 ; und setzen sta
$d021
nop ;Verzögern bis Mitte
nop
nop
nop
nop
nop
nop
lda $1300,x;Farbe rechts holen
sta $d020 ; und setzen
sta $d021
bit $ea ;Verzögern
inx ;Farb-Zähler+1
cpx $02 ;Mit FLD-Zähler vgl.
bcc FDLop ;ungl., also weiter
FDEnd nop ;Verz. bis Zeilenende
nop
nop
nop
nop
lda #$0e ;Vorder-/Hintergrund-
sta $d020 ; farben auf
lda #$06 ; hellblau u. dunkel-
sta $d021 ; blau setzen
pla ;Akku, X- und Y-Reg.
tay ; zurückholen
pla
tax
pla
rti ;IRQ beenden
Das war es dann wieder für diesen Monat.
Im nächsten Kursteil werden wir eine
weitere Anwendung besprechen, die eine
IRQ-Glättung benötigt: die Sideborder-
routinen zum Abschalten des linken und
rechten Bildschirmrands, nämlich.
(ub)