Magic Disk 64

home to index to html: MD9409-KURSE-IRQ-KURS_11.1.html
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 11)               
----------------------------------------
Herzlich  Willkommen zum elften Teil un-
seres IRQ-Kurses. Wie schon in den letz-
ten Kursteilen, werden wir uns auch die-
sen Monat mit  der  Spriteprogrammierung
der besonderen Art beschäftigen. Es soll
um  einige  Tricks  gehen, mit denen man
den Bildschirm  auch  über  alle  Ränder
hinaus  mit Gafikdaten füllen kann. Die-
sen Effekt nennt man "ESCOS", der  Dreh-
und  Angelpunkt  für die Rastertricks in
diesem Kursteil sein wird.              
1) UNSER ZIEL                           
In  früheren  Kursteilen  hatten  wir ja
schon einmal besprochen, auf welche  Art
und Weise oberer und unterer, sowie lin-
ker  und  rechter  Bildschirmrand  abge-
schaltet  werden.  Wir  hatten weiterhin
gelernt, daß in  diesen  Bereichen  aus-
schließlich  Sprites  auftauchen können,
die  durch  die  abgeschalteten   Ränder
sichtbar  sind, wo sie sonst von letzte-
ren überdeckt werden. Wir hatten  ebenso
eine  Möglichkeit  kennengelernt,  beide
Ränder, die horizontalen und vertikalen,
gleichzeitig abzuschalten, wobei wir auf
sehr exaktes Timing achten  mussten,  da
das  Abschalten  der  linken und rechten
Bildschirmbegrenzung eine hohe  Genauig-
keit  erforderte. Desweiteren wird Ihnen
aus dem letzten Kursteilen bestimmt noch
die Sprite-Multiplexer-Routine in Kombi-
nation  mit  einem Moviescroller im Kopf
sein, mit der wir 104 Sprites gleichzei-
tig auf den Bildschirm brachten. Wie Sie
sich  vielleicht erinnern, waren wir da-
bei an gewisse Grenzen gebunden. So  war
z.B.  zwischen  zwei  Spritezeilen immer
ein Abstand von ca. 2  Rasterzeilen  er-
forderlich,  die  wir benötigten, um die
Spritepointer   sowie   die   neuen   Y-
Positionen  der  Sprites zu setzen. Des-
weiteren mussten  wir  ein  komplizierte
Timingroutine   benutzen,  die  zwischen
Charakterzeilen (jede achte Rasterzeile,
in der der VIC den  Prozessor  für  eine
Dauer von 42 Taktzyklen anhält) und nor-
malen Rasterzeilen zu unterscheiden hat-
te.  In dieser Folge unseres Kurses wol-
len wir nun all diese Komponenten mitei-
nander  verbinden  und  eine Möglichkeit
kennenlernen, Timingprobleme durch  Cha-
rakterzeilenberücksichtigung,  zu  umge-
hen. Das Endergebnis wird  ein  flächen-
deckend  (!)  mit Sprites belegter Bild-
schirm sein, wobei weder Leerräume  zwi-
schen  den  Sprites,  noch  im  gesamten
Bildschirmrahmen zu sehen  sein  werden!
Wir  werden also über eine Grafik verfü-
gen, die, ähnlich einem Fernsehbild, die
gesamte Bildröhrenfläche ausfüllt!      
2) ERSTES PROBLEM: DAS TIMING           
Kommen wir gleich zum Kern  dieses  Kur-
steils, dem Timing-Problem, das sich uns
entgegenstellt. Möchten wir nämlich alle
Bildschirmränder  abschalten und gleich-
zeitig auch noch die  Sprites  multiple-
xen,  so können wir programmtechnisch in
"Teufels Küche"  gelangen.  Wir  müssten
berücksichtigen, daß im sichtbaren Bild-
schirmfenster  alle  acht   Rasterzeilen
eine  Chakaterzeile auftritt, gleichzei-
tig müsste in jeder Rasterzeile der lin-
ke  und rechte Bildschirmrand abgeschal-
tet, sowie in jeder 21. Rasterzeile  die
Sprites  neu  positioniert werden. Dabei
stellen vor  allem  die  Charakterzeilen
ein  großes Problem dar. Wir müssten un-
terscheiden  zwischen  Rasterstrahlposi-
tionen im oberen und unteren Bildschirm-
rand und innerhalb des sichtbaren  Bild-
schirmfensters, und zudem noch für letz-
teren Fall  berücksichtigen,  wann  sich
der  VIC  gerade  in einer Chakaterzeile
befindet und wann in einer normalen  Ra-
sterzeile.  Dieses  Problem stellte sich
bei unseren  Raster-Effekten  nun  schon
häufiger  in den Weg, wobei wir es meist
durch einen einfachen Trick umgingen: in
der Regel benutzten wir in solchen  Fäl-
len eine FLD-Routine, die die Charakter-
zeile  im  fraglichen  Bildschirmbereich
einfach  nach unten "wegdrückte", so daß
wir in jeder Rasterzeile  63  Taktzyklen
zur  Verfügung hatten und somit ein ein-
heitliches Timing programmieren konnten.
Wir könnten diesen Effekt hier nun  auch
anwenden,  jedoch  gibt  es speziell für
diese  Anwendung  einen  weiteren,  viel
einfacherern  Trick, die Charakterzeilen
zu umgehen: da wir ja den gesamten Bild-
schirm  mit Sprites füllen möchten, kön-
nen wir davon ausgehen, daß wir  keiner-
lei  Hintergrundgrafik, bzw. Textzeichen
benötigen. Es gibt nun einen Trick,  den
wir  noch nicht kennengelernt haben, mit
dem wir  die  Charakterzeilen  ganz  ab-
schalten  können,  so  daß  nur noch die
Sprites  dargestellt  werden.  Wie  fast
immer  ist Register $D011, ein Dreh- und
Angelpunkt  der   VIC-Trickeffekt-Kiste,
für diesen Trick verantwortlich. Mit Bit
4  dieses  Registers  können wir nämlich
den gesamten Bildschirm abschalten,  was
einer  Deaktivierung  des  VICs  gleich-
kommt. Er wird durch das Löschen  dieses
Bits  veranlasst, auf dem gesamten Bild-
schirm nur noch die  Rahmenfarbe  darzu-
stellen,  und keine Charakterzeilen mehr
zu lesen.  Die  Sprites  bleiben  jedoch
weiterhin  aktiv,  obwohl  sie jetzt un-
sichbar sind, da sie jetzt auf  dem  ge-
samten  Bildschirm  mit dem Rahmen über-
deckt werden. Man könnte das Setzen  und
Löschen  des  4. Bits von Register $D011
quasi mit dem Üffnen und Schließen eines
Vorhangs vor einem Fenster  vergleichen:
Eine  Fliege  (oder  unser  Sprite), die
sich auf  der  Fensterscheibe  befindet,
ist   bei  geschlossenem  Vorhang  nicht
sichtbar. Ist letzterer jedoch geöffnet,
so sieht man  die  Fliege,  solange  sie
sich  im  sichtbaren Bereich des Fenster
bewegt, und  nicht  unter  den  seitlich
aufgerafften Vorhängen verschwindet.    
Nun,  selbst wenn die Sprites noch aktiv
sind, so nutzen Sie uns  herzlich  wenig
wenn  sie  unsichtbar sind. Deshalb gilt
es mal wieder, den VIC auszutricksen, um
das  gewünschte  Ergebnis  zu  erhalten.
Dies gestaltet sich in diesem Fall recht
einfach: Zunächst einmal schalten wir an
einer  Rasterposition,  an  der  der VIC
normalerweise den  oberen  oder  unteren
Bildschirmrand  zeichnet,  den  gesamten
Bildschirm durch Löschen von Bit  4  aus
Register $D011, ab. Erreicht der Raster-
strahl nun Rasterzeile $30, an  der  ei-
gentlich das sichtbare Bildschirmfenster
beginnt,  so prüft der VIC, ob der Bild-
schirm nun ein- oder ausgeschaltet  ist.
In  letzterem  Fall deaktiviert er seine
Zeichenaufbau-Schaltkreise bis zum näch-
sten  Erreichen  dieser  Rasterposition,
womit er  keine  einzige  Charakterzeile
mehr  liest. Anstelle dessen zeigt er in
den folgenden Rasterzeilen nur noch  die
Farbe des Bildschirmrahmens an. Wenn wir
diesen  jedoch  mit  Hilfe einer Border-
Routine bei $FA abschalten, so - oh Wun-
der  - zeigt uns der VIC den Bildschirm-
hintergrund, auf dem sich auch die Spri-
tes  herumtollen  dürfen!  Wie bei jedem
Effekt, bei dem der VIC etwas  tut,  was
er  sonst nicht tun kann, erscheint hier
dann  wieder  der  Inhalt  der   letzten
Adresse des VIC-Speichers (normalerweise
$3FFF)  in Schwarz auf Hintergrundfarbe.
Durch Schreiben des Wertes  0  in  diese
Speicherzelle  können  wir natürlich die
Schwarzen Streifen auch  abschalten  und
damit  nur die Hintergrundfarbe anzeigen
lassen.                                 
Um  diese  Vorgehensweise  nun besser zu
erläutern haben wir natürlich wieder ein
Programmbeispiel auf Lager, das ich  Ih-
nen  nun auflisten möchte. Sie finden es
auf dieser MD auch als fertig ausführba-
res  File  mit dem Namen "SPRITES-ONLY",
daß Sie wie immer mit ",8,1"  laden  und
durch ein "SYS4096" starten müssen.     
Kommen wir also zur  Initialiserungsrou-
tine  des  Beispiels,  die  bei  Adresse
$1000 beginnt:                          
INIT:                                   
    sei        ;IRQs sperren            
    lda #$7f   ;Alle CIA-IRQs abschalten
    sta $dc0d  ; (CIA1)                 
    sta $dd0d  ; (CIA2)                 
    bit $dc0d  ;CIA1-ICR löschen        
    bit $dd0d  ;CIA2-ICR löschen        
    lda #$01   ;VIC-Hintergrundstriche  
    sta $3fff  ; auf 1 setzen           
    jsr sprinit;Sprites initialiseren   
    jsr irqinit;IRQ initialiseren       
    lda #$35   ;ROMs abschalte          
    sta $01                             
    cli        ;IRQs erlauben           
