IRQ-KURS "Die Hardware ausgetrickst..." (Teil 11)
Herzlich Willkommen zum elften Teil unseres IRQ-Kurses. Wie schon in den letzten Kursteilen, werden wir uns auch diesen Monat mit der Spriteprogrammierung
der besonderen Art beschäftigen. Es soll
um einige Tricks gehen, mit denen man
den Bildschirm auch über alle Ränder
hinaus mit Gafikdaten füllen kann. Diesen Effekt nennt man " ESCOS", der Drehund Angelpunkt für die Rastertricks in
diesem Kursteil sein wird.
1) UNSER ZIEL In früheren Kursteilen hatten wir ja
schon einmal besprochen, auf welche Art
und Weise oberer und unterer, sowie linker und rechter Bildschirmrand abgeschaltet werden. Wir hatten weiterhin gelernt, daß in diesen Bereichen ausschließlich Sprites auftauchen können, die durch die abgeschalteten Ränder
sichtbar sind, wo sie sonst von letzteren überdeckt werden. Wir hatten ebenso
eine Möglichkeit kennengelernt, beide
Ränder, die horizontalen und vertikalen, gleichzeitig abzuschalten, wobei wir auf
sehr exaktes Timing achten mussten, da
das Abschalten der linken und rechten
Bildschirmbegrenzung eine hohe Genauigkeit erforderte. Desweiteren wird Ihnen
aus dem letzten Kursteilen bestimmt noch
die Sprite-Multiplexer- Routine in Kombination mit einem Moviescroller im Kopf
sein, mit der wir 104 Sprites gleichzeitig auf den Bildschirm brachten. Wie Sie
sich vielleicht erinnern, waren wir dabei an gewisse Grenzen gebunden. So war
z. B. zwischen zwei Spritezeilen immer
ein Abstand von ca.2 Rasterzeilen erforderlich, die wir benötigten, um die
Spritepointer sowie die neuen Y-Positionen der Sprites zu setzen. Des- weiteren mussten wir ein komplizierte
Timingroutine benutzen, die zwischen
Charakterzeilen ( jede achte Rasterzeile, in der der VIC den Prozessor für eine
Dauer von 42 Taktzyklen anhält) und normalen Rasterzeilen zu unterscheiden hatte. In dieser Folge unseres Kurses wollen wir nun all diese Komponenten miteinander verbinden und eine Möglichkeit
kennenlernen, Timingprobleme durch Charakterzeilenberücksichtigung, zu umgehen. Das Endergebnis wird ein flächendeckend ( !) mit Sprites belegter Bildschirm sein, wobei weder Leerräume zwischen den Sprites, noch im gesamten
Bildschirmrahmen zu sehen sein werden!
Wir werden also über eine Grafik verfügen, die, ähnlich einem Fernsehbild, die
gesamte Bildröhrenfläche ausfüllt!
2) ERSTES PROBLEM: DAS TIMING Kommen wir gleich zum Kern dieses Kursteils, dem Timing-Problem, das sich uns entgegenstellt. Möchten wir nämlich alle
Bildschirmränder abschalten und gleichzeitig auch noch die Sprites multiplexen, so können wir programmtechnisch in
" Teufels Küche" gelangen. Wir müssten
berücksichtigen, daß im sichtbaren Bildschirmfenster alle acht Rasterzeilen
eine Chakaterzeile auftritt, gleichzeitig müsste in jeder Rasterzeile der linke und rechte Bildschirmrand abgeschaltet, sowie in jeder 21 . Rasterzeile die
Sprites neu positioniert werden. Dabei
stellen vor allem die Charakterzeilen
ein großes Problem dar. Wir müssten unterscheiden zwischen Rasterstrahlpositionen im oberen und unteren Bildschirmrand und innerhalb des sichtbaren Bildschirmfensters, und zudem noch für letzteren Fall berücksichtigen, wann sich
der VIC gerade in einer Chakaterzeile
befindet und wann in einer normalen Rasterzeile. Dieses Problem stellte sich
bei unseren Raster-Effekten nun schon
häufiger in den Weg, wobei wir es meist durch einen einfachen Trick umgingen: in
der Regel benutzten wir in solchen Fällen eine FLD-Routine, die die Charakterzeile im fraglichen Bildschirmbereich
einfach nach unten " wegdrückte", so daß
wir in jeder Rasterzeile 63 Taktzyklen
zur Verfügung hatten und somit ein einheitliches Timing programmieren konnten.
Wir könnten diesen Effekt hier nun auch
anwenden, jedoch gibt es speziell für
diese Anwendung einen weiteren, viel
einfacherern Trick, die Charakterzeilen
zu umgehen: da wir ja den gesamten Bildschirm mit Sprites füllen möchten, können wir davon ausgehen, daß wir keinerlei Hintergrundgrafik, bzw. Textzeichen
benötigen. Es gibt nun einen Trick, den
wir noch nicht kennengelernt haben, mit
dem wir die Charakterzeilen ganz abschalten können, so daß nur noch die
Sprites dargestellt werden. Wie fast
immer ist Register $ D011, ein Drehund
Angelpunkt der VIC-Trickeffekt- Kiste, für diesen Trick verantwortlich. Mit Bit4 dieses Registers können wir nämlich
den gesamten Bildschirm abschalten, was
einer Deaktivierung des VICs gleichkommt. Er wird durch das Löschen dieses
Bits veranlasst, auf dem gesamten Bildschirm nur noch die Rahmenfarbe darzustellen, und keine Charakterzeilen mehr
zu lesen. Die Sprites bleiben jedoch
weiterhin aktiv, obwohl sie jetzt unsichbar sind, da sie jetzt auf dem gesamten Bildschirm mit dem Rahmen überdeckt werden. Man könnte das Setzen und
Löschen des 4 . Bits von Register $ D011 quasi mit dem Üffnen und Schließen eines
Vorhangs vor einem Fenster vergleichen:
Eine Fliege ( oder unser Sprite), die
sich auf der Fensterscheibe befindet, ist bei geschlossenem Vorhang nicht
sichtbar. Ist letzterer jedoch geöffnet, so sieht man die Fliege, solange sie
sich im sichtbaren Bereich des Fenster
bewegt, und nicht unter den seitlich
aufgerafften Vorhängen verschwindet.
Nun, selbst wenn die Sprites noch aktiv sind, so nutzen Sie uns herzlich wenig
wenn sie unsichtbar sind. Deshalb gilt
es mal wieder, den VIC auszutricksen, um
das gewünschte Ergebnis zu erhalten.
Dies gestaltet sich in diesem Fall recht
einfach: Zunächst einmal schalten wir an
einer Rasterposition, an der der VIC
normalerweise den oberen oder unteren
Bildschirmrand zeichnet, den gesamten
Bildschirm durch Löschen von Bit 4 aus
Register $ D011, ab. Erreicht der Rasterstrahl nun Rasterzeile $30, an der eigentlich das sichtbare Bildschirmfenster
beginnt, so prüft der VIC, ob der Bildschirm nun einoder ausgeschaltet ist.
In letzterem Fall deaktiviert er seine
Zeichenaufbau-Schaltkreise bis zum nächsten Erreichen dieser Rasterposition, womit er keine einzige Charakterzeile
mehr liest. Anstelle dessen zeigt er in
den folgenden Rasterzeilen nur noch die
Farbe des Bildschirmrahmens an. Wenn wir
diesen jedoch mit Hilfe einer Border-Routine bei $ FA abschalten, so - oh Wun- der - zeigt uns der VIC den Bildschirmhintergrund, auf dem sich auch die Sprites herumtollen dürfen! Wie bei jedem
Effekt, bei dem der VIC etwas tut, was
er sonst nicht tun kann, erscheint hier
dann wieder der Inhalt der letzten
Adresse des VIC-Speichers ( normalerweise
$3 FFF) in Schwarz auf Hintergrundfarbe.
Durch Schreiben des Wertes 0 in diese
Speicherzelle können wir natürlich die
Schwarzen Streifen auch abschalten und
damit nur die Hintergrundfarbe anzeigen
lassen.
Um diese Vorgehensweise nun besser zu
erläutern haben wir natürlich wieder ein
Programmbeispiel auf Lager, das ich Ihnen nun auflisten möchte. Sie finden es
auf dieser MD auch als fertig ausführbares File mit dem Namen " SPRITES-ONLY", daß Sie wie immer mit ",8,1" laden und
durch ein " SYS4096" starten müssen.
Kommen wir also zur Initialiserungsroutine des Beispiels, die bei Adresse$1000 beginnt:
INIT: sei ;IRQs sperren lda #$7f ;Alle CIA-IRQs abschalten sta $dc0d ; (CIA1) sta $dd0d ; (CIA2) bit $dc0d ;CIA1-ICR löschen bit $dd0d ;CIA2-ICR löschen
lda #$01 ; VIC-Hintergrundstriche sta $3 fff ; auf 1 setzen jsr sprinit; Sprites initialiseren jsr irqinit; IRQ initialiseren
lda #$35 ;ROMs abschalte sta $01 cli ;IRQs erlauben spc:lda #$7f ;Auf SPACE-Taste sta $dc00 ; warten... lda $dc01 cmp #$ef bne spc sei ;IRQs sperren lda #$37 ;ROM wieder einschalten sta $01 jmp $fce2 ;und RESET auslösen
Alles in allem für uns keine besondere
Initialisierung. Wichtig sind noch die
Routinen " SPRINIT" und " IRQINIT" . In
ersterer initialisieren wir lediglich
die Sprite-Positionen, sowie die Sprite- Pointer und schalten alle acht Sprites ein. Letzere Routine ist für das
Korrekte initialisieren unseres IRQs
zurständig und sieht folgendermaßen aus:
IRQINIT:
lda #< bordirq ; IRQ-Vektor bei sta $ fffe ;$ FFFE/$ FFFF lda #> bordirq ; auf " BORDIRQ" verbiegen
sta $ ffff lda #$1 b ; Wert für $ D011 mit gel.
sta $ d011 ; High-Bit f. Rasterpos.
lda #$ fa ; Ersten Raster-IRQ bei
sta $d012 ; Zeile $FA auslösen lda #$81 ;VIC-Raster-IRQs sta $d01a ; erlauben dec $d019 ;VIC-ICR ggf. löschen rts
Wie Sie sehen, aktivieren wir hier einen
Raster-IRQ für Rasterzeile $ FA, der bei
Auftreten die Routine " BORDIRQ" anspringt, wo sich eine ganz gewöhnliche
Routine zum Abschalten des oberen und
unteren Bildschirmrandes befindet. Hier
das Listing dieser Routine:
BORDIRQ:
pha ;Prozessorregs. retten txa pha tya pha lda $d011 ;24-Zeilen-Darstellung and #$77 ; einschalten sta $d011 lda #$28 ;nächster IRQ bei Zeile $28 sta $d012 dec $d019 ;VIC-ICR löschen lda #<soff;Routine für nächsten IRQ sta $fffe ; "SOFF" in IRQ-Vektor lda #>soff; eintragen sta $ffff pla ;Prozessorregs. wieder vom tay ; Stapel holen und IRQ pla ; beenden tax pla rti
Wir schalten hier also an der üblichen
Position auf 24- Zeilen-Darstellung herunter, damit der VIC vergisst, den oberen und unteren Bildschirmrand zu zeichnen. Gleichzeitig wird ein neuer IRQ
initialisiert, der bei Erreichen von
Rasterzeile $28( acht Rasterzeilen vor
Beginn des sichtbaren Bildschirmfens- ters) die Routine " SOFF" anspringen
soll. Diese Routine übernimmt nun die
Aufgabe, die Darstellung der Charakterzeilen zu verhindern:
soff: pha ;Prozessorregs. retten txa pha tya pha
lda $ d011 ; Bild ausschalten ( durch and #$6 F ; ausmaskieren von Bit4) sta $ d011
lda #$32 ;nächster IRQ bei Raster- sta $d012 ; zeile $32 dec $d019 ;VIC-ICR löschen lda #<son ;Nächster IRQ soll auf sta $fffe ; Routine "SON" springen lda #>son sta $ffff pla ;Prozessorregs. wieder vom tay ; Stapel holen und IRQ pla ; beenden tax pla rti
Wie Sie sehen eine recht einfache Aufgabe: durch eine AND-Verknüpfung des
$ D011- Inhalts mit dem Wert $6 F wird einfach das 4 . Bit dieses Registers
gelöscht. Gleichzeitig löschen wir dabei
Bit 7, das ja das High-Bit der Rasterstrahlposition angibt, womit wir also
auch dieses Bit für den folgenden Raster- IRQ bei Zeile $32 vorbereitet hättem. Die Routine, die hier abgearbeitet
werden soll, heisst " SON" und ist für
das Wiedereinschalten des Bildschirms
verantwortlich. Da sich Rasterzeile $32 im sichtbaren Fenster befindet wäre somit der VIC überlistet und soweit gebracht, daß er keine Charakterzeilen mehr liest, geschweige denn darstellt.
Gleichzeitig schaltet diese Routine wieder auf die 25- Zeilen-Darstellung zurück
( Bit 3 von $ D011 muß gesetzt werden), damit das Abschalten des Borders auch im
nächsten Rasterstrahldurchlauf funktioniert:
SON: pha ;Prozessorregs. retten txa pha tya pha
lda $ d011 ; Bild und 25- Zeilenora #$18 ; Darstellung einschalten sta $ d011
lda #$fa ;nächster IRQ wieder bei sta $d012 ; Zeile $FA dec $d019 ;VIC-ICR löschen lda #<bordirq;Wieder "BORDIRQ" in sta $fffe ; IRQ-Vektor eintragen lda #>bordirq sta $ffff pla ;Prozessorregs. wieder vom tay ; Stapel holen und IRQ pla ; beenden tax pla rti
Nachdem Register $ D011 auf den gewünschten Wert zurückgesetzt wurde, wird der
IRQ wieder für die Routine " BORDIRQ" bei
Rasterzeile $ FA vorbereitet, womit sich
der Kreis schließt und unser Programmbeispiel komplett ist.
3)" ESCOS"- EINEN SCHRITT WEITER Nachdem wir nun unser Timing-Problem
gelöst, und die störenden Charakter-Zeilen aus dem Weg geräumt haben, möchten wir wieder zu unserer eigentlichen
Aufgabenstellung zurückkehren: dem bild- schirmfüllenden Darstellen von Sprites.
Hierzu müssen wir, nachdem oberer und
unterer Bildschirmrand, sowie die Charakterzeilen abgeschaltet wurden, zusätzlich auch noch die Bildschirmränder links und rechts deaktivieren. Das
Funktionsprinzip einer solchen Sideborderroutine sollte Ihnen noch aus einem
der ersten Kursteile im Kopf sein: durch
rechtzeitiges Umstellen von 40- auf 38- Spaltendarstellung und zurück tricksen
wir den VIC nach dem selben Prinzip aus, wie wir es bei den horizontalen Bildschirmrändern tun. Dadurch aber, daß
sich der Rasterstrahl horizontal recht
schnell bewegt, kommt es dabei auf ein
höchst exaktes Timing an. Einen Taktzyklus zu früh oder zu spät funktioniert
die Routine schon nicht mehr. Wenn man
das Ganze nun zusätzlich noch mit dem
Üffnen des oberen und unteren Randes, sowie dem Abschalten der Charakter-Zeilen und einem Sprite-Multiplexer kombinieren muß, so könnte man meinen, daß dies eine recht programmieraufwendige
Sache werden kann. Doch keine Panik, die
Umsetzung ist einfacher als Sie glauben.
Am Besten sehen Sie sich erst einmal das
Demoprogramm " ESCOS1" an. Es wird wie
üblich geladen und mit SYS4096 gestartet, und zeigt dann einen vollends mit
Sprites gefüllten Bildschirm - und zwar
über alle Ränder hinaus! Um so etwas nun
sebst zu programmieren, werden wir
zunächst auf die organisatirischen Probleme und deren Lösung eingehen:
Als Erstes müssen Sie davon ausgehen, daß wir keine IRQ-Routine im eigentlichen Sinne programmieren werden. Aufgrund des exakten Timings, das zum Abschalten des linken und rechten Randes
notwendig ist, muß der Prozessor nahezu
während des gesamten Rasterdurchlaufs
damit beschäftigt sein, die richtige
Rasterposition abzuwarten, um zwischen
der 38- und 40- Zeilen-Darstellung hinund herzuschalten. Dadurch wird ledi- glich ein einziger IRQ pro Rasterdurchlauf aufgerufen, nämlich direkt zu Anfang desselben, in Rasterzeile 0 . Dieser
IRQ muß nun, auf die uns schon bekannte
Art und Weise," geglättet" werden, so
daß kein einziger Taktzyklus Unterschied
zum vorherigen Rasterdurchlauf besteht.
Ab dann ( durch das Glätten, das 2 Rasterzeilen dauert also ab Zeile 2) beginnt der Prozessor damit in jeder einzelnen Rasterzeile den Rand abzuschalten. Dies geschieht dadurch, daß wir
nach jedem Umschalten der Spaltendarstellung genau am Öbergangspunkt zwischen sichtbarem Bildschirmfenster und
- rahmen, exakt 63 Taktzyklen verzögern, bevor dieser Vorgang wiederholt wird. So
zumindest sähe es aus, wenn wir keine
Sprites darzustellen hätten. Da wir dies
jedoch tun, müssen wir weiterhin berücksichtigen, daß der VIC zum Darstellen
der Sprites den Prozessor ebenso anhalten muß, wie beim Lesen der Charakterzeilen, um sich die Spritedaten aus dem Speicher zu holen. Hierbei braucht er 3 Taktzyklen für das erste Sprite, und
dann jeweils 2 Zyklen für alle weiteren, eingeschalteten Sprites. Da wir alle 8 Sprites benutzen, müssen wir also noch
den Betrag 3+7*2=17 von den 63 Zyklen
abziehen und erhalten somit exakt 46 Taktzyklen, die der Prozessor pro Rasterzeile " verbrauchen" muß.
( Anm. d. Red. : Bitte wählen Sie jetzt den zweiten Zeil des IRQ-Kurses aus dem
Textmenu.)