Magic Disk 64

home to index to text: MD9408-KURSE-IRQ-KURS_10.1.txt
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 10)               

Herzlich Willkommen zum zehnten Teil unseres Raster-IRQ- Kurses. In dieser Ausgabe wollen wir uns weiterhin mit der trickreichen Spriteprogrammierung befassen. Im letzten Kursteil hatten Sie ja schon gelernt, wie man mit Hilfe eines Sprite-Multiplexers mehr als 8 Sprites auf den Bildschirm zaubert. Mit einem ähnlichen Trick werden wir heute einen sogenannten " Movie-Scroller" programmieren, der es uns ermöglicht, einen Scrolltext, so wie in Abspännen von Filmen, von unten nach oben über den gesamten Bildschirm zu scrollen. Hierbei werden wir wieder durch den Multiplex-Effekt insgesamt 104( !) Sprites aus dem VIC locken!
1) DAS PRINZIP DES MOVIESCROLLERS Das Funktionsprinzip des Movie-Scrollers ist recht einfach und sollte nach Kenntnis der Multiplex-Routinen kein Problem für Sie sein: Jede Zeile unseres Movie-Scrollers soll aus 8 Sprites aufgebaut sein, in denen wir einen Text darstellen. Um nun mehrere Zeilen zu generieren, müssen wir in regelmäßigen Abständen einen Raster-IRQ erzeugen, der jedesmal die Y-Position, sowie die Sprite- Pointer der acht Sprites neu setzt, um somit die nächste Scroller-Zeile darzustellen. Unsere Routine tut dies alle 24 Rasterzeilen, womit sich zwischen zwei Spritezeilen immer 3 Rasterzeilen Freiraum befinden. Um nun einen Scrolleffekt nach oben zu erzeugen, benutzen wir zusätzlich ein Zählregister, daß einmal pro Rasterdurchlauf um 1 erniedrigt, und so von $17 bis $00 heruntergezählt wird. Es dient als zusätzlicher Offset auf die Rasterzeilen, in denen ein IRQ ausgelöst werden muß. Ist dieses Zählregister auf 0 heruntergezählt, so wird es wieder auf $17 zurückgesetzt und die Spritepointer für jede einzelne Spritezeile werden alle um je eine Zeile höher kopiert. In die, am Ende der Pointerliste, freigewordenen Sprites werden dann die Buchstaben der neuen Zeile einkopiert, die sich dann von unten wieder in den Scroller einreihen können.
2) DER PROGRAMMABLAUF Um den Movie-Scroll- Effekt besser zu erläutern haben wir natürlich wieder einige Beispielprogramme für Sie parat.
Sie heißen " MOVIE.1" und " MOVIE.2" und befinden sich ebenfalls auf dieser MD.
Wie immer müssen beide Beispiele mit ",8,1" geladen und durch ein " SYS4096" gestartet werden." MOVIE.2" unterscheidet sich von " MOVIE.1" nur darin, daß zusätzlich zum Scroller auch der obere und untere Bildschirand geöffnet wurden.
Dies ist nur durch einen ganz besonderen Trick möglich, den wir später noch erläutern werden. Ich möchte Ihnen nun zunächst eine Speicheraufteilung der beiden Routinen geben, damit Sie sich die einzelnen Unterroutinen, die ich nicht alle in diesem Kurs erläutern werde, mit Hilfe eines Disassemblers einmal selbst anschauen können:

Adr.   Funktion                         

