Magic Disk 64

home to index to html: MD9501-KURSE-IRQ-KURS_15.html
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 15)               
----------------------------------------
Im letzten Kursteil hatten wir uns einen
ganz  besonderen Rastertrick angeschaut.
Anhand einer VSP-Routine hatten wir  ge-
lernt,  wie  einfach  es  ist, den Bild-
schirm des C64 HARDWAREMÄSSIG, also ohne
den  Prozessor  mit  großen  Bildschirm-
Verschiebe-Aktionen  zu  belasten,  nach
oben und unten zu scrollen. Dabei unter-
schied  sich  die  VSP-Routine von einer
FLD-Routine in nur einem NOP-Befehl, der
das  nötige  Timing  erzeugte,  um   den
gewünschten  Effekt auszulösen. Der FLD-
Effekt war, wie wir gesehen hatten  maß-
geblich daran beteiligt, daß der VIC das
Lesen  von  einigen Charakterzeilen ver-
gaß, weswegen wir  in  der  Lage  waren,
einzelne  Bereiche im Video-RAM zu über-
springen, und so den Bildschirm beliebig
nach oben und unten zu scrollen. In die-
sem  Kursteil soll es nun um einen nahen
Verwandten von VSP gehen. Wir werden den
HSP-Effekt besprechen. "HSP"  steht  für
"Horizontal  Screen  Position" und setzt
den VSP-Effekt quasi auf die Horizontale
um. Mit  ihm  können  wir  DEN  GESAMTEN
BILDSCHIRM  problemlos um bis zu 320 Pi-
xel nach rechts verschieben,  wobei  wir
den Prozessor nur läppische 3 Rasterzei-
len lang in Anspruch nehmen müssen.  Da-
mit  werden  schnell  scrollende Baller-
oder Jump'n Run Spiele, wie auf dem Ami-
ga  oder dem Super-NES von Nintendo auch
auf dem C64 möglich!                    
1) ZUM PRINZIP VON HSP                  
Wir  erinnern  uns:  Um  die VSP-Routine
funktionsfähig zu  machen,  mussten  wir
den  FLD-Effekt so anwenden, daß wir dem
VIC vorgaukelten, sich auf das Lesen der
nächsten Rasterzeile  vorzubereiten  und
seinen internen Lesezähler hochzuzählen,
um  die richtige Charakterzeilen-Adresse
anzusprechen. Als er nun seinen Lesevor-
gang  durchführen wollte machten wir ihn
durch FLD-Wegdrücken der Charakterzeilen
glauben, daß er doch noch nicht die ent-
sprechende  Zeile  erreicht hatte. Somit
übersprang er mehrere Adressen und somit
auch  Charakterzeilen.  Wir  ließen  ihn
also  die Charakterzeilen zu spät lesen,
was zu dem gewünschten Effekt führte.   
Einen  ähnlichen  Trick  können  wir nun
auch für die HSP-Routine  anwenden.  Wie
wir  ja  wissen, so liest der VIC ab der
Rasterposition $30 alle  8  Rasterzeilen
die  40  Zeichen,  die in den nächsten 8
Rasterzeilen zu sehen sein  sollen,  aus
dem Video-RAM, um sie anschließend anzu-
zeigen. Durch den FLD-Effekt  haben  wir
nun  schon  oft genung die erste Charak-
terzeile auf dem Bildschim vor ihm  her-
geschoben,  so  daß  der VIC diese Zeile
verspätet erreichte, und somit der Bild-
schirm nach unten weggedrückt wurde. Der
Witz  ist,  daß dieser Trick nun auch in
her Horizontalen funktioniert! Denn  so-
bald der VIC merkt, daß er sich in einer
Charakterzeile  befindet, in der er Zei-
chendaten zu Lesen und  Anzuzeigen  hat,
beginnt  er auch unverzüglich mit dieser
Arbeit, und das ohne noch auf die  hori-
zontale  Rasterposition  zu  achten,  um
ggf. festzustellen, daß er sich garnicht
am Zeilenanfang befindet! Wenn  wir  nun
also eine Art FLD-Routine einsetzen, die
nur für einen Teil der aktuellen Raster-
zeile vorschreibt, daß selbige noch kei-
ne  Charakterzeile  ist, und dann mitten
innerhalb dieser Zeile  von  uns  wieder
auf normale Darstellung zurückgeschaltet
wird,  so fängt der VIC auch prompt mit-
tendrin damit an die  Charakterdaten  zu
lesen  und  sofort auf den Bildschirm zu
bringen. Verzögern wir also  nach  einem
FLD  bis  zur Mitte der Rasterzeile, und
schalten dann wieder zurück, so wird der
Video-RAM Inhalt  um  exakt  20  Zeichen
nach  rechts versetzt auf dem Bildschirm
dargestellt, wobei die 20  letzten  Zei-
chen,  die  ja nicht mehr in diese Text-
zeile passen, automatisch  erst  in  der
nächsten  Zeile erscheinen. Es kommt so-
gar noch besser: aufgrund eines internen
Timers des VIC, der das Lesen  der  Cha-
rakterzeilen  mitbeeinflusst (es sei den
wir tricksen ihn aus) führt der VIC  den
Lesefehler  in JEDER WEITEREN Charakter-
zeile ebenso durch, so  daß  es  genügt,
lediglich  am Bildschirmanfang einmal um
einen bestimmten Wert zu  verzögern,  um
DEN  GESAMTEN  Bildschirm  wie gewünscht
nach rechts versetzt darzustellen!!!    
Um den Trick nun umzusetzen  müssen  wir
wiefolgt vorgehen: zunächst schalten wir
in   $D011  den  vertikalen  Verschiebe-
Offset (wird in  den  untersten  3  Bits
festgelegt)  auf  1,  so daß für den VIC
die erste Charakterzeile erst  eine  Ra-
sterzeile  nach  Beginn  des  sichtbaren
Bildschirmfensters folgt. Dieser  Beginn
liegt  normalerweise in Rasterzeile $30.
Durch die  Verschiebung  legen  wir  die
erste  vom VIC zu lesende Charakterzeile
jedoch in Rasterzeile $31. Verzögern wir
nun jedoch in Rasterzeile  $30  um  eine
bestimmte  Anzahl Taktzyklen, und schal-
ten wir dann die  horizontale  Verschie-
bung  mittendrin wieder auf 0 zurück, so
merkt der VIC  plötzlich,  daß  er  sich
doch  schon  in einer Charakterzeile be-
findet und fängt einfrig  damit  an  die
Charakterdaten  zu  lesen  und  auf  dem
Bildschirm   darzustellen.   Wohlgemerkt
obwohl  er sich schon nicht mehr am Zei-
lenanfang befindet, sondern  mitten  in-
nerhalb  dieser  Rasterzeile!  Für jeden
Taktzyklus,  den  wir  mehr   verzögern,
stellt  der  VIC  die  Charakterdaten um
jeweils ein Zeichen (also 8 Pixel)  wei-
ter  rechts  dar.  Schalten  wir also 10
Takte nach Beginn des linken  Bildrandes
die  vertikale  Verschiebung ab, so wird
die Charakterzeile exakt 10 Zeichen nach
rechts versetzt gezeichnet.  Dies  setzt
sich,  wie  oben schon erwähnt, über den
gesamten Bildschirm, also auch  für  die
folgenden  24  weiteren Charakterzeilen,
fort, womit auch der gesamte  Bildschirm
um 10 Zeichen versetzt angezeigt wird!  
2) DIE UMSETZUNG                        
Wie das Ganze dann aussieht, können  Sie
sich  in  den  Programmbeispielen "HSP1"
und "HSP2" anschauen. Sie  werden  beide
mit  ",8,1"  geladen  und  durch SYS4096
gestartet. HSP2 unterscheidet  sich  von
HSP1 nur darin, daß das Zeichenwirrwarr,
das  durch  den HSP-Effekt in der ersten
Rasterzeile  zu  sehen  ist,  mit  einem
schwarzen  Rasterbalken  unsichtbar  ge-
macht wurde.                            
Kommen wir nun also zu der Routine,  die
uns  diesen  Effekt erzeugt. Sie ist vom
Aufbau   eigentlich    recht    einfach.
Zunächst  einmal befindet sich eine Ini-
tialisierungsroutine ab  Adresse  $1000,
die wie die meisten unserer IRQ-Routinen
das ROM abschaltet, um den IRQ-Vektor am
Speicherende  verwenden  zu  können, und
anschließend   einen   Border-Raster-IRQ
initialisiert,  der uns zunächst einmal,
wie immer, den unteren und oberen  Bild-
schirmrand   abschaltet.  Sie  steht  ab
Adresse $1200 im Speicher  und  ist  ge-
folgt von einer Routine zum Auslesen des
Joysticks,  sowie der Routine "Control",
die die  Joystick-Daten  auswertet,  den
Bildschirmverschiebeoffset berechnet und
damit  die  HSP-IRQ-Routine beeinflusst.
Selbige ist ab Adresse $1100 zu  finden.
Dir Border-IRQ-Routine legt diese Adres-
se in den IRQ-Vektoren  bei  $FFFE/$FFFF
ab,  und  gibt dem VIC vor, den nächsten
Raster-IRQ in Rasterzeile  $2D  auszulö-
sen.                                    
Wird unsere HSP-Routine  nun  in  dieser
Rasterzeile  aufgerufen,  so glätten wir
zunächst den IRQ, nach der uns  mittler-
weile altbekannten Methode. Ab dem Label
"Onecycle"  steht nun unsere eigentliche
Routine, die wiefolgt aussieht:         
onecycle:                               
      lda #$19   ;Bildsch. 1 Zeile nach 
      sta $d011  ; unten scrollen       
      ldy #$08   ;Verzögerungsschleife  
