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)