$0800 Zeichensatz $1000 IRQ-Init, incl. aller Sprite-Initialiserungen $1100 Movie-IRQ- Routine. Dies ist die eigentliche IRQ-Routine, die alle 24 Rasterzeilen die Sprites neu setzt.
$1200 BORDERNMI ( nur in " MOVIE.2"), zum Üffnen des oberen und unteren Bildschirmrandes.
$1300 MOVESPR-Routine. Sie bewegt die 13 Spritezeilen pro Rasterdurlauf um eine Rasterzeile nach oben.
$1400 MAKETEXT-Routine. Diese Routine schreibt den Text in die acht Sprites, die sich gerade am unteren Bildschirmrand befinden.
$1500 Spritepointer-Liste, die auf die Sprites im Bereich von $2600-$3 FFF zeigt.
$1600 Der Scroll-Text im ASCII-Format.
Die Initialisierungsroutine unseres Movie- IRQs schaltet wie üblich das Betriebssystem- ROM ab, und setzt im Hardware- IRQ-Zeiger bei $ FFFE/$ FFFF die Startadresse der MOVIEIRQ-Routine ($1200) ein. Zudem werden alle CIA-Interrupts gesperrt und die Spriteregister des VICs initialisiert. Hierbei tragen wir lediglich alle X-Positionen der Sprites ein, die bei $58 beginnen, und in 24- Pixel-Schritten pro Sprite erhöht werden. Natürlich muß auch das X-Position- High-Bit des achten Sprites, daß sich ganz rechts auf dem Bildschirm befindet, auf 1 gesetzt werden. Desweiteren wird die Farbe aller Sprites auf " weiß" geschaltet. Zusätzlich wird in einer eigenen Unterroutine der Speicherbereich von $2600-$3 FFF, in dem die 104 Sprites unterbringen, gelöscht. Zuletzt legt die Init-Routine Rasterzeile $17 als ersten IRQ-Auslöser fest und erlaubt dem VIC IRQs zu erzeugen.
Die MOVIEIRQ-Routine stellt nun den Kern unseres Movie-Scrollers dar. Es handelt sich hierbei um die IRQ-Routine, die alle 24 Rasterzeilen die Y-Positionen der Sprites ändert. Sie wird zum ersten Mal an Rasterzeile $17 angesprungen und setzt dann die folgenden IRQ-Rasterzeilen von selbst. Hier nun der kommentierte Sourcecode:
MOVIEIRQ:

   pha         ;Prozessorregs. retten   
   txa                                  
   pha                                  
   tya                                  
   pha                                  
   lda #$ff    ;Alle Sprites            
   sta $d015   ; einschalten            
   inc $d020   ;Rahmenfarbe erhöhen     

Nach Einsprung in die IRQ-Routine werden, nach dem obligatorischen Retten aller Prozessorregister, zunächst alle Sprites eingeschaltet. Anschließend erhöhen wir die Rahmenfarbe um 1, damit Sie sehen können, wie lange es dauert, bis alle Sprites neu gesetzt wurden. Nun beginnt der eigentliche Hauptteil der Routine:
clc ; C-Bit für Add. löschen ldy counter ; Rasterzähler als Y-Index lda softroll; Akt. Scrolloffs. holen. .
adc ypos, y ; . . Y-Wert addieren. .
sta $ d001 ; . . und selbigen in alle sta $ d003 ; acht Y-Positionen sta $ d005 ; der Sprites eintragen sta $ d007

   sta $d009                            
   sta $d00b                            
   sta $d00d                            
   sta $d00f                            

