Fortsetzung IRQ-Kurs, Teil 10
Es folgt nun der Programmteil mit dem
Label " CONTINUE", der von der obigen
Routine angesprungen wird. Hier kümmern
wir uns wieder um den Scrolloffset, dessen Wert ja noch negativ ist, da wir im
ersten Teil der MOVESPR-Routine durch
die Subtraktion einen Unterlauf des Zählers erzeugt hatten. Damit Sie hier nun
auch Werte größer 1 einsetzen können, womit der Scroll schneller durchläuft, wird " SOFTROLL" nicht wieder mit $17 vorinitialisiert, sondern wir addieren
auf das Ergebnis der Subtraktion den
Offset, der zwischen zwei Rasterinterrupts liegt,$18(= dez.24), auf. Der
resultierende Wert wird dann wieder in
Softroll abgelegt. Auf diese Weise werden also auch Scrollwerte größer 1 berücksichtigt. War das Ergebnis der
Subtraktion z. B.-2, so wird " SOFTROLL" auf 22 zurückgesetzt, womit der Öberlauf
abgefangen wird, und der Scrolleffekt flüssig weiterläuft:
CONTINUE:
clc ;C-Bit f.Add. löschen lda softroll;SOFTROLL laden adc #$18 ;24 addieren sta softroll;und wieder ablegen lda #$20 ;Op-Code für "JSR" sta mt ;in MT eintragen
Besonders trickreich ist die LDA-STA- Folge am Ende dieses Programmteils. Wir
tragen hier den Wert $20, der dem Assembler- Opcode des " JSR"- Befehls entspricht, in das Label " MT" ein. Letzteres befindet sich innerhalb der
MOVIEIRQ-Routine, und zwar vor dem Befehl " JSR MAKETEXT" . Die MAKETEXT-Routine baut eine Spritezeile auf, indem
Sie die Zeichendaten dieser Zeile von
dem Zeichensatz bei $0800 in die zu benutzenden Sprites einkopiert. Da dies
nicht direkt zu unserem Kursthema
gehört, möchte ich auch nicht weiter auf diese Routine eingehen. Wichtig zu wissen ist nur, daß die MOVESPR-Routine, nachdem sie erkannt hat, daß eine neue
Spritezeile aufgebaut werden muß, die
MOVIEIRQ-Routine derart modifiziert, daß
im nächsten IRQ die MAKETEXT-Routine
angesprungen wird. Innerhalb selbiger
existiert dann eine weitere Befehlsfolge, die den Wert $2 C in das Label " MT" schreibt. Selbiger Wert ist der Opcode
für den Assemlerbefehl " BIT" . In allen
folgenden IRQs arbeitet der Prozessor an
diesem Label also immer den Befehl " BIT
MAKETEXT" ab, der eigentlich keine Funktion beinhaltet, sondern lediglich verhindern soll, daß die Maketext-Routine
angesprungen wird. Erst, wenn MOVESPR
erkannt hat, daß eine neue Spritezeile
aufgebaut werden muß, ändert sie den
Befehl wieder in " JSR MAKETEXT" um, so
daß die Zeile im nächsten IRQ wieder
automatisch neu berechnet wird. Dieser, zugegebenermaßen etwas umständliche, Weg
des Routinenaufrufs wurde gewählt, da MAKETEXT recht lange ( insgesamt etwa
einen Rasterdurchlauf) braucht, um die
Spritezeile aufzubauen. Damit Sie in
dieser Zeit die Raster-IRQs nicht blokkiert, muß sie auf diesem Weg benutzt
werden. Während ihres Ablaufs erlaubt
sie auch weitere IRQs, so daß Sie während der Darstellung des nächsten Rasterdurchlaufs, immer zwischen den Spritepositionierungen durch den IRQ, ablaufen kann.
Kommen wir nun zum letzten Teil der MO-VESPR- Routine, dem Label " ROLLON" . Selbiges wird ja ganz am Anfang der Routine
angesprungen, wenn kein Unterlauf von
" SOFTROLL" stattfand, und somit ohne
jegliche Änderung weitergescrollt wird.
Sie setzt den Spritepointerindex " ISLI-NE" zurück auf den Wert in " SHOWLINE" und bereitet den ersten Raster-IRQ vor, der ja immer in der Rasterzeile " SOFT-ROLL" aufzutreten hat.
ROLLON:
lda showline;ISLINE mit Inhalt von sta isline ; SHOWLINE init. lda softroll;Scroll-Offset holen sta $d012 ;und als nächsten IRQ- lda $d011 ;Auslöser setzen, dabei and #$7f ;Hi-Bit löschen u. ora #$08 ;gleichz. 24-Zeilen- sta $d011 ;Darst. einschalten rts
Beim Festlegen des Wertes " SOFTROLL" als
nächste IRQ-Rasterzeile, muß die Routine
auch das High-Bit, dieser Rasterposition, in $ D011 löschen. Gleichzeitig
schaltet sie die 25- Zeilen-Darstellung
durch Setzen des 3 . Bits dieses Registers wieder ein. Dies ist eigentlich
eine Aufgabe, die für das Beispielprogramm " MOVIE.1" irrelevant ist. Wohl
aber für " MOVIE.2", in dem wir den Movie- Scroller über einen Bildschirm mit
abgeschaltetem oberen und unteren Rand
laufen lassen. Wie Sie wissen, muß dazu in Rasterzeile $ FA die Darstellung von
25 auf 24 Zeichen-Zeilen heruntergeschaltet werden, und danach, vor nochmaligem Erreichen von $ FA, wieder auf 25 Zeilen zurück, was hiermit durchgeführt
wird. Da MOVESPR immer im 13 . Interrupt
aufgerufen wird, und dieser immer nur
innerhalb der Rasterzeilen $10 C-$126 auftreten kann, befinden wir uns
tatsächlich schon unterhalb der Rasterzeile $ FA, womit die Änderung zum korrekten Zeitpunkt durchgeführt wird.
3) GLEICHZEITIGES ÜFFNEN DES BILDSCHIRMS
Wie schon angesprochen, öffnet das Programmbeispiel " MOVIE.2" zusätzlich noch
den oberen und unteren Bildschirmrand, damit die Sprites in voller Bildhöhe
über den Bildschirm laufen. Vom Prinzip
her ist dies ein recht einfaches Unterfangen, das wir auch schon ausgiebig in
diesem Kurs besprochen und angewandt
haben. Durch unsere Scrollroutine stellt sich uns jedoch ein kleines Problem in
den Weg: da unsere Raster-IRQs durch den
Scrolleffekt immer in verschiedenen Rasterzeilen aufzutreten haben, und wir
nicht immer genau sagen können, ob nun
der 11 . oder 12 . Rasterinterrupt gerade
ausgelöst wurde, bevor der Rasterstrahl
die Position $ FA erreicht hat, wird es
schwierig die Scroll-Routine so abzutimen, daß sie genau an dieser Position
die Bildschirmdarstellung ändert. Würde
man versuchen durch Verzögerungsschleifen die richtige Position abzutimen, so
wäre das mit einem erheblichen Programmieraufwand verbunden. Deshalb greifen
wir zu einem kleinen Trick: Die INIT-Routine von " MOVIE.2" wurde um eine
kleine Änderung erweitert. Zunächst lassen wir hier den Prozessor, durch ständiges Auslesen und Vergleichen der aktuellen Rasterposition, auf Rasterzeile
$ FA warten. Ist diese erreicht, so initialiseren wir Timer A von CIA-2 mit dem
Wert $4 CC7 und starten ihn. Da der Ra- sterstrahl immer exakt so viele Taktzyklen braucht, um einmal über den ganzen
Bildschirm zu laufen, erzeugt diese CIA
immer genau in Rasterzeile $ FA, in der
sie gestartet wurde, einen NMI. Weil
dieser Vorrang vor dem IRQ hat, wird er
selbst dann ausgelöst, wenn gerade ein
Raster-IRQ auftritt oder in Bearbeitung
ist. Die NMI-Routine nimmt nun die erforderliche Änderung von $ D011 vor, um
den Rand abzuschalten ( Bit 3 löschen) und kehrt anschließend sofort wieder
zurück, ggf. sogar in einen vom NMI unterbrochenen Raster-IRQ, der dann ganz
normal zu Ende bearbeitet wird. Das
Zurücksetzen von $ D011 auf die alte 25- Zeilen-Darstellung, wird dann wieder von
der MOVESPR-Routine durchgeführt, wie
wir oben ja schon gesehen hatten.
Um die NMIs zu erzeugen springt die
INIT-Routine von " MOVIE.2" auf eine Unterrountine zum Initialiseren des Timer- NMIs. Wie das funktioniert hatten wir schon ganz zu Anfang des Interrupt-Kurses bespochen. Hier die Routine, um
Ihnen den Vorgang wieder ins Gedächtnis
zu rufen. Wie auch schon für den IRQ
springen wir diesmal nicht über den
Soft-NMI- Vektor bei $0318/$0319, sondern
über den Hardvektor bei $ FFFA/$ FFFB in
den NMI ein:
NMIINIT:
lda #<nmi ;Startadresse NMI-Routine sta $fffa ; in die Hardvektoren bei lda #>nmi ;$FFFA/$FFFB eintragen sta $fffb lda #$c7 ;Timer A mit dem Zählwert sta $dd04 ; $4CC7 initialiseren lda #$4c sta $dd05 lda #$fa ;Rasterz. $FA in Akku WAIT: cmp $d012 ;m. akt. Raster vgl. bne wait ;ungl. also weiter lda #$11 ;Gleich, also Timer A sta $dd0e ; starten lda #$81 ;Timer-A-NMIs in ICR sta $dd0d ; erlauben rts
Das war eigentlich schon alles. Von nun
an löst Timer A von CIA-B alle $4 CC7 Taktzyklen einen NMI aus. Da der Rasterstrahl immer genau diese Anzahl Zyklen
benötigt, um ein ganzes Mal über den
Bildschirm zu laufen, tritt der NMI also
immer in Rasterzeile $ FA ein, auf die
wir vor Starten des Timers gewartet haben. Die NMI-Routine selbst ist recht
kurz und sieht folgendermaßen aus:
NMI: pha ;Akku retten lda $d011 ;$D011 holen HILO: ora #$00 ;7.Bit Rasterpos. setzen and #$F7 ;3.Bit löschen sta $d011 ;$D011 zurückschreiben bit $dd0d ;NMIs wieder erlauben pla ;Akku zurückholen rti ; und Ende
Da die NMI-Routine lediglich den Akku
benutzt, brauchen wir auch ausschlißelich nur diesen auf dem Stapel zu retten. Danach wird der Inhalt von $ D011 gelesen. Der nun folgende ORA-Befehl hat
die Aufgabe eine ggf. gesetztes High-Bit
der Rasterstrahlposition des nächsten
Raster-IRQs zu setzen, damit wir durch
unsere Manipulation von $ D011 nicht versehentlich die, schon gesetzte, nächste
Raster-IRQ- Position verändern. Hierzu
wurde die MOVIEIRQ-Routine von " MOVIE.2" derart abgeändert, daß Sie die High-Position für den nächsten Raster-IRQ
nicht nur in $ D011 schreibt, sondern
auch im Label " HILO+1" ablegt, so daß
das Argument des ORA-Befehls zwischen
$00 und $80 variiert und immer den richtigen ODER-Wert enthält. Anschließend
folgt nun ein AND-Befehl zum Löschen des
3 . Bits, womit wir mit dem Ablegen des
Wertes die 24- Zeilen-Darstellung einschalten. Durch den BIT-Befehl führen
wir einen Lesezugriff auf das ICR- Register von CIA-2 aus, womit wir selbiges Löschen, und dadurch das Auftreten
und Melden des nächsten NMIs ermöglichen. Hiernach wird dann nur noch der
gerettete Akkuinhalt zurückgeholt, bevor
wir den NMI mittels " RTI" beenden. Da
die MOVESPR-Routine nun automatisch zu
einer späteren Position Bit 3 in $ D011 wieder setzt, funktioniert der NMI-Border- Trick also auch wieder im folgenden Rasterdurchlauf! Mit Hilfe des hier
benutzen NMI-Tricks können Sie quasi
zwei Raster-Intterrupts gleichzeitig
ablaufen lassen, was auch für andere
Rasterroutinen sehr hilfreich sein kann.
(ih/ub)