spc:lda #$7f   ;Auf SPACE-Taste         
    sta $dc00  ; warten...              
    lda $dc01                           
    cmp #$ef                            
    bne spc                             
    sei        ;IRQs sperren            
    lda #$37   ;ROM wieder einschalten  
    sta $01                             
    jmp $fce2  ;und RESET auslösen      
Alles in allem für uns  keine  besondere
Initialisierung.  Wichtig  sind noch die
Routinen  "SPRINIT"  und  "IRQINIT".  In
ersterer  initialisieren  wir  lediglich
die Sprite-Positionen, sowie  die  Spri-
te-Pointer  und schalten alle acht Spri-
tes ein. Letzere  Routine  ist  für  das
Korrekte   initialisieren  unseres  IRQs
zurständig und sieht folgendermaßen aus:
IRQINIT:                                
  lda #<bordirq ;IRQ-Vektor bei         
  sta $fffe     ; $FFFE/$FFFF           
  lda #>bordirq ;auf "BORDIRQ" verbiegen
  sta $ffff                             
  lda #$1b      ;Wert für $D011 mit gel.
  sta $d011     ; High-Bit f. Rasterpos.
  lda #$fa      ;Ersten Raster-IRQ bei  
  sta $d012     ; Zeile $FA auslösen    
  lda #$81      ;VIC-Raster-IRQs        
  sta $d01a     ; erlauben              
  dec $d019     ;VIC-ICR ggf. löschen   
  rts                                   
