Magic Disk 64

home to index to html: MD9408-KURSE-IRQ-KURS_10.1.html
                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 befas-
sen. 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" programmie-
ren,  der  es  uns   ermöglicht,   einen
Scrolltext, so wie in Abspännen von Fil-
men, von unten nach oben über den gesam-
ten Bildschirm zu scrollen. Hierbei wer-
den  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 Kennt-
nis 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 darstel-
len. Um nun mehrere Zeilen  zu  generie-
ren,  müssen wir in regelmäßigen Abstän-
den einen Raster-IRQ erzeugen,  der  je-
desmal  die  Y-Position, sowie die Spri-
te-Pointer der acht Sprites  neu  setzt,
um somit die nächste Scroller-Zeile dar-
zustellen. Unsere Routine tut dies  alle
24  Rasterzeilen,  womit  sich  zwischen
zwei Spritezeilen immer  3  Rasterzeilen
Freiraum  befinden. Um nun einen Scroll-
effekt nach oben zu  erzeugen,  benutzen
wir  zusätzlich  ein  Zählregister,  daß
einmal pro Rasterdurchlauf um  1  ernie-
drigt,  und so von $17 bis $00 herunter-
gezä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 Poin-
terliste,  freigewordenen Sprites werden
dann die Buchstaben der neuen Zeile ein-
kopiert,  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" unterschei-
det 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 wer-
de, 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 unte-
       ren Bildschirmrand befinden.     
$1500  Spritepointer-Liste, die auf  die
       Sprites  im  Bereich  von  $2600-
       $3FFF zeigt.                     
$1600  Der Scroll-Text im ASCII-Format. 
Die Initialisierungsroutine unseres  Mo-
vie-IRQs  schaltet  wie  üblich  das Be-
triebssystem-ROM ab, und setzt im  Hard-
ware-IRQ-Zeiger   bei   $FFFE/$FFFF  die
Startadresse    der     MOVIEIRQ-Routine
($1200)  ein.  Zudem  werden  alle  CIA-
Interrupts gesperrt und die  Spriteregi-
ster  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.  Deswei-
teren  wird  die Farbe aller Sprites auf
"weiß" geschaltet.  Zusätzlich  wird  in
einer eigenen Unterroutine der Speicher-
bereich von $2600-$3FFF, 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  wer-
den,  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 weite-
ren Positionen resultieren dann aus  dem
jeweils  letzten  Positionswert plus dem
Offset 24.                              
Desweiteren  erscheinen  in  diesem Pro-
grammteil noch zwei Labels, mit den  Na-
men "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 wur-
de, kann so der  Basis-Y-Wert  der  ent-
sprechenden   Spritezeile   (im   ersten
Durchlauf Zeile 0,  Y-Pos  26)  auf  den
Akkuinhalt aufaddiert werden. Der resul-
tierende  Wert  entspricht  nun  der  Y-
Position aller Sprites dieser Zeile, die
wir sogleich in die VIC-Register eintra-
gen.                                    
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  aufad-
dieren  von  1  auf  den jeweils letzten
Wert, was in unserer Routine  durch  die
INX-Befehle  durchgeführt wird. Die Zei-
gertabelle enthählt nun  die  Werte  von
$98 bis $F8, als Zeiger auf die Sprites,
die  im  Speicherbereich von $2600-$3FFF
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 angespro-
chenen 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 Spritepoin-
ter von $98-$9F gehen, womit ihre  Spri-
tes  von  im Bereich von $2600 bis $2800
untergebracht sind, aus dem oberen Bild-
schirmrand, so muß die zweite Spritezei-
le (Pointer von $A0-$A7) von nun an  die
erste,  auf dem Bildschirm darzustellen-
de, Zeile sein,  wobei  wir  die  gerade
herausgescrollte Zeile als unterste Zei-
le verwenden müssen. Nachdem ihr Textin-
halt  in  die Sprites im Speicherbereich
von $2600 bis $2800  eingetragen  wurde,
müssen  nur  noch  die  Spritezeiger zum
richtigen Zeitpunkt auf diese Zeile  um-
geschaltet  werden.  Wir  haben nun noch
einen Weiteren Index, namens "SHOWLINE",
der in Zeropageadresse $F8 untergebracht
ist, und uns angibt, welche der  Sprite-
zeilen  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 pro-
blemlos inkementiert werden, ohne  dabei
einen Zeilenüberlauf beachten zu müssen!
Kommen wir jedoch wieder zurück zu unse-
rer   IRQ-Routine.   Nachdem   die    Y-
Positionen,  sowie  die Spritezeiger ge-
setzt wurden müssen noch einige  verwal-
tungstechnische   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ß, mit-
berü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" ausle-
sen.  Auf  diesen  Wert muß nun noch der
momentane  Scrolloffset  aus  "SOFTROLL"
addiert  werden, um die tatsächliche Ra-
sterzeile zu erhalten. Der daraus resul-
tierende  Wert  kann  zunächst einmal in
$D012 eingetragen werden. Sollte bei der
Addition ein Öberlauf stattgefunden  ha-
ben,  also ein Wert größer $FF herausge-
kommen 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 untege-
bracht 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  än-
dern.                                   
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 Spri-
tezeilen 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  Spritezei-
len  dargestellt  wurden. Ist dies nicht
der Fall, so wird der IRQ durch  Zurück-
holen der Prozessorregister, gefolgt von
einem  RTI,  beendet.  Befinden  wir uns
allerdings schon im letzen der 13  IRQs,
die  pro  Rasterdurchlauf auftreten sol-
len, 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 Bild-
schirm 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 Rasterdurch-
lauf  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  darge-
stellt  werden.  Durch  Ändern  des hier
subtrahierten Wertes in 2 oder 3  können
Sie übrigens auch die Scrollgeschwindig-
keit 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 #$0d     ; 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ür-
lich alle 13 Spritezeilen wieder zurück-
gesetzt 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  er-
haltene  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 Lauf-
schrift, die an dem Label "ESTEXT" abge-
legt ist, schon zu Ende gescrollt wurde.
Wenn ja, so wird in diesem Fall der Zei-
ger "TPOINT", der auf das erste  Zeichen
der als nächstes darzustellenden Sprite-
zeile zeigt, wieder mit  der  Startadra-
dresse  des  Textes ("ESTEXT") initiali-
siert:                                  
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!