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, des-
sen Wert ja noch negativ ist, da wir im
ersten Teil der MOVESPR-Routine durch
die Subtraktion einen Unterlauf des Zäh-
lers 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 Rasterinter-
rupts liegt, $18 (=dez. 24), auf. Der
resultierende Wert wird dann wieder in
Softroll abgelegt. Auf diese Weise wer-
den 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 Assem-
bler-Opcode des "JSR"-Befehls ent-
spricht, in das Label "MT" ein. Letzte-
res befindet sich innerhalb der
MOVIEIRQ-Routine, und zwar vor dem Be-
fehl "JSR MAKETEXT". Die MAKETEXT-
Routine baut eine Spritezeile auf, indem
Sie die Zeichendaten dieser Zeile von
dem Zeichensatz bei $0800 in die zu be-
nutzenden Sprites einkopiert. Da dies
nicht direkt zu unserem Kursthema
gehört, möchte ich auch nicht weiter auf
diese Routine eingehen. Wichtig zu wis-
sen 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 Befehlsfol-
ge, die den Wert $2C 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 Funk-
tion beinhaltet, sondern lediglich ver-
hindern 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 blok-
kiert, muß sie auf diesem Weg benutzt
werden. Während ihres Ablaufs erlaubt
sie auch weitere IRQs, so daß Sie wäh-
rend der Darstellung des nächsten Ra-
sterdurchlaufs, immer zwischen den Spri-
tepositionierungen durch den IRQ, ablau-
fen kann.
Kommen wir nun zum letzten Teil der MO-
VESPR-Routine, dem Label "ROLLON". Sel-
biges 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 Rasterposi-
tion, in $D011 löschen. Gleichzeitig
schaltet sie die 25-Zeilen-Darstellung
durch Setzen des 3. Bits dieses Regi-
sters wieder ein. Dies ist eigentlich
eine Aufgabe, die für das Beispielpro-
gramm "MOVIE.1" irrelevant ist. Wohl
aber für "MOVIE.2", in dem wir den Mo-
vie-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 herunterge-
schaltet werden, und danach, vor nochma-
ligem 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 $10C-$126
auftreten kann, befinden wir uns
tatsächlich schon unterhalb der Raster-
zeile $FA, womit die Änderung zum kor-
rekten Zeitpunkt durchgeführt wird.
3) GLEICHZEITIGES ÜFFNEN DES BILDSCHIRMS
Wie schon angesprochen, öffnet das Pro-
grammbeispiel "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 Unter-
fangen, 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 Ra-
sterzeilen 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 abzuti-
men, daß sie genau an dieser Position
die Bildschirmdarstellung ändert. Würde
man versuchen durch Verzögerungsschlei-
fen die richtige Position abzutimen, so
wäre das mit einem erheblichen Program-
mieraufwand verbunden. Deshalb greifen
wir zu einem kleinen Trick: Die INIT-
Routine von "MOVIE.2" wurde um eine
kleine Änderung erweitert. Zunächst las-
sen wir hier den Prozessor, durch stän-
diges Auslesen und Vergleichen der ak-
tuellen Rasterposition, auf Rasterzeile
$FA warten. Ist diese erreicht, so ini-
tialiseren wir Timer A von CIA-2 mit dem
Wert $4CC7 und starten ihn. Da der Ra-
sterstrahl immer exakt so viele Taktzy-
klen 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 er-
forderliche Ä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 un-
terbrochenen 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 Un-
terrountine zum Initialiseren des Ti-
mer-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 $4CC7
Taktzyklen einen NMI aus. Da der Raster-
strahl 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 ha-
ben. 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ße-
lich nur diesen auf dem Stapel zu ret-
ten. 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 ver-
sehentlich 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 rich-
tigen 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 ein-
schalten. Durch den BIT-Befehl führen
wir einen Lesezugriff auf das ICR-
Register von CIA-2 aus, womit wir selbi-
ges Löschen, und dadurch das Auftreten
und Melden des nächsten NMIs ermögli-
chen. 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 folgen-
den 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)