IRQ-KURS
"Die Hardware ausgetrickst..."
(Teil 12)
----------------------------------------
Herzlich Willkommen zu einer neuen Folge
unseres IRQ-Kurses. In dieser Ausgabe
werden wir uns weiter mit der ESCOS-
Routine des letzten Kursteils beschäfti-
gen. Wir werden hierbei die Routine mit
einem Movie-Scroller verbinden, um so
einen bildschirmübergreifenden Text
scrollen zu lassen. Dies gestaltet sich
ohne einen speziellen Trick gar nicht
mal so einfach...
1) EINLEITUNG
Wie Sie sich vielleicht noch erinnern,
so hatten wir in der letzten Folge des
IRQ-Kurses zuletzt das Beispielprogramm
"ESCOS2" besprochen. Diese Raster-IRQ-
Routine öffnete uns den linken und rech-
ten, sowie den oberen und unteren Bild-
schirmrand und stellte dann alle 21 Ra-
sterzeilen eine neue Reihe mit je acht
Sprites auf dem Bildschirm dar. Dadurch
hatten wir insgesamt vierzehn Zeilen zu
je acht Sprites auf dem Bildschirm, die
alle nahtlos aneinandergereiht fast den
gesamten Bildschirm überdeckten. Der
einzige ungenutzte Bereich war der von
Rasterzeile 294 bis 312, der zu klein
war um eine weitere Spritereihe darin
unterzubringen, aber sowieso schon un-
terhalb der für normale Monitore dar-
stellbaren Grenze liegt.
Der einzige Unterschied der Routine "ES-
COS2" zu "ESCOS1" bestand nun darin, daß
erstere Routine lediglich ein Zeilenoff-
set-Register für den ersten auszulösen-
den Raster-IRQ herunterzählte, um so
einen Scroll-Effekt der Spritereihen zu
erzielen. "ESCOS2" ist also schon eine
Art "Moviescroller". Der Grund, warum
sie es nicht wirklich ist, liegt darin,
daß in jeder Spritezeile dieselben Spri-
tes auf dem Bildschirm zu sehen waren.
Wie wir aber von den Moviescroll-
Routinen wissen, müssen wir für einen
Scrolltext das Aussehen einer Spritezei-
le ja individuell bestimmen können, da-
mit auch wirklich ein Text, und nicht
immer dieslbe Zeile, über den Bildschirm
läuft.
2) DAS PROBLEM - DIE LÜSUNG
"Kein Problem" werden Sie nun sagen,
"einfach die Textausgaberoutine der Mo-
viescroller-Routinen vom IRQ-Kurs ein-
bauen, und schon haben wir einen Scroll-
text". Diese Feststellung stimmt schon,
wie sollte es auch anders gehen, jedoch
stellt sich uns dabei noch ein kleines
Problem in den Weg: dadurch nämlich, daß
wir in den ESCOS-Routinen, keine Zwi-
schenräume mehr zwischen den einzelnen
Spritezeilen haben, gestaltet es sich
als schwierig, die Sprite-Pointer zeit-
genau zu setzen. Setzen wir diese näm-
lich auf die neu einzuscrollende Sprite-
zeile, noch bevor die letzte Spritezeile
abgearbeitet wurde, so erscheinen die
alten Sprites schon im Aussehen der
Neuen. Umgekehrt können die Spritepoin-
ter auch nicht nach Abarbeiten der letz-
ten Spritezeile gesetzt werden da hier
ja schon die neuen Sprites erscheinen
müssen. Man könnte nun versuchen, ein
mega-genaues Timing zu programmieren,
das innerhalb der ersten Rasterzeile
einer neuen Spritezeile exakt vor Dar-
stellen eines neuen Sprites dessen Poin-
ter neu setzt. Dies gestaltet sich je-
doch umso umständlicher, wenn wir beach-
ten müssen, daß gleichzeitig auch noch
der linke und rechte Rand geöffnet wer-
den soll. Da dieser ebenfalls ein exak-
tes Timing verlangt, würden wir mit dem
Doppeltiming in des Teufels Küche kom-
men. Aber keine Sorge: glücklicherweise
können wir als IRQ-Magier wieder in die
Raster-Trickkiste greifen, und eine
weitaus einfachere Lösung des Problems
anwenden.
Wie Sie z.B. schon von unseren FLI-
Routinen wissen, hat man mit dem VIC die
Möglichkeit, das Video-RAM innerhalb
seines Adressbereiches von 16KB zu ver-
schieben. Der Speicherbereich, den der
Grafikchip dazu verwendet, um den Inhalt
des Textbildschirms aufzubauen muß also
nicht zwingenderweise bei $0400 liegen,
wo er sonst nach dem Einschalten des
Rechners untergebracht ist. Durch die
Bits 4-7 des Registers $D018 können ins-
gesamt 16 verschiedene Speicherbereiche
gewählt werden, deren Basisadressen in
$0400-Schritten von $0000-$3C00 gehen.
Nun werden Sie fragen, was denn das Vi-
deo-RAM mit unserer ESCOS-Routine zu tun
hat, zumal wir die Bildschirmdarstellung
doch sowieso abgeschaltet haben, und
keinen Text auf dem Bildschirm haben?
Nun, ganz einfach: wo befinden sich denn
die Register der Spritepointer normaler-
weise? Natürlich in den Adressen von
$07F8-$07FF. Und genau diese Adresse
liegen am Ende des Video-RAMs. Ver-
schiebt man nun das Video-RAM an eine
andere Adresse, so verschiebt man auto-
matisch auch die Registeradressen der
Spritepointer! Wird das Video-RAM also
beispielsweise um $0400 Bytes nach $0800
verschoben, so bewegen sich die Sprite-
pointer-Register ebenfalls um $0400-
Bytes nach vorne. Um nun also das Ausse-
hen der acht Sprites zu definieren, müs-
sen die Adressen $0BF8-$0BFF beschrieben
werden. Und genau das ist die Lösung
unseres Problems. Da es während des
Spriteaufbaus zu lange dauert, alle acht
Spritepointer in den Akku zu laden und
in die Register zu schreiben, soll das
die Initialisierungsroutine des Movies-
crollers übernehmen. Hierbei schreibt
letztere die benötigten Werte für eine
Spritezeile in die Pointerregister eines
verschobenen Video-RAMs. Während der
Darstellung brauchen wir nun nur noch
durch Schreiben eines einzigen Bytes,
nämlich des ensprechenden Wertes für ein
neues Video-RAM in $D018, auf selbiges
umzuschalten. Dadurch, daß der VIC für
die neue Spritezeile nun in einem ganz
anderen Video-RAM arbeitet, holt er sich
auch die Spritepointer aus den neuen
Adressen, womit wir alle acht Sprite-
pointer mit nur einem Schreibzugriff
umgeschaltet hätten!
Die Umsetzung dieser Lösung in die Pra-
xis gestaltet sich für uns sehr einfach.
Sinnigerweise haben wir nämlich in den
Routinen "ESCOS1" und "ESCOS2" schon
Platz für diese Änderung gelassen. Wie
Sie sich vielleicht erinnern, hatten wir
zur Darstellung der Sprites innerhalb
der IRQ-Routine dieser beiden Beispiel-
programme die Unterroutine "OPEN21"
vierzehnmal aufgerufen. Sie wird immer
in der ersten Rasterzeile einer neuen
Spritezeile angesprungen, und übernimmt
das Neusetzen der Y-Koordinaten aller
Sprites, sowie das Üffnen des Sidebor-
ders in den folgenden 21 Rasterzeilen.
So sah der Aufruf in den beiden Bei-
spielprogrammen aus:
nop ;Diese Befehlsfolge wird
jsr open21; insgesamt 14x aufgerufen
... ; um je 21 Zeilen zu öffnen
nop ;Sprite Line 14
jsr open21
Die "NOP"-Befehle dienten dabei nur der
Verzögerung um zwei Taktzyklen, damit
die Änderung zum richtigen Zeitpunkt
eintritt. Wir können diese Befehle mit
jedem anderen Befehl ersetzen, der nur 2
Takte in Anspruch nimmt. Diese Tatsache
machen wir uns für den Moviescroller
zunutze. Wir ersetzen die NOPs mit LDA-
Befehlen, wobei der Wert, der in den
Akku geladen wird, dem Wert entspricht,
der in Register $D018 geschrieben werden
muß, um auf das neue Video-RAM umzu-
schalten. Er dient quasi als Parameter
für die "OPEN21"-Routine. Demnach sieht
der Aufruf dieser Routine, aus dem Ra-
ster-IRQ heraus, nun folgendermaßen aus:
v00:lda #$00*$10 ;Code für Scr0 ($0000)
jsr open21 ;21 Rasterzeilen öffnen
v01:lda #$01*$10 ;Code für Scr0 ($0400)
jsr open21 ;21 Rasterzeilen öffnen
v02:lda #$02*$10 ;Code für Scr0 ($0800)
jsr open21 ;21 Rasterzeilen öffnen
...
v0d:lda #$0d*$10 ;Code für Scr13 ($3400)
jsr open21 ;21 Rasterzeilen öffnen
Wie schon in den ESCOS-Beispielen, so
wiederholt sich auch hier die LDA-JSR-
Befehlsfolge 14 Mal, wobei jeweils der
nächste Video-RAM-Bereich als Parameter
im Akku übergeben wird. Timingmässig hat
sich nichts geändert, da der NOP-Befehl
genausolange braucht wie der LDA-Befehl.
Eine ähnliche Modifikation haben wir nun
für das Schreiben dieses Akku-Wertes in
Register $D018 vorgenommen. Diese Aufga-
be soll von der Routine "OPEN21" durch-
geführt werden. Hier ein Auszug der er-
sten Zeilen dieser Routine aus dem Bei-
spiel "ESCOS2":
open21:
nop ;Verzögern bis rechter
nop ; Rand erreicht
dec $d016 ;38 Spalten (Rand
inc $d016 ;40 Spalten öffnen)
lda $1500,y ;$D011-Wert aus Tabelle
sta $d011 ; lesen und eintragen
iny ;Tabellen-Index+1
jsr cycles+5;24 Zyklen verzögern
...
Wie Sie sehen, stehen hier ebenfalls
zwei NOP-Befehle am Anfang der Routine.
Sie benötigen 4 Taktzyklen, was für ei-
nen "STA $XXXX"-Befehl ebenfalls zu-
trifft. Die zwei NOPs wurden für den
Moviescroller nun mit einem "STA $D018"
ersetzt:
open21:
sta $d018 ;VRAM f.SprPtrs. versch.
dec $d016 ;38 Spalten (Rand
inc $d016 ;40 Spalten öffnen)
lda $1500,y ;$D011-Wert aus Tabelle
sta $d011 ; lesen und eintragen
iny ;Tabellen-Index+1
jsr cycles+5;24 Zyklen verzögern
...
Damit hätten wir also die ESCOS-Routine
so umprogrammiert, daß Sie uns in jeder
der 14 Spritezeilen auch neue Sprite-
pointer setzt. Es müssen nun noch zwei
weitere Änderungen gemacht werden, damit
der Movie-scroller auch voll funk-
tionstüchtig ist.
Zunächst einmal muß die Initialierungs-
routine erweitert werden. Sie soll uns
die Spritepointer der benutzten Video-
RAM-Adressen auf bestimmte Sprites vor-
initialisieren, so daß später zur Dar-
stellung einer bestimmten Spritereihe
nur noch die Nummer des zu benutzenden
Video-RAMs in den Labeln "V00" bis "V0D"
der Raster-IRQ-Routine (siehe oben) ein-
getragen werden muß, und die Routine
somit automatisch den richtigen Bild-
schirm zur korrekten Darstellung der
entsprechenden Spritezeile wählt.
Zunächst einmal wollen wir vereinbaren,
daß wir den 16K-Adressbereich des VICs
von $0000-$3FFF um eins nach oben in den
Bereich von $4000-$7FFF verschieben.
Dadurch stört uns die Zeropage, die nor-
malerweise ja auch im Bereich des VICs
liegt, nicht mehr, und wir haben volle
16KB zur Speicherung von Sprites und
Spritepointer-Video-RAM zur Verfügung.
Die Verschiebung wird durch Schreiben
des Wertes 2 in das Portregister A von
CIA-B erreicht. Innerhalb der Initial-
sierung wurde also folgende Befehlsse-
quenz hinzugefügt:
LDA #$02
STA $DD00
Damit befindet sich der Datenbereich für
den VIC nun im Bereich von $4000-$7FFF.
Beachten Sie bitte auch, daß nun der
Bytewert, den der VIC in "ausgetrick-
sten" Rasterzeilen darstellt, nicht mehr
in $3FFF, sondern in $7FFF abgelegt wer-
den muß (im Beispielprogramm enthält er
den Wert $81, womit vertikale Lininen
hinter dem Scrolltext erscheinen). Nun
folgt der Teil, der die Spritepointer
setzt. Hier treffen wir die Konvention,
daß die Sprites, die durch die Pointer
einer Video-RAM-Bereichs dargestellt
werden auch innerhalb dieses Video-RAMs
unterbracht werden sollen. Liegt dieses
also Beispielsweise bei $4400, so soll
Spritepointer 0 auf das Sprite bei $4400
(Blocknr. 16), Spritepointer 1 auf das
Sprite bei $4440 (Blocknr. 17), usw.,
zeigen. Dies bewerkstelligt nun der fol-
gende Teil der Init-Routine:
lda #$f8 ;ZP-Zgr. $02/03 mit
sta $02 ; $43F8 init.
lda #$43
sta $03
lda #($0000/64);Ptr. f. Sprite-Line01
jsr setpoint ; setzen
lda #($0400/64);Ptr. f. Sprite-Line02
jsr setpoint ; setzen
lda #($0800/64);Ptr. f. Sprite-Line03
jsr setpoint ; setzen
...
lda #($3000/64);Ptr. f. Sprite Line13
jsr setpoint ; setzen
lda #($3400/64);Ptr. f. Sprite Line14
jsr setpoint ; setzen
Wie Sie sehen wird lediglich ein Adres-
sierungszeiger in der Zeropage initiali-
siert, und dann 14 Mal die Unterroutine
"SETPOINT" aufgerufen, wobei im Akku der
Inhalt für den jeweils ersten Sprite-
pointer übergeben wird. Hier nun die
Routine "SETPOINT", die die eigentlichen
Werte in die Pointerregister schreibt:
SETPOINT:
ldy #$00 ;Index-Reg. init.
sta ($02),y;SprPtr0 ablegen
clc ;Akku=Akku+1
adc #$01
iny ;Index=Index+1
sta ($02),y;SprPtr1 ablegen
clc ;Akku=Akku+1
adc #$01
iny ;Index=Index+1
sta ($02),y;SprPtr2 ablegen
...
clc ;Akku=Akku+1
adc #$01
iny ;Index=Index+1
sta ($02),y;SprPtr7 ablegen
clc ;Auf Hi-Byte des $02/$03
lda $03 ; Zeigers den Wert 4 add.
adc #$04 ; um auf nächstes VRAM zu
sta $03 ; positonieren
rts
Wie Sie sehen, so wird vom Basiswert des
ersten Spritepointers an, acht Mal je-
weils um eins hochgezählt und das Ergeb-
nis über den Vektor bei $02/$03 in die
entsprechende Sprite-Pointer-Adresse
geschrieben. Beim ersten Durchlauf zeigt
dieser Vektor auf Adresse $43F8, wo sich
die Spritepointer des ersten Video-RAM-
Bereichs befinden. Am Ende der Pointer-
initialisierung wird die Vektoradresse
nun um $0400 erhöht (auf Hi-Byte wird
$04 addiert), damit beim nächsten Durch-
lauf die Zeiger des nächsten Video-RAM-
Bereichs gesetzt werden.
(Anm.d.Red.: Bitte wählen Sie jetzt den
zweiten Teil des IRQ-Kurses aus dem
Textmenu)