Magic Disk 64

home to index to html: MD9502-KURSE-IRQ-KURS_16.1.html
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 16)               
----------------------------------------
Herzlich Willkommen zum 16. Teil unseres
Kurses  über die Rasterstrahlprogrammie-
rung. In den letzten  beiden  Kursteilen
hatten  wir  uns  mit  zwei IRQ-Routinen
beschäftigt,  die  das   hardwaremässige
Scrollen  des Bildschirms jeweils in der
Horizontalen (HSP-Routine) und  Vertika-
len (VSP-Routine) ermöglichten. Der Clou
an  diesen  beiden Routinen war, daß des
GESAMTE Bildschirm  vom  VIC  verschoben
wurde,  und  wir keinen einzigen Taktzy-
klus zum  Kopieren  von  Bildschirmdaten
verschwenden mussten. In diesem Kursteil
wollen  wir nun das "Sahnestückchen" der
Raster-IRQ-Programmierung    besprechen:
die   Kombinattion  aus  HSP-  und  VSP-
Routine, genannt "AGSP". Diese Abkürzung
steht für "Any  Given  Screen  Position"
und bedeutet, daß der Bildschirm in jede
Richtung verschoben werden kann, und das
natürlich HARDWAREMÄSSIG, also wie schon
bei  HSP und VSP ohne auch nur einen Zy-
klus zum Kopieren von Bildschirmdaten zu
verschwenden!                           
Stellen  Sie  sich vor, was für Möglich-
keiten sich hierdurch für  Spiele  erge-
ben:  so kann man z.B. problemlos Spiele
programmieren, die sich über  einer  be-
liebig  großen Oberfläche abspielen, die
in  alle  Richtungen  flüssig  gescrollt
werden  kann, ohne dabei mehr als 30 Ra-
sterzeilen pro Frame zu verbrauchen.  25
Rasterzeilen  lang ist der Prozessor ei-
gentlich nur mit dem Abpassen der  opti-
malen  Rasterstrahlpostion  für den HSP-
Effekt beschäftigt, der, wie  wir  schon
im  14. Kursteil sehen konnten, pro Cha-
rakterzeile, die der Bildschirm horizon-
tal  gescrollt werden soll, eine Raster-
zeile für das Timing verbraucht.        
Damit  Sie  sehen,  was  mit  der  AGSP-
Routine alles  möglich  ist,  haben  wir
Ihnen natürlich wieder zwei Beispielpro-
gramme vorbereitet. Sie heissen  "AGSP1"
und  "AGSP2"  und  werden  wie immer mit
",8,1" geladen und durch  ein  "SYS4096"
gestartet.  Desweiteren  finden  Sie auf
dieser MD eine  Demo  mit  Namen  "AGSP-
Demo",  in  der am eindrucksvollsten die
Möglichkeiten  der  AGSP-Routine  demon-
striert  werden.  Sie  sehen hier einige
Hiresgrafiken,  die  in  Sinuswellenform
auf-  und  abschwingen  und gleichzeitig
von links nach rechts scrollen.  Hierbei
werden jeweils neue Grafiken in die Gra-
fik einkopiert, so daß der Eindruck ent-
steht, daß der Bildschirm weitaus größer
sei,  als  eigentlich sichtbar. Das Demo
laden  Sie  mit  LOAD"AGSP-DEMO",8   und
starten es durch "RUN".                 
1) DAS AGSP-PRINZIP                     
Kommen wir nun also  zum  Arbeitsprinzip
von  AGSP,  das eigentlich recht schnell
erläutert ist:  Zunächst  einmal  passen
wir  die  erste  Rasterzeile  des  Bild-
schirms ab, an der die erste  Charakter-
zeile  gelesen werden muß. Hier nun las-
sen wir eine VSP-Routine, so wie wir Sie
im letzten Kurteil schon  kennenlernten,
zunächst  dem VIC vorgaugeln, daß er auf
den Beginn der  Charakterzeile  noch  zu
warten  hat,  indem wir eine horizontale
Bildschirmverschiebung  um  1  Pixel  in
$D011 angeben. Inmitten dieser Zeit soll
nun  die  VSP-Routine diese Verschiebung
wieder Aufheben, um so  den  VIC  sofort
die  Charakterdaten lesen zu lassen, und
ihn somit dazu  zu  zwingen,  den  Bild-
schirm  nach  rechts versetzt darzustel-
len. Die Anzahl Taktzyklen, die bis  zum
Zurückschalten  verzögert werden müssen,
muß dabei der  Anzahl  Zeichen  entspre-
chen, die der Bildschirm verschoben wer-
den soll. Hieran anschließend lasen  wir
eine  HSP-Routine folgen, die den Beginn
der nächsten Charakterzeilen vor dem VIC
herdrückt, um so  auch  die  zeilenweise
Verschiebung  des  Bildschirmanfangs  zu
erreichen. Da diese Routine  maximal  25
Rasterzeilen   benötigt  (nämlich  dann,
wenn die Darstellung erst 25  Charakter-
zeilen  später beginnen soll, müssen die
ersten 25  Rasterzeilen  des  sichtbaren
Bildschirms  immer  für  das  Timing der
AGSP-Routine verwendet werden, auch wenn
stellenweise weniger  Rasterzeilen  dazu
benötigt werden (z.B. wenn nur eine Zei-
le Verschiebung erzeugt werden muß). Für
diese Fälle müssen wir mit  Hilfe  einer
normalen  FLD-Routine  den Bildschirm um
die fehlende  Anzahl  Rasterzeilen  nach
unten drücken, damit der Bildschirm auch
immer  in  ein und derselben Rasterzeile
beginnt. Diese FLD-Routine wird in unse-
rem  Programmbeispiel  den VSP- und HSP-
Routinen vorgeschaltet. Sie  sorgt  also
gleichzeitig  für  immer gleiches Timing
und zudem für die  richtige  Positionie-
rung  in  der  Horzontalen.  Aus  diesem
Grund sind dann die ersten 25 Rasterzei-
len  des Bildschirms auch nicht zum Dar-
stellen von Bildschirmdaten  verwendbar.
In  unserem Programmbeispielen haben wir
hier jedoch  Sprites  untergebracht,  in
denen die Scrollrichtung angezeigt wird.
In  einem  Spiel  könnte  sich hier z.B.
auch eine Score-Anzeige befinden.       
2) DAS PROGRAMM                         
Wollen  wir  uns  nun die Funktionsweise
von AGSP  anhand  des  Programmbeispiels
"AGSP1" anschauen. Die Routinen zur Joy-
stickabfrage und Scrollgeschwindigkeits-
verzögerung  sollen hier nicht Thema un-
seres Kurses sein, sondern lediglich die
Routine, die uns den Bildschirm beliebig
im sichtbaren Fenster positioniert.  Zur
angesprochenen   Scrollgeschwindigkeits-
verzögerung sei erwähnt,  daß  wir  hier
beim Drücken und Loslassen des Joysticks
die Scrollrichtung verzögern, bzw. nach-
laufen lassen, so daß  der  Scrolleffekt
zunächst  träge anfängt und beschleunigt
und beim Loslassen erst abgebremst  wer-
den muß, bis er zum Stillstand kommt.   
Die Initialisierungsroutine zu AGSP1 bei
$1000 legt nun zunächst einen Border-IRQ
in  Zeile  $FB fest, wobei, wie schon so
oft in  unseren  Beispielen,  der  Hard-
IRQ-Vektor bei $FFFE/$FFFF benutzt wird.
Diese  Border-Routine (bei $1400) schal-
tet nun den  oberen  und  unteren  Bild-
schirmrand  ab  und  initialisiert einen
Raster-IRQ für  Rasterzeile  $18,  wobei
dann   unsere   eigentliche  IRQ-Routine
"AGSP" angesprungen wird.  Sie  befindet
sich  an  Adresse  $1200 und soll im nun
Folgenden ausführlich  beschrieben  wer-
den. Die AGSP-Routine soll nun der Reihe
nach folgende Arbeiten verrichten:      
* Verwaltung des Sprite-Scoreboards, das
aus zwei Spritereihen zu je acht Sprites
bestehen soll.                          
* Glätten des  IRQs,  um  ein  möglichst
exaktes Timing zu bewirken.             
* FLD-Routine benutzen, um die fehlenden
Rasterzeilen, die  von  VSP  ggf.  nicht
benötigt werden, auszugleichen          
*  VSP-Routine charakterweisen zum hoch-
und runterscrollen des Bildschirms  ein-
setzen                                  
* HSP-Routine zum charakterweisen links-
und rechtsscrollen des Bildschirms  ein-
setzen                                  
* horizontales und vertikales Softscrol-
ling zur exakten  Bildschirmverschiebung
durchführen                             
a) DIE SPRITELEISTE                     
Kommen wir nun also zum ersten Teil  der
AGSP-Routine,  die  zunächst das Sprite-
Scoreboard verwaltet. Wir verwenden hier
zwei Sätze zu  je  acht  Sprites,  deren
Spritedaten  in  den Adressen von $0C00-
$1000 zu  finden  sein  sollen  (Sprite-
Pointer  $30-$3f).  Um  die Pointer zwi-
schen beiden leichter umschalten zu kön-
nen   benutzen   wir   zwei   Video-RAM-
Adressen. Für die erste Zeile, die eh in
einem  unsichtbaren  Bildbereich  liegt,
wird das Video-RAM an Adresse $0000 ver-
schoben, so daß wir die Spritepointer in
den Adressen $03F8-$03FF  liegen  haben.
Für  die zweite Spritezeile wird das Vi-
deo-RAM an die (normale)  Adresse  $0400
gelegt,  womit  wir die Spritepointer an
den Adressen $07F8-$07FF vorfinden.  Da-
durch,  daß  durch  den  VSP-Effekt auch
diese Spritepointer als einzelne Zeichen
auf dem  Bildschirm  auftauchen  können,
müssen  wir die Pointer in jedem Raster-
durchlauf (Frame) wieder neu setzen,  da
die  Pointer  auf dem Bildschirm ja dur-
chaus auch  Bildschirmzeichen  enthalten
können.  Doch kommen wir nun endlich zum
Source-Code  der  AGSP-Routine,  der  in
seinem  ersten  Teil zunächst einmal die
Spriteinitialisierungen   vornimmt   und
eigentlich  einfach  zu  verstehen  sein
sollte:                                 
agsp:    pha       ;IRQ-Beginn -> also  
         txa       ; Prozessorregs.     
         pha       ; retten             
         tya                            
         pha                            
         lda #$1e  ;Y-Position aller    
         sta $d001 ; Sprites auf Raster-
         sta $d003 ; zeile $1E (dez. 30)
         sta $d005 ; setzen             
         sta $d007                      
         sta $d009                      
         sta $d00b                      
         sta $d00d                      
         sta $d00f                      
         lda #$01  ;Die Farbe aller     
         sta $d027 ; Sprites auf 1, also
         sta $d028 ; 'weiß' setzen      
         sta $d029                      
         sta $d02a                      
         sta $d02b                      
         sta $d02c                      
         sta $d02d                      
         sta $d02e                      
         lda #$ff  ;Alle Sprites ein-   
         sta $d015 ; schalten           
         lda #$80  ;Hi-Bit d. X-Pos. von
         sta $d010 ; Sprite 8 setzen    
         lda #$00  ;Sprite-Multicolor   
         sta $d01c ; ausschalten        
         clc       ;C-Bit f.Add. löschen
         lda #$58  ;XPos Sprite 0       
         sta $d000 ; setzen             
         adc #$18  ;$18 (dez.24) add.   
         sta $d002 ; u. XPos Spr.1 setz.
         adc #$18  ;$18 (dez.24) add.   
         sta $d004 ; u. XPos Spr.2 setz.
         adc #$18  ;usw.                
         sta $d006                      
         adc #$18                       
         sta $d008                      
         adc #$18                       
         sta $d00a                      
         adc #$18                       
         sta $d00c                      
         adc #$18  ;$18 (dez.24) add.   
         sta $d00e ; u. XPos Spr7 setz. 
