IRQ-KURS "Die Hardware ausgetrickst..." (Teil 8)
Herzlich willkommen zum achten Teil unseres Raster-IRQ- Kurses. Heute wollen
wir uns mit einem besonders interessanten Rastertrick beschäftigen: der FLI-Routine, die es uns ermöglicht, Grafiken
mit mehr als 2 Farben im Hires-Modus, bzw. mehr als 4 Farben im Multicolor-Modus, jeweils pro 8 x8- Pixel-Block, darzustellen. Durch die dabei entstehende
Farbvielfalt können sehr eindrucksvolle
Bilder angezeigt werden, die bei geschickten Grafikern schon an die Qualität von Amiga-Bildern reichen können!
1) GRUNDLAGEN Wollen wir uns zunächst einmal anschauen, wie der VIC vorgeht, um eine Bitmap-Grafik auf den Bildschirm zu zaubern:
Zunächst einmal muß der Grafikmodus eingeschaltet werden, wobei die Lage der
Bitmap im Speicher mitangegeben wird.
Nun zeigt der VIC also die Bits des angegegebenen Speicherbereichs als einzelne Pixel auf dem Bildschirm an. Um diesen Pixeln nun auch noch Farbe zu verleihen, muß in zwei Fälle unterschieden
werden:
a) DER HIRES-MODUS Hier bestimmt ein Farbcode im Video-RAM, das im Textmodus zur Darstellung der
Zeichen benutzt wird und sich normalerweise bei $0400( dez.1024) befindet, die Farbe der Pixel innerhalb eines
8 x8- Pixel-Blocks. So legt das erste Byte
des Video-RAMs ( als Zeichen ganz links
oben), die Farbe für die 8 x8, im Grafikmodus quasi " über" ihm liegenden, Pixel
fest. Das zweite Byte ist für den nächsten 8 x8- Pixel-Block zuständig, und so weiter. Da der VIC insgesamt nur 16 Farben kennt, sind dabei jeweils nur die
unteren vier Bits eines Video-RAM- Bytes
von Bedeutung. Die oberen vier sind unbenutzt und werden ignoriert.
b) DER MULTICOLOR-MODUS In diesem Modus werden zwei nebeneinander liegende Pixel jeweils zu einem
Farbcode zusammengefasst. Sind beide 0, so erscheint an ihrer Stelle die Hintergrundfarbe, sind beide auf 1, so wird
für beide die Farbe aus einem äquvalenten Byte des Color-RAMs geholt ( bei
Adresse $ D800- dez.55296), das normalerweise zur Farbgebung der einzelnen
Zeichen im Textmodus verwendet wird. Bei
der Bitkombination "10" wird wieder das
Lownibble ( die unteren vier Bits) des
Video-RAMs zur Farbgebung ausgewertet.
Bei der Bitkombination "10" sind die, im
Hires-Modus unbenutzten, oberen vier
Bits des Video-RAMs für die Pixelfarbe
zuständig. Sie sehen also, daß das Vi- deo-RAM im Multicolormodus gleich zwei
Farbwerte für Pixelkombinationen festlegt.
2) DAS FLI-PRINZIP Soviel zur Darstellung einer Grafik.
Sicherlich ist Ihnen bei den obigen
Ausführungen das häufige Auftreten des
Begriffs " Video-RAM", bzw." Video-Map" aufgefallen. Und genau dieser Begriff
ist der Schlüssel zu unserer FLI-Routine. Wie Sie vielleicht wissen, kann
man die Lage der Video-Map, innerhalb
des Adressierungsbereichs des VICs ( im
Normalfall von $0000-$3 FFF) in 1 KB-Schritten verschieben. Hierfür ist Register 24 des VICs ( Adresse $ D018- dez.
53272) zuständig. Seine oberen 4 Bits
geben die Lage der Video-Map an, also
des RAM-Bereichs, der für die Darstellung der Textzeichen, bzw. im Grafikmodus der Farbzeichen, zuständig ist. Die
unteren Bits von 0-3 bestimmen die Lage des Zeichengenerators, also des Speicherbereichs, in dem die Daten für den
Zeichensatz ausgelesen werden. Dies soll
uns hier jedoch nicht interessieren und
sei nur nebenbei angemerkt.
Konzentrieren wir uns auf die Bits 4-7 :
Sie bestimmen die Lage des Video-RAMs
innerhalb des 16 KB-Bereichs des VICs.
Die im Folgenden angegebenen Adressen
verstehen sich also als Offsets, die auf
die Startadresse des 16 KB-Bereichs aufaddiert werden müssen:
Wert Bits Bereich (Hex) Bereich (Dez)
0: 0000 $0000-$03FF 0- 1023 1: 0001 $0400-$07FF 1024- 2047 2: 0010 $0800-$0BFF 2048- 3071 3: 0011 $0CFF-$0FFF 3072- 4095 4: 0100 $1000-$13FF 4096- 5119 5: 0101 $1400-$17FF 5120- 6143 6: 0110 $1800-$1BFF 6144- 7167 7: 0111 $1CFF-$1FFF 7168- 8191 8: 1000 $2000-$23FF 8192- 9215 9: 1001 $2400-$27FF 9216-10239 10: 1010 $2800-$2BFF 10240-11263 11: 1011 $2CFF-$2FFF 11264-12287 12: 1100 $3000-$33FF 12288-13311 13: 1101 $3400-$37FF 13312-14335 14: 1110 $3800-$3BFF 14336-15359 15: 1111 $3CFF-$3FFF 15360-16383
Obwohl die Video-Map nur 1000 Bytes lang
ist, habe ich hier dennoch 1024- Byte-Bereiche angegeben. Das hat nämlich auch
eine Bedeutung für den nächsten Kursteil.
Desweiteren wollen wir noch schnell klären, wie man den 16 KB-Bereich des VICs
verschiebt, da die FLI-Routine eine Menge Video-Speicher benötigt ( nämlich die
vollen 16 KB), sollten wir den VIC in
einem Bereich arbeiten lassen, in dem
wir nicht auf Zeropage-Adressen und
Sprungvektoren ( die im ersten VIC-Bereich - von $0000-$3 FFF - eine Menge Platz wegnehmen) Rücksicht nehmen zu
müssen.
Der Adressbereich des VIC wird nun mit
den untersten zwei Bits der Adresse
$ DD00( dez.56576) angegeben ( richtig:
dies ist ein CIA-B Register, das dem VIC
seinen Adressbereich vorschreibt) . Hier
eine Auflistung der möglichen Bitkombinationen und der Adressbereiche die sie
aktivieren:
3: 11 $0000-$3FFF 0-16383 2: 10 $4000-$7FFF 16384-32767 1: 01 $8000-$BFFF 32768-49151 0: 00 $C000-$FFFF 49152-65535
In unserem Programmbeispielen werden wir
den VIC-Bereich nach $4000 verschieben, womit der Wert 2 in die Adresse $ DD00 geschrieben werden muß. Die tatsächliche
Adresse der Video-Map ist dann immer
$4000 plus der oben angegebenen Offseta- dresse.
Nachdem wir nun also die Grundlagen
gelkärt hätten, ist die Erklärung des
Prinzips der FLI-Routine höchst simpel:
Zum Einen wissen wir, daß die Video-Map
zur Farbgebung der Grafik verwendet
wird. Zum Anderen haben wir gesehen, wie
die Startadresse, aus der der VIC sich
die Video-Map- Daten holt, verschoben
werden kann. Was liegt nun also näher
als zwei und zwei zusammenzuzählen, und
eine Raster-IRQ- Routine zu schreiben, die in JEDER Rasterzeile eine andere
Video-Map aktiviert? Die Folge dieser
Operation wäre dann nämlich die Möglichkeit, einem 8 x8- Pixel Block der Grafik
in jeder Zeile eine neue Farbe zuzuteilen ( im Multicolormodus sogar 2), so daß
wir die 2-, bzw.4- Farbeinschränkung auf
einen Bereich von 1 x8 Pixeln reduzieren!
3) DIE UMSETZUNG
Vom Prinzip her klingt das natürlich
sehr einfach, jedoch stellt sich uns
noch ein kleines Problem in den Weg:
Wie wir bei der Beschreibung des FLD-Effektes schon gelernt hatten, liest der
VIC ja nur in jeder Charakterzeile ( also
jede achte Rasterzeile), die 40 Bytes, die er in den folgenden acht Rasterzeilen darzustellen hat. Somit würde ein
einfaches Umschalten auf eine neue Video- Map nichts bewirken, da der VIC ja
immer noch mit den 40 Zeichen, die er zu
Beginn der Charakterzeile gelesen hat, die folgenden Zeilen darstellen würde - und das selbst bei umgeschalteter Video-Map. Also müssen wir ihn auch hier mit
einem kleinen Raster-Trick " veräppeln" .
Man kann den VIC nämlich auch dazu zwingen, eine Charakterzeile NOCHMALS zu
lesen. Der anzuwendende Trick ist uns
dabei gar nicht mal so unbekannt, denn
er funktioniert ähnlich wie der FLD-Effekt. Bei diesem schoben wir den Anfang der nächsten Charakterzeile durch Hochsetzen der vertikalen Bildschirmverschiebung vor dem Rasterstrahl her, so
daß die Charakterzeile für den VIC erst
begann, als wir mit unserer Manipulation
aufhörten. Nun arbeiten wir im Prinzip
genauso, nur daß wir die Chrakterzeile
nicht VOR dem Rasterstrahl wegschieben, sondern MIT ihm. Verschieben wir den
Vertikal-Offset nämlich so, daß er immer
mit dem Anfang einer Charakterzeile zusammenfällt, so meint der VIC, er müsse
jetzt die neuen Charakterdaten lesen, selbst wenn er das in der Rasterzeile
zuvor auch schon getan hat. Schalten wir
nun gleichzeitig auch noch auf eine andere Video-Map um, so liest der VIC, so
als wäre alles in Ordnung, die 40 Charakter der neuen Map!
Bevor ich mich nun aber in theoretischen
Erklärungen verliere, möchte Ich Ihnen
ein Programmbeispiel zeigen, das alles
einfacher zu erklären vermag. Sie finden
es auf dieser MD unter dem Namen " GO-FLI- CODE", und müssen es mit der Endung",8,1" laden. Gleichzeitig ( und ebenfalls mit ",8,1") sollte auch noch die
lange Grafik " GO-FLIPIC" geladen werden, damit Sie beim Start der Routine mittels
" SYS4096", auch etwas auf dem Bildschirm
sehen. Es handelt sich dabei um das Logo
unseres Schwestermagazins " Game On", und
zwar in schillernd bunten Farbabstufungen!
Doch kommen wir nun zum Sourcecode dieser FLI-Routine. Zunächst einmal werde
ich Ihnen die Initialisierung hier auflisten, die größenteils identisch mit
den zuvorigen Init-Routinen ist, jedoch
auch einige FLIspezifische Einstellungen vornimmt:
Init:sei ;IRQs sperren lda $7F ;CIA-IRQs und NMIs sta $dc0d ; sperren sta $dd0d bit $dc0d ;ggf. vorhandene IRQ- bit $dd0d ;oder NMI-Anfr. löschen lda #$0b ;Bildschirm sta $d011 ; abschalten ldy #$00 ;Daten für Color-Map lda $3c00,y ; von $3C00 sta $d800,y ; nach $D800 lda $3d00,y ; kopieren sta $d900,y lda $3e00,y sta $da00,y lda $3f00,y sta $db00,y iny bne color lda #$00 ;Hardvektor füt IRQ bei sta $fffe ; $FFFE/$FFFF auf lda #$11 ; eigene Routine bei sta $ffff ; $1100 setzen ldx #$38 ;Basisw. Vert.Versch. stx $02 ; in Zeropage ablegen inx ;Pro Zeile +1 und stx $03 ; ebenfalls in ZP abl. inx ;usw. bis X=$3F stx $04 inx stx $05 inx stx $06 inx stx $07 inx stx $08 inx stx $09 lda #$5C ;Rasterz. $d012 ist sta $d012 ; IRQ-Auslöser lda #$81 ;Raster als IRQ-Quelle sta $d01a ; einschalten dec $d019 ;ggf. VIC-IRQ freigeben lda #$35 ;Basic- u. Betr.Sys.- sta $01 : ROM abschalten cli ;IRQs freigeben
lda #$7 f ; Tastaturport init.
sta $ dc00
spc: lda $dc01 ;Auf 'SPACE'-Taste cmp #$ef ; warten bne spc lda #$37 ;ROMs wieder sta $01 ; einschalten jmp $fce2 ;und RESET auslösen
Hier schalten wir zunächst alle CIA-IRQs
ab, tragen die Startadresse unserer FLI-Routine bei $1100 in den Hard-IRQ- Vektor
$ FFFE/$ FFFF ein, schalten das Betriebssystem ab, damit der Vektor auch
angesprungen wird, und erlauben dem VIC
in Rasterzeile $5 C einen Raster-IRQ auszulösen. Zudem wird eine Tabelle in den
Zeropageadressen von $02 bis $09 initialisiert, die in Folge die Werte von $38 bis $3 F enthält. Diese müssen wir später, je nach Rasterzeile, in Register
$ D011 schreiben, damit der Anfang der
Charakterzeile immer in der aktuellen
Rasterzeile ist. Durch den Basiswert $38 legen wir zunächst nur fest, daß der Bildschirm eingeschaltet ist, und sich
der VIC im Grafikmodus und in 25- Charakterzeilen-Darstellung befindet.
Durch das jeweilige aufaddieren von 1 wird dann legiglich der vertikale Verschiebeoffset um 1 erhöht, was dann immer dem jeweiligen Wert für den Beginn
einer Charakterzeile entspricht ( Startwert $38-> Verschiebung=0 für tatsächliche Charakterzeile; nächster Wert=$39-> Verschiebung=1 Zeile, wehalb die erste Rasterzeile hinter der normalen Charakterzeile vom VIC wieder als Charakterzeile aufgefasst wird; usw.) . Die
Werte werden übrigens deshalb in eine
Tabelle innerhalb der Zeropage eingetragen, damit das Timing später besser
klappt.
Desweiteren wird hier der Inhalt der
Color-Map initialisiert. Hierzu sollte
ich vielleicht noch erläutern, wie das
68 Blocks lange FLIPIC-File aufgebaut
ist: zunächst einmal wird es an Adresse
$3 C00 geladen, wo sich auch die $0400
Bytes für die Color-Map befinden. Ab
Adresse $4000 beginnen nun die acht Video- Maps, die später von der FLI-Routine
durchgeschaltet werden. Auch sie sind
jeweils $0400 Bytes lang ( was einer Gesamtlänge von $0400*8=$2000 Bytes
gleichkommt) . Hiernach, im Bereich von
$6000-$8000 befindet sich nun die darzustellende Grafik-Bitmap. Was die Init-Routine nun macht, ist lediglich die
Color-Map- Daten zwischen $3 C00 und $4000 nach $ D800( Basisadresse des Color-RAMs), zu kopieren. Die Video-RAM- Daten
liegen in den Speicherbereichen, die mit
den Werten von 0-7 für die Highbits von
Register $ D018, angewählt werden können
( was gleichzeitig auch der Anordnung in
Rasterzeilen entspricht - Video-RAM Nr.0($4000) für die 0 . Rasterzeile innerhalb
Charakterzeile; Video-RAM Nr.1($4400) für die 1 . Rasterzeile innerhalb der
Charakterzeile; usw) .
Kommen wir nun zur Interruptroutine selbst. Sie beginnt wie all unsere zeitkritischen Raster-IRQs zunächst mit der
Glättungsroutine, wobei ein weiterer
Interrupt festgelegt und ausgelöst wird, bevor die eigentliche FLI-Routine folgt.
Sie beginnt wieder ab dem Label " Onecycle", ab dem der IRQ " geglättet" ist.
Hier nun der eigentliche Kern der Routine. Da der Interrupt bei Rasterzeile $5 C
ausgelöst wurde, und die Glättung zwei
Rasterzeilen verbrauchte, befinden wir
uns nun also in Zeile $5 E, womit wir
also zwei Rasterzeilen vor Beginn der
achten Charakterzeile stehen:
dec $d019 ;VIC-ICR löschen lda #$5C ;Neue IRQ-Rasterzeile sta $d012 ; festlegen ($5C) lda #$00 ;IRQ-Vektor wieder auf sta $fffe ; die erste IRQ-Routine lda #$11 ; verbiegen (für den sta $ffff ; nächsten Aufruf)
lda #$00 ; Bildschirmrahmenund sta $ d020 ; Hintergrundfarbe auf sta $ d021 ;' schwarz' setzen
NOP ;Hier folgen nun 40 NOPs ... ; um bis zum richtigen NOP ; Zeitpunkt zu verzögern ldy #$08 ;Rasterzeilenzähler init. jsr fliline ;8 FLI-Rasterzeilen jsr fliline ; für 12 Charakterzeilen jsr fliline ; durchführen (gesamte jsr fliline ; Größe des FLI-Bereichs: jsr fliline ; 8x12=96 Rasterzeilen) jsr fliline jsr fliline jsr fliline jsr fliline jsr fliline jsr fliline jsr fliline
lda #$02 ; Bildschirmrahmenund sta $ d020 ; Hintergrundfarbe auf sta $ d021 ;' rot' setzen
lda #$38 ;Vertikalverschiebung sta $d011 ; zurücksetzen (=0) lda #$88 ;VideoMap 8 sta $d018 ; einschalten pla ;Prozessorregister vom tay ; Stapel zurückholen pla ; und IRQ beenden. tax pla rti
Hier werden erst einmal die Vorbereitungen für den nächsten Interrupt getroffen
( also für den nächsten Bildaufbau) . Dies
ist das Rücksetzen des IRQ-Vektors, auf
die Glättung-IRQ- Routine, das neue festlegen der Rasterzeile $5 C als IRQ-Auslöser, sowie das Löschen des VIC-ICR- Registers durch Zugriff auf Adresse
$ D019 . Nun wird das Y-Register mit dem
Wert 8 initialisiert, der in der nun
folgenden " FLILINE"- Routine gebraucht wird. Selbige führt den eigentlichen
FLI-Effekt aus, wobei Sie immer acht
Rasterzeilen lang, seit Beginn einer
Rasterzeile, den Effekt erzeugt. Durch
den 12- maligen Aufruf lassen wir ihn
also ab Rasterzeile $5 E für 96 Rasterzeilen aktiv sein. Hier nun der Sourcecode zur FLILINE-Routine:
( Anm. d. Red. : Bitte wählen Sie nun den zweiten Teil des Kurses aus dem Textmenu)