IRQ-KURS
"Die Hardware ausgetrickst..."
(Teil 11)
----------------------------------------
Herzlich Willkommen zum elften Teil un-
seres IRQ-Kurses. Wie schon in den letz-
ten Kursteilen, werden wir uns auch die-
sen 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. Die-
sen Effekt nennt man "ESCOS", der Dreh-
und 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 lin-
ker und rechter Bildschirmrand abge-
schaltet werden. Wir hatten weiterhin
gelernt, daß in diesen Bereichen aus-
schließlich Sprites auftauchen können,
die durch die abgeschalteten Ränder
sichtbar sind, wo sie sonst von letzte-
ren ü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 Genauig-
keit erforderte. Desweiteren wird Ihnen
aus dem letzten Kursteilen bestimmt noch
die Sprite-Multiplexer-Routine in Kombi-
nation mit einem Moviescroller im Kopf
sein, mit der wir 104 Sprites gleichzei-
tig auf den Bildschirm brachten. Wie Sie
sich vielleicht erinnern, waren wir da-
bei an gewisse Grenzen gebunden. So war
z.B. zwischen zwei Spritezeilen immer
ein Abstand von ca. 2 Rasterzeilen er-
forderlich, 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 nor-
malen Rasterzeilen zu unterscheiden hat-
te. In dieser Folge unseres Kurses wol-
len wir nun all diese Komponenten mitei-
nander verbinden und eine Möglichkeit
kennenlernen, Timingprobleme durch Cha-
rakterzeilenberücksichtigung, zu umge-
hen. Das Endergebnis wird ein flächen-
deckend (!) mit Sprites belegter Bild-
schirm sein, wobei weder Leerräume zwi-
schen 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 Kur-
steils, dem Timing-Problem, das sich uns
entgegenstellt. Möchten wir nämlich alle
Bildschirmränder abschalten und gleich-
zeitig auch noch die Sprites multiple-
xen, so können wir programmtechnisch in
"Teufels Küche" gelangen. Wir müssten
berücksichtigen, daß im sichtbaren Bild-
schirmfenster alle acht Rasterzeilen
eine Chakaterzeile auftritt, gleichzei-
tig müsste in jeder Rasterzeile der lin-
ke und rechte Bildschirmrand abgeschal-
tet, sowie in jeder 21. Rasterzeile die
Sprites neu positioniert werden. Dabei
stellen vor allem die Charakterzeilen
ein großes Problem dar. Wir müssten un-
terscheiden zwischen Rasterstrahlposi-
tionen im oberen und unteren Bildschirm-
rand und innerhalb des sichtbaren Bild-
schirmfensters, und zudem noch für letz-
teren Fall berücksichtigen, wann sich
der VIC gerade in einer Chakaterzeile
befindet und wann in einer normalen Ra-
sterzeile. 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äl-
len eine FLD-Routine, die die Charakter-
zeile im fraglichen Bildschirmbereich
einfach nach unten "wegdrückte", so daß
wir in jeder Rasterzeile 63 Taktzyklen
zur Verfügung hatten und somit ein ein-
heitliches 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 Bild-
schirm mit Sprites füllen möchten, kön-
nen wir davon ausgehen, daß wir keiner-
lei Hintergrundgrafik, bzw. Textzeichen
benötigen. Es gibt nun einen Trick, den
wir noch nicht kennengelernt haben, mit
dem wir die Charakterzeilen ganz ab-
schalten können, so daß nur noch die
Sprites dargestellt werden. Wie fast
immer ist Register $D011, ein Dreh- und
Angelpunkt der VIC-Trickeffekt-Kiste,
für diesen Trick verantwortlich. Mit Bit
4 dieses Registers können wir nämlich
den gesamten Bildschirm abschalten, was
einer Deaktivierung des VICs gleich-
kommt. Er wird durch das Löschen dieses
Bits veranlasst, auf dem gesamten Bild-
schirm nur noch die Rahmenfarbe darzu-
stellen, und keine Charakterzeilen mehr
zu lesen. Die Sprites bleiben jedoch
weiterhin aktiv, obwohl sie jetzt un-
sichbar sind, da sie jetzt auf dem ge-
samten Bildschirm mit dem Rahmen über-
deckt 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 Raster-
strahl nun Rasterzeile $30, an der ei-
gentlich das sichtbare Bildschirmfenster
beginnt, so prüft der VIC, ob der Bild-
schirm nun ein- oder ausgeschaltet ist.
In letzterem Fall deaktiviert er seine
Zeichenaufbau-Schaltkreise bis zum näch-
sten 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 Bildschirm-
hintergrund, auf dem sich auch die Spri-
tes 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
$3FFF) 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 Ih-
nen nun auflisten möchte. Sie finden es
auf dieser MD auch als fertig ausführba-
res 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 Initialiserungsrou-
tine 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 $3fff ; 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 Spri-
te-Pointer und schalten alle acht Spri-
tes 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 #$1b ;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" an-
springt, 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 he-
runter, damit der VIC vergisst, den obe-
ren und unteren Bildschirmrand zu zeich-
nen. 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 Charakter-
zeilen zu verhindern:
soff:
pha ;Prozessorregs. retten
txa
pha
tya
pha
lda $d011 ;Bild ausschalten (durch
and #$6F ; 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 Aufga-
be: durch eine AND-Verknüpfung des
$D011-Inhalts mit dem Wert $6F wird ein-
fach das 4.Bit dieses Registers
gelöscht. Gleichzeitig löschen wir dabei
Bit 7, das ja das High-Bit der Raster-
strahlposition angibt, womit wir also
auch dieses Bit für den folgenden Ra-
ster-IRQ bei Zeile $32 vorbereitet hät-
tem. 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 so-
mit der VIC überlistet und soweit ge-
bracht, daß er keine Charakterzeilen
mehr liest, geschweige denn darstellt.
Gleichzeitig schaltet diese Routine wie-
der auf die 25-Zeilen-Darstellung zurück
(Bit 3 von $D011 muß gesetzt werden),
damit das Abschalten des Borders auch im
nächsten Rasterstrahldurchlauf funktio-
niert:
SON:
pha ;Prozessorregs. retten
txa
pha
tya
pha
lda $d011 ;Bild und 25-Zeilen-
ora #$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ünsch-
ten 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 Programm-
beispiel 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öch-
ten 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 Cha-
rakterzeilen abgeschaltet wurden,
zusätzlich auch noch die Bildschirmrän-
der links und rechts deaktivieren. Das
Funktionsprinzip einer solchen Sidebor-
derroutine 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 Bild-
schirmrändern tun. Dadurch aber, daß
sich der Rasterstrahl horizontal recht
schnell bewegt, kommt es dabei auf ein
höchst exaktes Timing an. Einen Taktzy-
klus 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 kom-
binieren 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 gestar-
tet, 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 Pro-
bleme und deren Lösung eingehen:
Als Erstes müssen Sie davon ausgehen,
daß wir keine IRQ-Routine im eigentli-
chen Sinne programmieren werden. Auf-
grund des exakten Timings, das zum Ab-
schalten 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 hin-
und herzuschalten. Dadurch wird ledi-
glich ein einziger IRQ pro Rasterdurch-
lauf aufgerufen, nämlich direkt zu An-
fang 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 Ra-
sterzeilen dauert also ab Zeile 2) be-
ginnt der Prozessor damit in jeder ein-
zelnen Rasterzeile den Rand abzuschal-
ten. Dies geschieht dadurch, daß wir
nach jedem Umschalten der Spaltendar-
stellung genau am Öbergangspunkt zwi-
schen 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ück-
sichtigen, daß der VIC zum Darstellen
der Sprites den Prozessor ebenso anhal-
ten muß, wie beim Lesen der Charakter-
zeilen, 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 Ra-
sterzeile "verbrauchen" muß.
(Anm. d. Red.: Bitte wählen Sie jetzt
den zweiten Zeil des IRQ-Kurses aus dem
Textmenu.)