wy    dey        ; um den richtigen     
      bne wy     ; Moment abzupassen    
      jsr cycles ;Verzögerung 12 Takte  
      lda #$18   ;Wert f. 1 Zeile zurück
redu1 beq redu2  ;2 oder 3 Take verz.   
redu2 bne tt     ;ans Ende verzweigen   
      nop        ;20 NOPs die für das   
      nop        ; Timing später SEHR   
      nop        ; WICHTIG sind, ob-    
      nop        ; wohl sie hier        
      nop        ; übersprungen werden!!
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
      nop                               
tt    sta $d011  ;Wert schreiben        
      lda #$0e   ;Bildschirmfarben set- 
      sta $d020  ; zen (innerhalb dieser
      lda #$06   ; Befehle wird die Cha-
      sta $d021  ; rakterz. gelesen!)   
Zu  Beginn  unserer   IRQ-Routine   wird
zunächst  also  eine vertikale Verschie-
bung um eine Rasterzeile in $D011 einge-
tragen  (Bits  0-2  enthalten  den  Wert
%001=$01). Dadurch, daß der  HSP-IRQ  in
Rasterzeile  $2D  aufgerufen  wurde, und
daß die IRQ-Glättung 2 Rasterzeilen ver-
braucht,  befinden  wir  uns nun also in
Rasterzeile $2F. Wir verzögern nun  noch
mit  der  folgenden Zählschleife und dem
JSR-Befehl um eine knappe weitere Zeile,
wobei exakt die Position abgepasst wird,
an der sich der  Rasterstrahl  genau  am
Anfang  des linken Randes des sichtbaren
Bildschirms befindet  (so  wie  bei  der
Routine  zum  Abschalten  der seitlichen
Bildschirmränder). Hierbei  gehöhrt  der
"LDA #$18"-Befehl ebenfalls zur Verzöge-
rung. Er initialisirt  den  Akku  jedoch
gleichzeitig schon mit dem Wert vor, den
wir  in  $D011  schreiben müssen, um die
vertikale Verschiebung wieder abzuschal-
ten  (die unstersten drei Bits enthalten
den Wert 0). Nun folgt wieder eine  sehr
ausgeklügelte  Verzögerung, um Taktgenau
eine ganz bestimmte Rasterposition abzu-
passen. Beachten Sie bitte, daß die Rou-
tine an dieser Stelle von der oben schon
erwähnten "Control"-Routine  modifiziert
wird,  um  die  jeweils gewünschte Bild-
schirmverschiebung  zu  erreichen.   Wir
haben  hier nun zwei Branch-Befehle, die
jeweils mit  Labels  versehen  sind, und
denen  20 NOP-Befehle folgen. Zum Schluß
steht dann der STA-Befehl, mit  dem  der
Wert  des  Akkus  in  $D011  eingetragen
wird, um nach der  gewünschten  Verzöge-
rung den VIC zum Lesen der Charakterzei-
le  zu  bewegen.  Schauen  wir  uns  nun
zunächst  die  beiden Branches und deren
Bedeutung an:                           
      lda #$18   ;Wert f. 1 Zeile zurück
