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)