Wir setzen hier die Y-Positionen der Sprites. Hierbei hilft uns eine Tabelle namens " YPOS", in der alle Basis-Y- Positionen der insgesamt 13 Spritezeilen untergebracht sind. Die Y-Positionen der Sprites in der ersten Zeile sind dabei auf den Wert 26 festgelegt. Alle weiteren Positionen resultieren dann aus dem jeweils letzten Positionswert plus dem Offset 24 .
Desweiteren erscheinen in diesem Programmteil noch zwei Labels, mit den Namen " SOFTROLL" und " COUNTER" . Sie stehen für die Zeropageadressen $ F6 und $ F7, in denen wir Zwischenwerte unterbringen.
" SOFTROLL"($ F6) ist der oben schon erwähnte Rasterzeilenzähler, der von $17 auf 0 heruntergezählt wird. In " COUNTER" ist vermerkt, wie oft die IRQ-Routine während des aktuellen Rasterdurchlaufs schon aufgerufen wurde. Dies dient gleichzeitig als Zähler dafür, welche Spritezeile wir momentan zu bearbeiten haben. Beim ersten Aufruf enthält " COUN-TER" den Wert 0 . Auf diese Weise können wir ihn als Index auf die YPOS-Tabelle verwenden. Nachdem der Akku nun also mit den Scrolloffset " SOFTROLL" geladen wurde, kann so der Basis-Y- Wert der entsprechenden Spritezeile ( im ersten Durchlauf Zeile 0, Y-Pos 26) auf den Akkuinhalt aufaddiert werden. Der resultierende Wert entspricht nun der Y-Position aller Sprites dieser Zeile, die wir sogleich in die VIC-Register eintragen.
Nun müssen noch die Spritepointer der neuen Spritezeile neu gesetzt werden, da diese ja einen anderen Text enthält als die vorherige:
ldy isline ; Zgr.- Index in Y holen

   ldx pointer,y;Zgr.-Basiswert aus Tab.
   stx $07f8    ;für Sprite0 setzen..   
   inx          ; ..um 1 erhöhen und    
   stx $07f9    ;   für Sprite1 setzen  
   inx          ;Ebenso für Sprites2-7  
   stx $07fa                            
   inx                                  
   stx $07fb                            
   inx                                  
   stx $07fc                            
   inx                                  
   stx $07fd                            
   inx                                  
   stx $07fe                            
   inx                                  
   stx $07ff                            

Auch hier verwenden wir ein Label um auf eine Zeropageadresse zuzugreifen." ISLI-NE" steht für Adresse $ F9, die uns als Zwischenspeicher für einen Index auf die Spritezeigerliste dient. In letzterer sind nun alle Spritepointerwerte für das jeweils 0 . Sprite einer jeden Zeile un- tergebracht. Die Zeiger für die Sprites von 1 bis 7 resultieren aus dem aufaddieren von 1 auf den jeweils letzten Wert, was in unserer Routine durch die INX-Befehle durchgeführt wird. Die Zeigertabelle enthählt nun die Werte von $98 bis $ F8, als Zeiger auf die Sprites, die im Speicherbereich von $2600-$3 FFF liegen, jeweils in Achterschritten. Hier eine Auflistung der kompletten Tabelle:

pointer  .byte $98,$a0,$a8,$b0          
         .byte $b8,$c0,$c8,$d0          
         .byte $d8,$e0,$e8,$f0,$f8      
         .byte $98,$a0,$a8,$b0          
         .byte $b8,$c0,$c8,$d0          
         .byte $d8,$e0,$e8,$f0,$f8      

