Magic Disk 64

home to index to html: MD9402-KURSE-IRQ-KURS_4.1.html
        Interrupt-Kurs - Teil 4         
     "Die Hardware ausgetrickst..."     
Herzlich  Willkommen  zum  vierten  Teil
unseres IRQ-Kurses.  In  dieser  Ausgabe
möchten  wir uns mit sehr zeitkritischen
Rastereffekten  beschäftigen  und   kurz
zeigen,  wie  man den oberen und unteren
Bildschirmrand mit Hilfe  von  Rasterin-
terrupts verschwinden lassen kann.      
1) DIE TOP- UND BOTTOM-BORDER-ROUTINE   
Wie  Sie  ja  sicherlich wissen, ist der
Bildschirm des C64 auf  einen  sichbaren
Bereich  von  320x200  Pixeln, oder auch
40x25 Textzeichen beschränkt.  Der  Rest
des  Bildschirms ist von dem meist hell-
blauen  Bildschirmrahmen  verdeckt   und
kann  in der Regel nicht genutzt werden.
Werfen Sie jetzt jedoch einen Blick  auf
diese Zeilen, so werden Sie feststellen,
daß  das  Magic-Disk-Hauptprogramm genau
25 Textzeilen,  die  maximale  vertikale
Anzahl  also,  darstellt und trotzdem am
oberen Bildschirmrand die  Seitennummer,
sowie  am unteren Bildschirmrand das MD-
Logo zu sehen sind. Ganz  offensichtlich
haben  wir  es geschafft, den Bildschirm
auf  wundersame  Weise  zu   vergrößern!
Tatsächlich   schaltet   das   MD-Haupt-
programm den oberen  und  unteren  Bild-
schirmrand  schlichtweg  ab,  so daß wir
auch hier noch etwas  darstellen  können
und  auf  diese Weise mehr Informationen
auf  einer   Bildschirmseite   abzulesen
sind.  Dies ist wieder einmal nichts an-
deres als  ein  Rastertrick.  Noch  dazu
einer  der  simpelsten  die es gibt. Wie
einfach er  zu  programmieren  ist  soll
folgendes  kleines  Rasterprogramm  ver-
deutlichen. Sie finden es auf dieser  MD
unter  dem Namen "BORDERDEMO" und müssen
es wie immer mit ",8,1" laden  und  mit-
tels "SYS4096" starten:                 
INIT: SEI         ;IRQ sperren          
      LDA #$7F    ;Timer-IRQ            
      STA $DC0D   ; abschalten          
      LDA $DC0D   ;ICR löschen          
      LDA #$F8    ;Rasterzeile $F8 als  
      STA $D012   ; Interrupt-Auslöser  
      LDA $D011   ; festlegen (incl. dem
      AND #$7F    ; Löschen des HI-Bits)
      STA $D011                         
      LDA #$01    ;Raster als IRQ-      
      STA $D01A   ; Quelle wählen       
      LDX #<(IRQ) ;IRQ-Vektoren auf     
      LDY #>(IRQ) ; eigene Routine      
      STX $0314   ; verbiegen           
      STY $0315   ;                     
      LDA #$00    ;Letzte VIC-Adr. auf  
      STA $3FFF   ; 0 setzen            
      LDA #$0E    ;Rahmen- u. Hinter-   
      STA $D020   ; grundfarben auf     
      LDA #$06    ; hellblau/blau       
      STA $D021   ; setzen              
      LDY #$3F    ;Sprite-Block 13      
      LDA #$FF    ; ($0340) mit $FF     
LOOP2 STA $0340,Y ; füllen              
      DEY                               
      BPL LOOP2                         
      LDA #$01    ;Sprite 0             
      STA $D015   ; einschalten         
      STA $D027   ; Farbe="Weiß"        
      LDA #$0D    ;Spritezeiger auf     
      STA $07F8   ; Block 13 setzen     
      LDA #$64    ;X- und Y-Pos.        
      STA $D000   ; auf 100/100         
      STA $D001   ; setzen              
      CLI         ;IRQs freigeben       
      RTS         ;ENDE                 
IRQ   LDA $D011   ;Bildschirm           
      AND #$F7    ; auf 24 Zeilen       
      STA $D011   ; Umschalten          
      DEC $D019   ;VIC-ICR löschen      
      LDX #$C0    ;Verzögerungs-        
LOOP1 INX         ; schleife            
      BNE LOOP1                         
      LDA $D011   ;Bildschirm           
      ORA #$08    ; auf 25 Zeilen       
      STA $D011   ; zurückschalten      
      INC $D001   ;Sprite bewegen       
END   JMP $EA31   ;Weiter zum SYS-IRQ   
Wie Sie sehen, besteht  die  eigentliche
IRQ-Routine, die den  Border  abschaltet
nur aus  einer  handvoll  Befehlen.  Die
Initialisierung der Routine sollte Ihnen
noch aus dem  letzten  Kursteil  bekannt
sein. Wir  sperren  hier  zunächst  alle
IRQs und verhindern, daß CIA-A ebenfalls
IRQs auslöst, damit  unser  Rasterinter-
rupt nicht gestört  wird.  Als  nächstes
wird Rasterzeile $F8  als  Interruptaus-
löser festgelegt, was  auch  einen  ganz
bestimmten Grund  hat,  wie  wir  weiter
unten sehen werden. Nun sagen  wir  noch
dem VIC, daß  er  Rasterinterrupts  aus-
lösen soll, und verbiegen den IRQ-Vektor
bei $0314/$0315 auf unsere  eigene  Rou-
tine namens  "IRQ".  Die  nun  folgenden
Zeilen dienen  lediglich  "kosmetischen"
Zwecken. Wir  setzen  hier  Rahmen-  und
Hintergrundfarben auf die  Standardwerte
und  schalten  Sprite  0  ein,  das  von
unserer Interruptroutine in  der  Verti-
kalen pro IRQ um einen  Pixel  weiterbe-
wegt werden soll. Zudem wird der Sprite-
block, der dieses Sprite darstellt,  mit
$FF gefüllt, damit wir ein schönes  Qua-
drat auf dem Bildschirm sehen und keinen
Datenmüll.  Nach   Freigabe   der   IRQs
mittels "CLI" wird dann wieder  aus  dem
Programm  zurückgekehrt.  Von   nun   an
arbeitet  unsere  kleine,   aber   feine
Raster-IRQ-Routine.   Damit   Sie    sie
verstehen, müssen wir nun ein  wenig  in
die Funktionsweise des VIC einsteigen:  
Normalerweise zeigt  uns  der  Videochip
des C64, wie oben schon erwähnt, ein  25
Text-, bzw. 200 Grafikzeilen hohes Bild.
Nun können wir die  Bildhöhe  mit  Hilfe
von Bit 3 in Register 17 des VICs auf 24
Textzeilen reduzieren. Setzen wir es auf
"1",  so  werden  25  Textzeilen  darge-
stellt, setzen wir es auf "0", so  sehen
wir lediglich 24 Textzeilen. Im  letzte-
ren  Fall  werden  dann   jeweils   vier
Grafikzeilen  des  oberen  und   unteren
Bildschirmrandes  vom   Bildschirmrahmen
überdeckt. Diese Einschränkung  ist  vor
allem  bei  der   Programmierung   eines
vertikalen Soft-Scrollers von Bedeutung.
Effektiv zeichnet der VIC nun  also  den
oberen Bildschirmrand vier  Rasterzeilen
länger und den unteren  vier  Rasterzei-
len  früher.  Um  nun  den   Rahmen   zu
zeichnen kennt die Schaltlogik  des  VIC
zwei  Rasterzeilen,  die  er   besonders
behandeln  muß.  Erreicht   er   nämlich
Rasterzeile $F7, ab der  der  Bildschirm
endet, wenn die  24  Textzeilen-Darstel-
lung aktiv ist, so prüft er,  ob  Bit  3
von Register 17 gelöscht ist.  Wenn  ja,
so beginnt er den Rand zu zeichnen, wenn
nein, so fährt er normal fort.  Erreicht
er dann Rasterzeile $FB,  die  das  Ende
eines 25-zeiligen Bildschirms darstellt,
wird nochmals geprüft, ob das obige  Bit
auf 0 ist. Wenn ja, so weiß der VIC, daß
er mit dem Zeichnen  des  Rahmens  schon
begonnen hat. Wenn nein, so  beginnt  er
erst jetzt damit. Mit unserem  Interrupt
tricksen wir den armen Siliziumchip  nun
aus. Unsere Routine wird immer  in  Ras-
terzeile $F8  angesprungen,  also  genau
dann, wenn der VIC die 24-Zeilen-Prüfung
schon vorgenommen hat. Da  die  Darstel-
lung auf 25  Zeilen  war,  hat  er  noch
keinen Rand  gezeichnet.  Unsere  Inter-
ruptroutine schaltet  nun  aber  auf  24
Zeilen  um  und  gaukelt  dem  VIC   auf
diese Weise vor, er hätte schon mit  dem
Zeichnen des Randes begonnen, weshalb er
nicht nocheinmal beginnen muß, und somit
ohne zu  zeichnen  weitermacht.  Dadurch
erscheinen  unterer  und  oberer   Bild-
schimrand in der  Hintergrundfarbe,  und
es ist kein  Rahmen  mehr  sichtbar.  In
diesen  Bereichen  kann  man  nun   zwar
keinen  Text  oder  Grafik   darstellen,
jedoch  sind  Sprites,  die  sich   hier
befinden durchaus sichtbar!  Sie  werden
normalerweise nämlich einfach vom Rahmen
überdeckt, sind aber dennoch  vorhanden.
Da der Rahmen nun aber  weg  ist,  sieht
man  auch  die  Sprites,  wie  das  sich
bewegende Sprite  0  unserer  Interrupt-
routine beweist!                        
Wichtig an unserer Routine ist nun noch,
daß wir vor Erreichen des  oberen  Bild-
randes die Darstellung nocheinmal auf 25
Zeilen zurückschalten, damit  der  Trick
beim nächsten Rasterdurchlauf nocheinmal
klappt. Hierbei darf  natürlich  frühes-
tens dann umgeschaltet werden, wenn  der
Rasterstrahl an der  zweiten  Prüf-Posi-
tion, Rasterzeile $FB, schon vorbei ist.
Dies wird durch die kleine Verzögerungs-
schleife bewirkt, die genau 4 Rasterzei-
len wartet, bevor mit dem anschließenden
ORA-Befehl Bit 3 in Register 17 des  VIC
wieder gesetzt  wird.  Am  Ende  unseres
Interrupts bewegen wir das  Sprite  noch
um eine Y-Position weiter und verzweigen
zum   Betriebssystem-IRQ,   damit    die
Systemaufgaben trotz abgeschalteter  CIA
dennoch ausgeführt  werden.  Die  inter-
ruptauslösende  Rasterzeile  muß   nicht
nochmal neu eingestellt werden,  da  wir
diesmal nur eine Rasterzeile haben,  die
jedesmal wenn sie  erreicht  wird  einen
Interrupt auslöst.                      
Wollen wir nun noch  klären,  warum  wir
bei  der  Initialisierung  eine   0   in
Adresse $3FFF geschrieben haben. Wie Sie
vielleicht wissen, kann  der  VIC  Spei-
cherbereiche von lediglich  16KB  adres-
sieren, aus denen er  sich  seine  Daten
holt. Im Normalfall ist das der  Bereich
von $0000-$3FFF.  Die  letzte  Speicher-
zelle seines Adressbereichs hat nun eine
besondere Funktion. Der Bit-Wert, der in
ihr steht, wird nämlich in allen Spalten
der Zeilen des nun nicht  mehr  überdek-
kten Bildschirmrandes dargestellt -  und
zwar immer in schwarzer Farbe. Durch das
Setzen dieser Zelle auf 0 ist hier  also
gar  nichts  sichtbar.   Schreiben   wir
jedoch  bei  aktivierter   Borderroutine
mittels   "POKE16383,X"   andere   Werte
hinein, so werden je nach Wert mehr oder
weniger  dicke,  vertikale   Linien   in
diesem Bereich  sichtbar.  Durch  Setzen
aller Bits mit Hilfe des Wertes 255 (mit
Rahmenfarbe=schwarz), können  wir  sogar
einen scheinbar vorhandenen  Bildschirm-
rand simulieren!                        
Vielleicht fällt Ihnen nun auch noch ein
interessanter Nebeneffekt  auf:  nachdem
wir die oberen und  unteren  Bildschirm-
grenzen  abgeschaltet  haben,  gibt   es
Spritepositionen, an  denen  das  Sprite
zweimal zu sehen ist. Nämlich sowohl  im
oberen, als auch  im  unteren  Teil  des
Bildschirms. Das liegt  daran,  daß  das
PAL-Signal,  welches  der  VIC   erzeugt
313 Rasterzeilen  kennt,  wir  aber  die
Y-Position eines  Sprites  nur  mit  256
verschiedenen  Werten  angeben   können.
Dadurch stellt der VIC das Sprite an den
Y-Positionen zwischen 0 und 30 sowohl am
unteren, als auch am  oberen  Rand  dar.
Bei eingeschalteten Rändern fiel  dieser
Nebeneffekt nie auf,  da  diese  Sprite-
positionen normalerweise im unsichtbaren
Bereich des Bildschirms liegen,  wo  sie
vom Bildschirmrahmen überdeckt werden.  
Bleibt noch zu erwähnen, daß wir mit ei-
nem ähnlichen Trick auch die  seitlichen
Ränder des Bildschirms verschwinden las-
sen  können,  nur  ist  das  hier   viel
schwie-  riger,  da  es  auf  ein   sehr
genaues Timing ankommt.  Wie  man  damit
umgeht  müssen  wir  jetzt   erst   noch
lernen, jedoch werde ich in den nächsten
Kursteilen auf dieses Problem nocheinmal
zu sprechen kommen.                     
2) EINZEILEN-RASTER-EFFEKTE             
Kommen wir nun zu dem oben schon erwähn-
ten Timing-Problem. Vielleicht haben Sie
nach  Studieren  des  letzten  Kursteils
einmal versucht  einzeilige  Farbraster-
effekte zu programmieren. Das heißt also
daß Sie  gerade  eine  Zeile  lang,  die
Bildschirmfarben wechseln, und sie  dann
wieder  auf  die  Normalfarbe  schalten.
Hierzu wären dann zwei Raster-Interrupts
notwendig,  die  genau  aufeinander   zu
folgen haben  (z.B.  in  Zeile  $50  und
$51).  Wenn  Sie  verschucht  haben  ein
solches Rasterprogramm zu schreiben,  so
werden Sie bestimmt eine Menge  Probleme
dabei gehabt haben, da  die  Farben  nie
genau   eine   Rasterzeile   lang    den
gewünschten  Wert  enthielten,   sondern
mindestens   eineinhalb   Zeilen    lang
sichtbar  waren.  Dieses   Problem   hat
mehrere  Ursachen,   die   hauptsächlich
durch  die  extrem  schnelle  Gesschwin-
digkeit  des   Rasterstahls   entstehen.
Selbiger bewegt sich nämlich in genau 63
Taktzyklen einmal von links nach rechts.
Da innerhalb  von  63  Taktzyklen  nicht
allzu viele Instruktionen vom  Prozessor
ausgeführt  werden  können,  kann  jeder
Befehl zuviel eine zeitliche Verzögerung
verursachen, die  eine  Farbänderung  um
mehrere Pixel nach rechts verschiebt, so
daß die Farbe nicht am Anfang der Zeile,
sondern erst  in  ihrer  Mitte  sichtbar
wird. Da ein IRQ  nun  aber  verhältnis-
mäßig viel Rechenzeit benötigt,  bis  er
abgearbeitet ist, tritt  ein  Raster-IRQ
in der nächsten Zei- le  meist  zu  früh
auf, nämlich noch bevor  der  erste  IRQ
beendet   wurde!   Dadurch   gerät   das
Programm natürlich  vollkommen  aus  dem
Takt  und  kann  ggf.  sogar  abstürzen!
Noch dazu muß  ein  weiterer,  hardware-
mäßiger Umstand beachtet werden: hat man
normale Textdarstellung  auf  dem  Bild-
schirm eingeschaltet,  so  muß  der  VIC
nämlich  jedes  mal  zu   Beginn   einer
Charakterzeile die 40  Zeichen  aus  dem
Video-RAM lesen, die er in den folgenden
acht Rasterzeilen darzustellen hat,  und
sie entsprechend in ein Videosignal  um-
wandeln. Um diesen Vorgang durchzuführen
hält er den Prozessor für eine Zeit  von
genau 42 Taktzyklen an, damit  er  einen
ungestörten Speicherzugriff machen kann.
Eine Charakterzeile  ist  übrigens  eine
der 25 Textzeilen. Da der Bildschirm  in
der Regel bei Rasterzeile  $32  beginnt,
und jede achte Rasterzeile  ein  solcher
Zugriff durchgeführt  werden  muß,  sind
all  diese  Zeilen  besonders  schwierig
über einen Raster-IRQ programmierbar, da
erst nach dem VIC-Zugriff ein Raster-IRQ
bearbeitet werden kann, der jedoch durch
den Zugriff schon viel zu spät eintritt,
da die  Zeile  in  der  Zwischenzeit  ja
schon zu zwei Dritteln aufgebaut  wurde.
Hier  muß  man  sich  eines   speziellen
Tricks  behelfen.  Um  selbigen   besser
erläutern zu können, wollen wir uns  das
folgende Beispielprogramm  einmal  etwas
näher anschauen:                        
;************************************** 
INIT  SEI         ;IRQs sperren         
      LDA #$7F    ;CIA-A-IRQs           
      STA $DC0D   ; unterbinden         
      LDA $DC0D                         
      LDA #$82    ;Rasterzeile $82 als  
      STA $D012   ; Interruptauslöser   
      LDA $D011   ; festlegen (incl.    
      AND #$7F    ; Löschen des         
      STA $D011   ; HI-Bits             
      LDA #$01    ;Rasterstrahl ist     
      STA $D01A   ; IRQ-Auslöser        
      LDX #<(IRQ) ;IRQ-Vektor auf eigene
      LDY #>(IRQ) ; Routine verbiegen   
      STX $0314                         
      STY $0315                         
      CLI         ;IRQs freigeben       
VERZ  RTS         ;ENDE                 
;************************************** 
IRQ   DEC $D019   ;VIC-IRQ freigeben    
      JSR VERZ    ;Verzögern...         
      JSR VERZ                          
      NOP                               
      LDY #$00    ;Farb-Index init.     
LOOP1 LDX #$08    ;Char-Index init.     
LOOP2 LDA $1100,Y ;Farbe holen          
      STA $D020   ; und im Rahmen-und   
      STA $D021   ; Hintergrund setzen  
      INY         ;Farb-Index+1         
      DEX         ;Char-Index-1         
      BEQ LOOP1   ;Wenn Char=0 verzweig.
      LDA VERZ    ;Sonst verzögern...   
      JSR VERZ                          
      JSR VERZ                          
      JSR VERZ                          
      CPY #$48    ;Farb-Index am Ende?  
      BCC LOOP2   ;Nein also weiter     
      LDA #$0E    ;Sonst Rahmen/Hinter- 
      STA $D020   ; grund auf           
      LDA #$06    ; Standardfarben      
      STA $D021   ; zurücksetzen        
      JMP $EA31   ;IRQ mit SYS-IRQ beend
Besten laden Sie das Programm einmal und
starten es mit "SYS4096". Sie sehen  nun
einen schönen Rasterfarbeneffekt auf dem
Bildschirm, wo wir ab Rasterzeile $83 in
jeder Zeile die Rahmen- und Hintergrund-
farbe ändern. Ich habe  hierbei  Farbab-
stufungen benutzt,  die  schöne  Balken-
effekte  erzeugen.   Die   entsprechende
Farbtabelle liegt ab  Adresse  $1100  im
Speicher und kann  natürlich  von  Ihnen
auch verändert werden.  Kommen  wir  nun
zur Programmbeschreibung. Die  Initiali-
sierungsroutine sollte Ihnen keine  Pro-
bleme bereiten. Wir schalten  wie  immer
die CIA ab, sagen dem VIC, daß er  einen
Raster-IRQ generieren soll,  legen  eine
Rasterzeile (hier Zeile  $82)  als  IRQ-
Auslöser fest, und  verbiegen  die  IRQ-
Vektoren  auf  unser  eigenes  Programm.
Etwas seltsam mag Ihnen nun die  eigent-
liche IRQ-Routine vorkommen. Nachdem wir
mit dem  DEC-Befehl  dem  VIC  bestätigt
haben, daß der IRQ  bei  uns  angekommen
ist,   folgen   nun   drei,    scheinbar
sinnlose, Befehle. Wir springen nämlich 
das   Unterprogramm   "VERZ"   an,   das
lediglich aus einem RTS-Befehl  besteht,
und somit  direkt  zu  unserem  Programm
zurückverzweigt. Zusätzlich  dazu  folgt
noch ein NOP-Befehl der ebensowenig tut,
wie die  beiden  JSRs  zuvor.  Der  Sinn
dieser Instruktionen liegt lediglich  in
einer  Zeitverzögerung,  mit   der   wir
abwarten, bis der Rasterstrahl  am  Ende
der Zeile $82 angelangt ist. Wir  hätten
hier auch jeden anderen Befehl verwenden
können, jedoch ist es mit JSRs  am  ein-
fachsten zu verzögern,  da  ein  solcher
Befehl, ebenso  wie  der  folgende  RTS-
Befehl, jeweils 6 Taktzyklen verbraucht.
Durch  einen  JSR-Befehl  vergehen  also
genau 12  Taktzyklen,  bis  der  nächste
Befehl abgearbeitet wird.  Da  ein  NOP-
Befehl, obwohl  er  nichts  macht,  zwei
Taktzyklen zur Bearbeitung benötigt, und
wir zwei JSRs verwenden,  verzögern  wir
also um insgesamt 26  Taktzyklen.  Genau
diese  Verzögerung  ist  dem  DEC-Befehl
zuvor und den folgenden  LDX-  und  LDY-
Befehlen   notwendig,   um   soviel   zu
verzögern, daß sich der Rasterstrahl bis
ans Ende  der  Rasterzeile  bewegt  hat.
Hinzu kommt daß wir  die  42  Taktzyklen
hinzurechnen müssen,  die  der  VIC  den
Prozessor sowieso schon gestoppt hat, da
Rasterzeile  $82  eine  der  schon  oben
angesprochenen Charakterzeilen darstellt
($82-$32=$50/8=10 - ohne Rest!).        
 Laden Sie nun bitte Teil 2 des Kurses! 
Valid HTML 4.0 Transitional Valid CSS!