Bis  hierhin hätten wir nun die wichtig-
sten Spritedaten initialisiert. Dadurch,
daß diese in  jedem  Frame  neu  gesetzt
werden,  können Sie im AGSP-Bereich pro-
blemlos auch noch acht  weitere  Sprites
sich  bewegen  lassen.  Sie müssen deren
Spritedaten dann nur am Ende  der  AGSP-
Routine  wieder in die VIC-Register ein-
kopieren. Nun folgt noch  die  Initiali-
sierung  der Spritepointer. Zunächst die
für die Sprites der ersten  Spritezeile,
deren Pointer ja im Video-RAM ab Adresse
$0000 untergebracht sind, und sich somit
in  den  Adressen von $03f8-$03ff befin-
den. Anschließend werden die Spritepoin-
ter für die zweite Spritereihe eingetra-
gen, die sich  im  normalen  Bildschirm-
speicher  bei  $0400,  in  den  Adressen
$07f8-$07ff befinden. Das  abschließende
schreiben des Wertes 3 in Register $DD00
stellt sicher, daß der 16K-Adressbereich
des  VICs  auf  den unteren Bereich, von
$0000 bis $3FFF, gelegt ist:            
         ldx #$30  ;Spr.Pointer Spr0=$30
         stx $03f8 ; bis Spr7=$37 in    
         inx       ; die Pointeradressen
         stx $03f9 ; $03F8-$03FF ein-   
         inx       ; tragen             
         stx $03fa                      
         inx                            
         stx $03fb                      
         inx                            
         stx $03fc                      
         inx                            
         stx $03fd                      
         inx                            
         stx $03fe                      
         inx                            
         stx $03ff                      
         inx       ;Spr.Pointer Spr0=$38
         stx $07f8 ; bis Spr8=$3F in    
         inx       ; die Pointeradressen
         stx $07f9 ; $07F8-$07FF ein-   
         inx       ; tragen             
         stx $07fa                      
         inx                            
         stx $07fb                      
         inx                            
         stx $07fc                      
         inx                            
         stx $07fd                      
         inx                            
         stx $07fe                      
         inx                            
         stx $07ff                      
         lda #$03  ;VIC-Adressraum auf  
         sta $dd00 ; $0000-$3FFF schalt.