Wie Sie sehen, liegen hier die angesprochenen Pointer-Werte zweimal vor. Das ist notwendig, um das Umschalten der Spritezeilen, wenn diese aus dem oberen Bildschirmrand herausgescrollt werden, zu vereinfachen. Verschwindet nämlich die erste Spritezeile, deren Spritepointer von $98-$9 F gehen, womit ihre Sprites von im Bereich von $2600 bis $2800 untergebracht sind, aus dem oberen Bildschirmrand, so muß die zweite Spritezeile ( Pointer von $ A0-$ A7) von nun an die erste, auf dem Bildschirm darzustellende, Zeile sein, wobei wir die gerade herausgescrollte Zeile als unterste Zeile verwenden müssen. Nachdem ihr Textinhalt in die Sprites im Speicherbereich von $2600 bis $2800 eingetragen wurde, müssen nur noch die Spritezeiger zum richtigen Zeitpunkt auf diese Zeile umgeschaltet werden. Wir haben nun noch einen Weiteren Index, namens " SHOWLINE", der in Zeropageadresse $ F8 untergebracht ist, und uns angibt, welche der Spritezeilen als Erstes auf dem Bildschirm dargestellt werden muß. Zu Beginn eines neuen Rasterdurchlaufs wird " ISLINE" mit diesem Index initialisert. Dadurch, daß unsere Tabelle nun nach dem Wert $ F8 ein zweites Mal von vorne beginnt, kann " IS-LINE" während des Programmablaufs problemlos inkementiert werden, ohne dabei einen Zeilenüberlauf beachten zu müssen!
Kommen wir jedoch wieder zurück zu unserer IRQ-Routine. Nachdem die Y-Positionen, sowie die Spritezeiger gesetzt wurden müssen noch einige verwaltungstechnische Aufgaben durchgeführt werden:
clc ; C-Bit für Add. löschen ldy counter ; Spr-Zeilen- Index holen lda ad012+1, y; LO-Byte f. nächst. IRQ adc softroll ; Scroll-Offs. add.
sta $ d012 ; u. als nächst. IRQ setzen ror ; C-Bit in Akku rotieren and #$80 ; und isolieren ora ad011+1, y; HI-Bit f. nächst. IRQ ora $ d011 ; sowie $ D011 einodern sta $ d011 ; und setzen dec $ d019 ; VIC-IRQs freigeben dec $ d020 ; Rahmenfarbe zurücksetz.
In diesem Teil der Routine wird nun der folgende Raster-IRQ vorbereitet. Hierzu muß zunächst die Rasterzeile ermittelt werden, in der dieser auftreten soll.
Dafür existieren zwei weitere Tabellen, die die Basis-Rasterstrahlpositionen für die 13 Interrupts enthalten. Hierbei wird es wieder etwas kompliziert, da nämlich auch IRQs an Strahlpositionen größer als $ FF ausgelöst werden müssen, und wir deshalb das High-Bit der auslösenden Rasterstrahlposition, das in Bit 7 von $ D011 eingetragen werden muß, mitberücksichtigen müssen. Auch hierfür müssen wir sehr trickreich vorgehen:
Zunächst einmal ermitteln wir das Low-Byte der nächsten Rasterposition, indem wir es, mit " COUNTER" als Index im Y-Register, aus der Tabelle " AD012" auslesen. Auf diesen Wert muß nun noch der momentane Scrolloffset aus " SOFTROLL" addiert werden, um die tatsächliche Rasterzeile zu erhalten. Der daraus resul- tierende Wert kann zunächst einmal in $ D012 eingetragen werden. Sollte bei der Addition ein Öberlauf stattgefunden haben, also ein Wert größer $ FF herausgekommen sein, so wurde dies im Carry-Flag vermerkt. Selbiges rotieren wir mit dem ROR-Befehl in den Akku hinein, und zwar an Bitposition 7, wo auch das High-Bit der IRQ-Rasterstrahls in $ D011 untegebracht wird. Nachdem nun dieses High-Bit durch ein " AND $80" isoliert wurde, odern wir aus der Tabelle " AD011" das High-Bit der Standard-Rasterposition ( ohne Offset) in den Akku ein. Danach müssen natürlich auch noch alle weiteren Bits von $ D011 in den Akku eingeknüpft werden, damit wir beim folgenden Schreibzugriff keine Einstellungen ändern.
Nun muß nur noch das ICR des VIC gelöscht werden, damit der nächste IRQ auch auftreten kann. Gleichzeitig wird die Rahmenfarbe wieder heruntergezählt ( dadurch entstehen die grauen Rechen- zeit-Anzeigen im Bildschirmrahmen) .
Nun noch der letzte Teil der IRQ-Routine, der prüft, ob schon alle Spritezeilen aufgebaut wurden:

   inc isline   ;Akt. Zgr.-Zähler. +1   
   inc counter  ;Y-Pos-Zähler +1        
   lda counter  ;Y-Pos-Zähler holen     
   cmp #$0c     ; und mit 14 vgl.       
   bne endirq   ;Wenn ungl., dann weiter
   jsr movespr                          
   lda #$00                             
   sta $d015                            
mt:jsr maketext                         

ENDIRQ:

   pla                                  
   tay                                  
   pla                                  
   tax                                  
   pla                                  
   rti                                  