Wie Sie sehen, aktivieren wir hier einen
Raster-IRQ für Rasterzeile $FA, der  bei
Auftreten   die  Routine  "BORDIRQ"  an-
springt, wo sich eine  ganz  gewöhnliche
Routine  zum  Abschalten  des oberen und
unteren Bildschirmrandes befindet.  Hier
das Listing dieser Routine:             
BORDIRQ:                                
  pha       ;Prozessorregs. retten      
  txa                                   
  pha                                   
  tya                                   
  pha                                   
  lda $d011 ;24-Zeilen-Darstellung      
  and #$77  ; einschalten               
  sta $d011                             
  lda #$28  ;nächster IRQ bei Zeile $28 
  sta $d012                             
  dec $d019 ;VIC-ICR löschen            
  lda #<soff;Routine für nächsten IRQ   
  sta $fffe ; "SOFF" in IRQ-Vektor      
  lda #>soff; eintragen                 
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   
Wir schalten hier also an  der  üblichen
Position  auf  24-Zeilen-Darstellung he-
runter, damit der VIC vergisst, den obe-
ren und unteren Bildschirmrand zu zeich-
nen. Gleichzeitig  wird  ein  neuer  IRQ
initialisiert,  der  bei  Erreichen  von
Rasterzeile $28 (acht  Rasterzeilen  vor
Beginn  des  sichtbaren  Bildschirmfens-
ters)  die  Routine  "SOFF"   anspringen
soll.  Diese  Routine  übernimmt nun die
Aufgabe, die Darstellung der  Charakter-
zeilen zu verhindern:                   
soff:                                   
  pha       ;Prozessorregs. retten      
  txa                                   
  pha                                   
  tya                                   
  pha                                   
  lda $d011 ;Bild ausschalten (durch    
  and #$6F  ; ausmaskieren von Bit4)    
  sta $d011                             
  lda #$32  ;nächster IRQ bei Raster-   
  sta $d012 ; zeile $32                 
  dec $d019 ;VIC-ICR löschen            
  lda #<son ;Nächster IRQ soll auf      
  sta $fffe ; Routine "SON" springen    
  lda #>son                             
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   
Wie Sie sehen eine recht einfache Aufga-
be:   durch   eine  AND-Verknüpfung  des
$D011-Inhalts mit dem Wert $6F wird ein-
fach    das   4.Bit   dieses   Registers
gelöscht. Gleichzeitig löschen wir dabei
Bit 7, das ja das High-Bit  der  Raster-
strahlposition  angibt,  womit  wir also
auch dieses Bit für  den  folgenden  Ra-
ster-IRQ  bei Zeile $32 vorbereitet hät-
tem. Die Routine, die hier  abgearbeitet
werden  soll,  heisst  "SON" und ist für
das  Wiedereinschalten  des  Bildschirms
verantwortlich.  Da sich Rasterzeile $32
im sichtbaren Fenster befindet wäre  so-
mit  der  VIC  überlistet und soweit ge-
bracht,  daß  er  keine  Charakterzeilen
mehr  liest,  geschweige denn darstellt.
Gleichzeitig schaltet diese Routine wie-
der auf die 25-Zeilen-Darstellung zurück
(Bit  3  von  $D011 muß gesetzt werden),
damit das Abschalten des Borders auch im
nächsten Rasterstrahldurchlauf  funktio-
niert:                                  
SON:                                    
  pha          ;Prozessorregs. retten   
  txa                                   
  pha                                   
  tya                                   
  pha                                   
  lda $d011    ;Bild und 25-Zeilen-     
  ora #$18     ; Darstellung einschalten
  sta $d011                             
  lda #$fa     ;nächster IRQ wieder bei 
  sta $d012    ; Zeile $FA              
  dec $d019    ;VIC-ICR löschen         
  lda #<bordirq;Wieder "BORDIRQ" in     
  sta $fffe    ; IRQ-Vektor eintragen   
  lda #>bordirq                         
  sta $ffff                             
  pla       ;Prozessorregs. wieder vom  
  tay       ; Stapel holen und IRQ      
  pla       ; beenden                   
  tax                                   
  pla                                   
  rti                                   
Nachdem Register $D011 auf den gewünsch-
ten  Wert  zurückgesetzt wurde, wird der
IRQ wieder für die Routine "BORDIRQ" bei
Rasterzeile $FA vorbereitet, womit  sich
der  Kreis  schließt und unser Programm-
beispiel komplett ist.                  
3) "ESCOS" - EINEN SCHRITT WEITER       
Nachdem  wir  nun  unser  Timing-Problem
gelöst,  und  die  störenden  Charakter-
Zeilen  aus dem Weg geräumt haben, möch-
ten wir wieder zu  unserer  eigentlichen
Aufgabenstellung zurückkehren: dem bild-
schirmfüllenden Darstellen von  Sprites.
Hierzu  müssen  wir,  nachdem oberer und
unterer Bildschirmrand, sowie  die  Cha-
rakterzeilen     abgeschaltet    wurden,
zusätzlich auch noch die  Bildschirmrän-
der  links  und rechts deaktivieren. Das
Funktionsprinzip einer solchen  Sidebor-
derroutine  sollte  Ihnen noch aus einem
der ersten Kursteile im Kopf sein: durch
rechtzeitiges Umstellen von 40- auf  38-
Spaltendarstellung  und  zurück tricksen
wir den VIC nach dem selben Prinzip aus,
wie wir es bei  den  horizontalen  Bild-
schirmrändern  tun.  Dadurch  aber,  daß
sich der Rasterstrahl  horizontal  recht
schnell  bewegt,  kommt es dabei auf ein
höchst exaktes Timing an. Einen  Taktzy-
klus  zu  früh oder zu spät funktioniert
die Routine schon nicht mehr.  Wenn  man
das  Ganze  nun  zusätzlich noch mit dem
Üffnen des oberen  und  unteren  Randes,
sowie   dem  Abschalten  der  Charakter-
Zeilen und einem Sprite-Multiplexer kom-
binieren  muß, so könnte man meinen, daß
dies  eine  recht  programmieraufwendige
Sache werden kann. Doch keine Panik, die
Umsetzung ist einfacher als Sie glauben.
Am Besten sehen Sie sich erst einmal das
Demoprogramm  "ESCOS1"  an.  Es wird wie
üblich geladen und mit  SYS4096  gestar-
tet,  und  zeigt dann einen vollends mit
Sprites gefüllten Bildschirm - und  zwar
über alle Ränder hinaus! Um so etwas nun
sebst   zu   programmieren,  werden  wir
zunächst auf die organisatirischen  Pro-
bleme und deren Lösung eingehen:        
Als  Erstes  müssen  Sie davon ausgehen,
daß wir keine IRQ-Routine  im  eigentli-
chen  Sinne  programmieren  werden. Auf-
grund des exakten Timings, das  zum  Ab-
schalten  des  linken und rechten Randes
notwendig ist, muß der Prozessor  nahezu
während  des  gesamten  Rasterdurchlaufs
damit  beschäftigt  sein,  die  richtige
Rasterposition  abzuwarten,  um zwischen
der 38- und  40-Zeilen-Darstellung  hin-
und  herzuschalten.  Dadurch  wird ledi-
glich ein einziger IRQ pro  Rasterdurch-
lauf  aufgerufen,  nämlich direkt zu An-
fang desselben, in Rasterzeile 0. Dieser
IRQ muß nun, auf die uns schon  bekannte
Art  und  Weise,  "geglättet" werden, so
daß kein einziger Taktzyklus Unterschied
zum vorherigen Rasterdurchlauf  besteht.
Ab  dann  (durch  das Glätten, das 2 Ra-
sterzeilen dauert also ab Zeile  2)  be-
ginnt  der Prozessor damit in jeder ein-
zelnen Rasterzeile den  Rand  abzuschal-
ten.  Dies  geschieht  dadurch,  daß wir
nach jedem  Umschalten  der  Spaltendar-
stellung  genau  am  Öbergangspunkt zwi-
schen sichtbarem  Bildschirmfenster  und
-rahmen,  exakt 63 Taktzyklen verzögern,
bevor dieser Vorgang wiederholt wird. So
zumindest sähe es aus,  wenn  wir  keine
Sprites darzustellen hätten. Da wir dies
jedoch tun, müssen wir weiterhin berück-
sichtigen, daß der  VIC  zum  Darstellen
der  Sprites den Prozessor ebenso anhal-
ten muß, wie beim Lesen  der  Charakter-
zeilen,  um sich die Spritedaten aus dem
Speicher zu holen. Hierbei braucht er  3
Taktzyklen  für  das  erste  Sprite, und
dann jeweils 2 Zyklen für alle weiteren,
eingeschalteten Sprites. Da wir  alle  8
Sprites  benutzen,  müssen wir also noch
den Betrag 3+7*2=17 von  den  63  Zyklen
abziehen  und  erhalten  somit  exakt 46
Taktzyklen, die der  Prozessor  pro  Ra-
sterzeile "verbrauchen" muß.            
  (Anm. d. Red.: Bitte wählen Sie jetzt 
 den zweiten Zeil des IRQ-Kurses aus dem
               Textmenu.)               
Valid HTML 4.0 Transitional Valid CSS!