redu1 beq redu2  ;2 oder 3 Take verz.   
redu2 bne tt     ;ans Ende verzweigen   
Durch  den  vorherigen  LDA-Befehl,  der
einen  Wert  ungleich  Null lädt, wissen
wir, daß das  Zero-Flag  in  jedem  Fall
gelöscht ist. Ausserdem scheint der "BEQ
REDU2"-Befehl unsinnig zu sein, zumal er
exakt zum nächsten Befehl weiterspringt.
Wie  aber  auch  schon  bei unserer IRQ-
Glättungsroutine  hat   dieser   Branch-
Befehl  die Aufgabe, exakt einen Taktzy-
klus  lang  zu  verzögern.  Ein  Branch-
Befehl benötigt mindestens zwei Takte um
ausgeführt  zu  werden. Trifft die abge-
fragte  Bedingung  nicht  zu,  so   wird
gleich beim nächsten Befehl fortgefahren
(so  wie  das  hier  auch der Fall ist).
Trifft  die  Bedingung  jedoch  zu,   so
dauert  der  Branch-Befehl einen Taktzy-
klus länger, in dem  der  Prozessor  den
Sprung-Offset   auf  den  Programmzähler
aufaddieren muß. Soll nun um eine gerade
Anzahl Zyklen verzögert werden, weil der
Bildschirm um eine gerade Anzahl Zeichen
verschoben werden soll,  so  steht  hier
ein  BEQ-Befehl,  der  nur 2 Zyklen ver-
braucht.  Soll  eine   ungerade   Anzahl
verzögert werden, so wird von der Routi-
ne "Control", im Label "REDU1" der Opco-
de  für  einen  BNE-Befehl  eingetragen,
womit die Routine einen Taktzyklus  län-
ger  dauert,  und  somit  auch  ungerade
verzögert. Der nun  folgende  BNE-Befehl
ist immer wahr und verzögert somit immer
3 Taktzyklen (da dies eine ungerade Zahl
ist,  verhält  es  sich  also eigentlich
umgekehrt  mit  der  Änderung  des  BEQ-
Befehls für gerade und ungerade Verzöge-
rung). Bei diesem Befehl wird von  "Con-
trol"  die Sprungadresse modifiziert. Je
nach dem, wieviele weitere Zyklen verzö-
gert  werden  müssen,  trägt die Routine
einen  Offset  auf  die  folgenden  NOP-
Befehle  ein.  Der Befehl verzweigt dann
nicht mehr auf das Label  "TT",  wo  der
Akkuinhalt  nach $D011 geschrieben wird,
sondern auf einen NOP-Befehl davor.  Ei-
ner  dieser Befehle verzögert dann immer
um 2 Taktzyklen. Hierzu sollten wir  ei-
nen  Blick auf die Routine "Contol" wer-
fen:                                    
control:                                
    ldx #$d0      ;Opcode für BNE in    
    stx redu1     ; REDU1 ablegen       
    lda xposhi    ;X-Verschiebungs-     
    sta xposhib   ; zähler kopieren     
    lda xposlo    ; (Low- und High-     
    sta xposlob   ;  byte)              
    and #$08      ;Bit 3 v. XLo ausmask.
    bne co1       ;<>0, dann            
    ldx #$f0      ;Opcode für BEQ in    
    stx redu1     ; REDU1 ablegen       