Hier werden jetzt die Zähler und Indizes für den nächsten IRQ voreingestellt, sowie geprüft, ob schon alle Spritezeilen dargestellt wurden. Ist dies nicht der Fall, so wird der IRQ durch Zurückholen der Prozessorregister, gefolgt von einem RTI, beendet. Befinden wir uns allerdings schon im letzen der 13 IRQs, die pro Rasterdurchlauf auftreten sollen, so fällt der Vergleich von " COUN-TER" mit dem Wert 14 negativ aus, womit die Routine " MOVESPR" angesprungen wird.
Sie sorgt für das korrekten Herabzählen des Scrolloffsets, und erkennt, wenn die oberste Spritezeile gerade aus dem Bildschirm gescrollt wurde:
MOVESPR:

   lda #$00    ;IRQ-Zähler init.        
   sta counter                          
   sec         ;C-Bit für Subtr. setzen 
   lda softroll;Scroll-Offs. holen      
   sbc #$01    ;Und 1 subtrahieren      

sta softroll; neuen Scroll-Offs. abl.
bpl rollon ; Wenn >0, dann weiter Wie Sie sehen, wird hier zunächst der IRQ-Zähler für den nächsten Rasterdurchlauf auf 0 zurückgesetzt. Anschließend subtrahieren wir den Wert 1 vom Scroll-Offset, wodurch die Sprites im nächsten Durchlauf eine Y-Position höher dargestellt werden. Durch Ändern des hier subtrahierten Wertes in 2 oder 3 können Sie übrigens auch die Scrollgeschwindigkeit erhöhen. Gab es bei der Subtraktion keinen Unterlauf, so wird zum Label " ROLLON"( s. u.) verzweigt. Im anderen Fall wurde durch den Scroll soeben eine ganze Spritezeile aus dem Bildschirm gescrollt, weswegen wir die Zeile unten, mit einem neuen Text belegt, wieder einfügen müssen. Zusätzlich müssen die Spritepointer in anderer Reihenfolge ausgelesen werden, was wir durch das Hochzählen von " SHOWLINE" bewirken.
Diese Aufgaben werden in folgendem Pro- grammteil ausgeführt:
inc showline ;1 . Spr-Zeilen- Ind. erh.
sec ; C-Bit f. Subtr. setzen lda showline ; Showline holen sbc #$0 d ; und 13 subtr.
bmi noloop ; Bei Unterlauf weiter sta showline ; Sonst Wert abl.
Da unsere Pointertabelle zwar doppelt, aber nicht ewig lang ist, muß sie natürlich alle 13 Spritezeilen wieder zurückgesetzt werden, was durch den SBC-Befehl geschieht. Erzeugte die Subtraktion ein negatives Ergebnis, so sind wir noch in einer Zeile kleiner als 13, und der erhaltene Wert wird ignoriert. Im andern Fall haben wir soeben die Mitte der Pointerliste erreicht, ab der ja die selben Werte stehen wie am Anfang, und wir können " SHOWLINE" wieder auf den erhaltenen Wert ( immer 0) zurücksetzen.
Den nun folgenden Routinenteil, der ab dem Label " NOLOOP" beginnt, möchte ich Ihnen nur der Vollständigkeit halber hier auflisten. Er prüft, ob die Laufschrift, die an dem Label " ESTEXT" abgelegt ist, schon zu Ende gescrollt wurde.
Wenn ja, so wird in diesem Fall der Zeiger " TPOINT", der auf das erste Zeichen der als nächstes darzustellenden Spritezeile zeigt, wieder mit der Startadradresse des Textes (" ESTEXT") initialisiert:
NOLOOP:

   lda tpoint                           
   cmp #<estext+($34*$18)               
   bne continue                         
   lda tpoint+1                         
   cmp #<estext+($34*$18)               
   bne continue                         
   lda #$00                             
   sta showline                         
   lda #<estext                         
   sta tpoint+0                         
   lda #>estext                         
   sta tpoint+1                         

( Anm. d. Red. : Bitte wählen Sie nun den zweiten Teil des IRQ-Kurses aus dem Textmenu aus.)

Valid HTML 4.0 Transitional Valid CSS!