b) DAS GLÄTTEN DES IRQS                 
Der nun folgende Teil  der  AGSP-Routine
ist für das Glätten des IRQs verantwort-
lich. Ausserdem wird hier der Border-IRQ
wieder als  nächste  IRQ-Quelle  festge-
legt,  womit diese Arbeit nun auch erle-
digt wäre:                              
     dec $d019   ;IRQ-ICR freigeben     
     lda #$1d    ;Nächster Raster-IRQ   
     sta $d012   ; bei Zeile $1D        
     lda #<irq2  ;Adresse Glättungs-    
     sta $fffe   ; IRQ in $FFFE/$FFFF   
     lda #>irq2  ; eintragen            
     sta $ffff                          
     cli         ;IRQs erlauben         
ch:  nop         ;Insgesamt 23 NOPs, in 
     ...         ; denen der Glättungs- 
     nop         ; IRQ ausgelöst wird   
     bne ch                             
Beachten  Sie  bitte,  daß  das Programm
hier nicht mehr normal fortgesetzt wird,
sondern daß innerhalb der  23  NOPs  auf
den  Glättungs-IRQ  bei  "IRQ2" gewartet
wird.  Selbiger  folgt   gleich   diesem
Stückchen  Source-Code,  wobei  ihm  ein
RTS-Befehl vorangestellt  ist,  der  mit
dem Label "Cycles" assoziiert wird. Die-
ser RTS-Befehl wird später  im  AGSP-IRQ
desöfteren  zum  Verzögern angesprungen.
Zusammen mit dem aufrufenden  JSR-Befehl
werden  so  12 Taktzyklen verbraucht (je
Befehl 6 Zyklen):                       
cycles:                                 
     rts         ;Verzög.-Unterroutine  
