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äftigen. 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 rechten, sowie den oberen und unteren Bild- schirmrand und stellte dann alle 21 Rasterzeilen 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 unterhalb der für normale Monitore darstellbaren Grenze liegt.
Der einzige Unterschied der Routine " ES-COS2" zu " ESCOS1" bestand nun darin, daß
erstere Routine lediglich ein Zeilenoffset- Register für den ersten auszulösenden 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 Sprites auf dem Bildschirm zu sehen waren.
Wie wir aber von den Moviescroll-Routinen wissen, müssen wir für einen
Scrolltext das Aussehen einer Spritezeile ja individuell bestimmen können, damit 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 Moviescroller- Routinen vom IRQ-Kurs einbauen, und schon haben wir einen Scrolltext" . 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 Zwischenräume mehr zwischen den einzelnen
Spritezeilen haben, gestaltet es sich
als schwierig, die Sprite-Pointer zeitgenau zu setzen. Setzen wir diese nämlich 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 Spritepointer auch nicht nach Abarbeiten der letzten Spritezeile gesetzt werden da hier
ja schon die neuen Sprites erscheinen
müssen. Man könnte nun versuchen, ein
megagenaues Timing zu programmieren, das innerhalb der ersten Rasterzeile
einer neuen Spritezeile exakt vor Darstellen eines neuen Sprites dessen Pointer neu setzt. Dies gestaltet sich jedoch umso umständlicher, wenn wir beachten müssen, daß gleichzeitig auch noch
der linke und rechte Rand geöffnet werden soll. Da dieser ebenfalls ein exaktes Timing verlangt, würden wir mit dem
Doppeltiming in des Teufels Küche kommen. 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 16 KB zu verschieben. 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 insgesamt 16 verschiedene Speicherbereiche
gewählt werden, deren Basisadressen in
$0400- Schritten von $0000-$3 C00 gehen.
Nun werden Sie fragen, was denn das Video- 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 normalerweise? Natürlich in den Adressen von
$07 F8-$07 FF. Und genau diese Adresse liegen am Ende des Video-RAMs. Verschiebt man nun das Video-RAM an eine
andere Adresse, so verschiebt man automatisch auch die Registeradressen der
Spritepointer! Wird das Video-RAM also
beispielsweise um $0400 Bytes nach $0800 verschoben, so bewegen sich die Spritepointer- Register ebenfalls um $0400- Bytes nach vorne. Um nun also das Aussehen der acht Sprites zu definieren, müssen die Adressen $0 BF8-$0 BFF 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 Moviescrollers ü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 Spritepointer mit nur einem Schreibzugriff
umgeschaltet hätten!
Die Umsetzung dieser Lösung in die Praxis 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 Beispielprogramme 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 Sideborders in den folgenden 21 Rasterzeilen.
So sah der Aufruf in den beiden Bei- spielprogrammen aus:
nop ; Diese Befehlsfolge wird jsr open21 ; insgesamt 14 x 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 umzuschalten. Er dient quasi als Parameter
für die " OPEN21"- Routine. Demnach sieht
der Aufruf dieser Routine, aus dem Raster- 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 Aufgabe soll von der Routine " OPEN21" durchgeführt werden. Hier ein Auszug der er- sten Zeilen dieser Routine aus dem Beispiel " 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 einen " STA $ XXXX"- Befehl ebenfalls zutrifft. 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 Spritepointer setzt. Es müssen nun noch zwei
weitere Änderungen gemacht werden, damit
der Moviescroller auch voll funktionstüchtig ist.
Zunächst einmal muß die Initialierungsroutine erweitert werden. Sie soll uns
die Spritepointer der benutzten Video-RAM- Adressen auf bestimmte Sprites vorinitialisieren, so daß später zur Darstellung einer bestimmten Spritereihe
nur noch die Nummer des zu benutzenden
Video-RAMs in den Labeln " V00" bis " V0 D" der Raster-IRQ- Routine ( siehe oben) ein- getragen werden muß, und die Routine
somit automatisch den richtigen Bildschirm zur korrekten Darstellung der
entsprechenden Spritezeile wählt.
Zunächst einmal wollen wir vereinbaren, daß wir den 16 K-Adressbereich des VICs
von $0000-$3 FFF um eins nach oben in den
Bereich von $4000-$7 FFF verschieben.
Dadurch stört uns die Zeropage, die normalerweise ja auch im Bereich des VICs
liegt, nicht mehr, und wir haben volle
16 KB 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 Initialsierung wurde also folgende Befehlssequenz hinzugefügt:
LDA #$02 STA $DD00
Damit befindet sich der Datenbereich für
den VIC nun im Bereich von $4000-$7 FFF.
Beachten Sie bitte auch, daß nun der
Bytewert, den der VIC in " ausgetricksten" Rasterzeilen darstellt, nicht mehr
in $3 FFF, sondern in $7 FFF abgelegt werden 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 folgende 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 Adressierungszeiger in der Zeropage initialisiert, und dann 14 Mal die Unterroutine
" SETPOINT" aufgerufen, wobei im Akku der
Inhalt für den jeweils ersten Spritepointer ü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 jeweils um eins hochgezählt und das Ergebnis über den Vektor bei $02/$03 in die entsprechende Sprite-Pointer- Adresse
geschrieben. Beim ersten Durchlauf zeigt
dieser Vektor auf Adresse $43 F8, wo sich
die Spritepointer des ersten Video-RAM- Bereichs befinden. Am Ende der Pointerinitialisierung wird die Vektoradresse
nun um $0400 erhöht ( auf Hi-Byte wird
$04 addiert), damit beim nächsten Durchlauf 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)