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)