co1 lsr xposhib   ;X-Verschiebung       
    ror xposlob   ; (16 Bit) durch 4X   
    lsr xposhib   ; Rotieren nach rechts
    ror xposlob   ; mit 16 dividieren   
    lsr xposhib                         
    ror xposlob                         
    lsr xposhib                         
    ror xposlob                         
    sec           ;Subtraktion vorber.  
    lda #$14      ;20 NOPS              
    sbc xposlob   ; minus XPos/16       
    sta redu2+1   ;als Sprungoffset für 
                  ; BNE bei REDU2       
    lda xposlo    ;Alte X-Versch. laden 
    and #$07      ;unterste 3 Bits isol.
    ora #%00011000;Standard-Bits setzen 
    sta softmove+1;in hor.Scroll eintr. 
    rts                                 
Zu  Allererst trägt die Control-Routine,
die innerhalb des Border-IRQs aufgerufen
wird, in das Label "REDU1" den Wert  $D0
ein,  der  dem Opcode für den BNE-Befehl
entspricht. Hieran  anschließend  werden
die  Inhalte der Labels "XPOSLO" und "X-
POSHI" in die Labels "XPOSLOB"  und  "X-
POSHIB"  kopiert,  was  für  die Offset-
Berechnung später notwendig  ist.  Diese
Labels sind im Source-Code des Programms
auf  die Zeropage-Adressen $02, $03, $04
und $05 vordefiniert. "XPOSLO"  und  "X-
POSHI" enthalten einen 16-Bit Zähler für
die  horziontale Bildschirmverschiebung,
die von der Joystickabfrage,  die  eben-
falls während des Border-IRQs aufgerufen
wird,  den  Joystickbewegungen  entspre-
chend hoch  oder  runter  gezählt  wird.
Dieser  Zähler kann also einen Wert zwi-
schen 0 und 320 enthalten.  Da  mit  der
HSP-Routine   der   Bildschirm   nur  in
Schritten von einzelnen Zeichen (also  8
Pixeln) versetzt werden kann, muß unsere
Routine  zum  weichen  Scollen des Bild-
schirms auch noch den horizontalen  Ver-
schiebeoffset des Bildschirms verändern.
Diese   Verschiebung  wird  in  Register
$D016 des  VICs  festgelegt,  wobei  die
untersten  3 Bits unseres XPOS-Wertes in
die untersten 3  Bits  dieses  Registers
gelangen  müssen. Die Bits 3-9 des XPOS-
Wertes  enthalten  nun   (dreimal   nach
rechts  verschoben)  die Anzahl Zeichen,
und somit auch Taktzyklen, die die  HSP-
Routine verzögern muß, damit der VIC die
Charakterzeile  erst  an der gewünschten
Position liest. Ist also das 3. Bit (das
das 0. Bit der Anzahl ist)  gesetzt,  so
muß  eine ungerade Anzahl Zeichen verzö-
gert werden. In  dem  Fall  enthält  das
Label  "REDU1" schon den richtigen Wert,
nämlich den Opcode für  den  BNE-Befehl,
der zusammen mit dem BNE-Befehl bei "RE-
DU2" sechs  (also  eine  gerade  Anzahl)
Taktzyklen   verbraucht.   Ist   Bit   3
gelöscht, so enthält der Akku  nach  dem
"AND #$08"-Befehl den Wert 0 und es wird
vor  dem Weitergehen im Programm der Op-
code für den BEQ-Befehl in "REDU1"  ein-
getragen.  Damit wird in der HSP-Routine
um 2+3=5  (also  eine  ungerade  Anzahl)
Taktzyklen  verzögert.  Nun muß noch er-
mittelt  werden,  wieviele   zusätzliche
NOPs  zur Verzögerung notwendig sind. Da
ein  NOP-Befehl   immer   2   Taktzyklen
braucht,  wird nur die halbe Anzahl NOPs
benötigt, um enstsprechend viele Zeichen
(Taktzyklen) lang zu verzögern. Da zudem
noch die 3 Bit Verschiebeoffset in  XPOS
stehen,  muß  dieser Wert durch 16 divi-
diert werden, um den gewünschten Wert zu
erhalten. Diese Berechnung wird  an  der
Kopie  von  XPOS, also in den Labels "X-
POSLOB"  und   "XPOSHIB"   durchgeführt.
Nachdem   im  Low-Byte  dieser  Register
hiernach die Anzahl der benötigten  NOPs
stehen,  kann  nun die Sprungadresse für
den  BNE-Befehl  bei  "REDU2"  berechnet
werden.  Da Branch-Befehle immer nur ein
Byte mit dem relativen  Offset  zum  ak-
tuellen Programmzähler enthalten, müssen
wir  also  lediglich  angeben,  wieviele
NOPs übersprungen  werden  müssen.  Dies
wird  durch  die Gesamtanzahl NOPs minus
der benötigten  Anzahl  NOPs  errechnet,
und  in  Adresse  "REDU2"+1 eingetragen.
Die Verzögerung sollte nun  also  sauber
funktionieren.                          
Zu guter Letzt wird noch der horizontale
Verschiebeoffset   für   das  horzontale
Softscrolling  ermittelt,   indem    aus
"XPOSLO" die untersten drei Bits ausmas-
kiert werden. Da diese Bits im  Register
$D016  landen  müssen,  das auch für die
38/40-Zeichendarstellung und den  Multi-
colormodus zuständig ist, setzen wir die
entsprechenden  Bits  mit  dem folgenden
OR-Befehl. Der resultierende  Wert  wird
in  das  Label "SOFTMOVE"+1 eingetragen,
das in der HSP-Routine kurz vor dem oben
gezeigten Codestück steht:              
softmove lda #$00                       
         sta $d016                      