irq2:pla         ;(IRQ-) Prozessorstatus
     pla         ; und Rücksprungadresse
     pla         ; vom Stapel werfen    
     dec $d019   ;VIC-ICR freigeben     
     lda #$f8    ;Nächster Raster-IRQ   
     sta $d012   ;bei Zeile $F8         
     lda #<border;Adresse der Border-IRQ
     sta $fffe   ; -Routine in Vektor   
     lda #>border; bei $FFFE/$FFFF ein- 
     sta $ffff   ; tragen               
     lda #$c8    ;40-Zeichen-Darst.     
     sta $d016   ; einschalten          
     lda #$06    ;Video-RAM nach $0000  
     sta $d018   ; verschieben (für Spr.
                   Pointer 1.Spr.Zeile, 
                   sh. oberste 4 Bits!) 
     nop         ;verzögern             
     lda $d012   ;Und den letzten Takt- 
     cmp #$1d    ;Zyklus korrigieren    
     beq line    ; (IRQ-Glättung)       
line:lda #$00                           
     ...                                
c) DIE FLD-ROUTINE                      
Nun  folgt  der  wichtige Teil der AGSP-
Routine. Zunächst einmal noch ein  wenig
Verwaltungsarbeit.  Wir  setzen hier den
Bildschirmbereich, in dem das VSP-Timing
unergebracht ist auf schwarz und  setzen
schon  einmal die Y-Positionen der Spri-
tes für die zweite Spritezeile des  Sco-
reboards (wie Sie aus unseren Kursteilen
über die Spriteprogrammierung wissen, so
wird die neue Y-Koordinate erst dann vom
VIC  übernommen, wenn die ersten Sprites
fertig gezeichnet sind  -  somit  können
wir  die  neuen  Koordinaten  irgendwann
setzen, wenn der VIC die  alten  Sprites
noch zeichnet - was hier der Fall ist): 
line     lda #$00   ;Bildschirm und Rah-
         sta $d020  ; mein auf 'schwarz'
         sta $d021  ; schalten          
         jsr cycles ;3*12=36 Zyklen     
         jsr cycles ; verzögern         
         jsr cycles                     
         bit $ea    ;3 Zyklen verz.     
         ldy #$1e+21;YPos=YPos+21       
         sty $d001  ; und für die Spr0- 
         sty $d003  ; Spr7 setzen       
         sty $d005                      
         sty $d007                      
         sty $d009                      
         sty $d00b                      
         sty $d00d                      
         sty $d00f                      
Nach diesen mehr organisatorisch wichti-
gen  Aufgaben folgt nun die FLD-Routine,
die das Timing zur VSP-Routine  ausglei-
chen soll:                              
fld:  ldx #$27    ;Max. Anz. FLD-Durchl.
      ldy #$01    ;Index d011/d018-Tab. 
fldlp:jsr cycles  ;12 Zyklen verz.      
      lda field1,y;Wert für $d011 holen 
      sta $d011   ; und setzen          
      lda field2,y;Wert für $d018 holen 
      sta $d018   ; und setzen          
      nop         ;6 Zyklen verz.       
      nop                               
      nop                               
      iny         ;Tab-Index+1          
      dex         ;FLD-Durchläufe-1     
      cpx <fldcnt ;=erforderliche Anz.  
      bne fldlp   ; Durchl.?Nein->Weiter
      nop         ;Sonst 14 Zyklen      
      jsr cycles  ; verzögern           
      lda field2,y;und letzten Wert für 
      iny         ; $d018 setzen        
      sta $d018                         
 (Anm. d. Red.: Bitte wählen Sie nun den
  2. Teil des Kurses aus dem Textmenu)  
Valid HTML 4.0 Transitional Valid CSS!