Hier wird also lediglich  der  Verschie-
beoffset   in  den  Operanden  des  LDA-
Befehls eingetragen,  der  dann  in  der
HSP-Routine  die  Bildschirmverschiebung
jeweils wie benötigt in $D016 einträgt. 
Damit  hätten  wir alle Einzelheiten der
HSP-Routine besprochen.  Wie  Sie  sehen
funktioniert  sie  sogar  noch einfacher
als die VSP-Routine. Vielleicht  experi-
mentieren  Sie  einmal ein wenig mit den
Programmbeispielen und  versuchen  einen
horizontalen  Endlosscroller  daraus  zu
machen.  Der   HSP-Effekt   funktioniert
übrigens  genauso  wie  VSP auch mit HI-
RES-Grafik. Im nächsten Kursteil  werden
wir  auch  das  noch  sehen, und die er-
staunlichste IRQ-Raster-Routine  kennen-
lernen  die je entdeckt wurde: die AGSP-
Routine nämlich,  die  eine  Kombination
aus  HSP  und VSP darstellt, und mit der
es problemlos möglich ist den kompletten
Bildschirm in ALLE Richtungen zu  scrol-
len,  ohne  große Kopieraktionen mit dem
Prozessor durchführen zu müssen!!!      
                                 (ih/ub)



Valid HTML 4.0 Transitional Valid CSS!