Mehr Details, dank MCI (Multi Color Interlaced)
Neben FLI, ist der MCI Modus wohl der wichtigste „neue“ Grafikmodus des C64. Diese beiden stellen die Basis für viele weitere Modi dar (z. B. IFLI oder SHI). Werfen wir mal einen Blick auf MCI und wie er funktioniert.
Ihr solltet bereits die Beiträge VIC-II: Grafikmodes – BITMAP (Multi-Color) und VIC-II: Speicherbereiche festlegen gelesen haben! Außerdem ist es sicherlich hilfreich, die VIC-II Register griffbereit zuhaben.
MCI – Funktionsprinzip
Als Programmierer könnt ihr euch zunächst mal freuen, der Multi Color Interlaced (MCI) Modus funktioniert nämlich technisch viel einfacher, als z. B. FLI. Ihr braucht eigentlich nur zwei passende Bitmaps und müsst ein Wenig scrollen. Für den Grafiker wird es aber etwas aufwendiger, da die Bilder speziell angepasst sein müssen.
Die Idee hinter MCI ist, dass ihr abwechselend, zwei entsprechend vorbereitete Bitmaps anzeigt, die um einen Pixel versetzt sind. Dadurch wirkt das Bild am C64 detailreicher, es zuckt aber auch ständig hin und her.
Aber seht besser selbst…
Das Bild (bzw. die Bilder)
Da ich absolut keine künstlerische Ader habe, war ich so frei und habe mir für unseren Test ein MCI Bild stibitzt. Es nennt sich „Take me home“, stammt von Leon von der Singular Crew und wurde 2007 veröffentlicht.
Hier könnt ihr euch das Original herunterladen.
Take me home (MCI Demo)
Das Programm
Beginnen wir einfach damit, dass wir zunächst die erste Grafik anzeigen. Dafür müssen wir nur ein kleines Programm erstellen, dass euch im Großen und Ganzen schon geläufig sein sollte. Da ihr ja bereits VIC-II: Grafikmodes – Bitmap (Multi-Color) gelesen habt, gibt es eigentlich nichts Neues.
Hier einfach das komplette Listing…
;*** VIC-II Speicher-Konstanten VICBANKNO = 0 ;Nr. (0 - 3) der 16KB Bank | Standard: 0 VICSCREENBLOCKNO = 1 ;Nr. (0 -15) des 1KB-Blocks für den Textbildschirm | Standard: 1 VICCHARSETBLOCKNO = 2 ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz | Standard: 2 VICBITMAPBBLOCKNO = 1 ;Nr. (0 - 1) des 8KB-Blocks für die BITMAP-Grafik | Standard: 0 VICBASEADR = VICBANKNO*16384 ;Startadresse der gewählten VIC-Bank | Standard: $0000 VICCHARSETADR = VICBASEADR+VICCHARSETBLOCKNO*2048 ;Adresse des Zeichensatzes | Standard: $1000 ($d000) VICSCREENRAM = VICBASEADR+VICSCREENBLOCKNO*1024 ;Adresse des Bildschirmspeichers VICBITMAPADR = VICBASEADR+VICBITMAPBBLOCKNO*8192 ;Adresse der BITMAP VICCOLORRAM = $d800 ;*** Startadresse *=$0801 ;** BASIC-Zeile: 2018 SYS 2062 !word main-2, 2018 !byte $9e !text " 2062" !byte $00,$00,$00 !zone main main ;Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren lda $d016 ;VIC-II Register 22 in den Akku ora #%00010000 ;Multi-Color über BIT-4 sta $d016 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit BIT-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des Bitmap- sta $d018 ;festlegen jsr copyColor ;Farben kopieren jmp * ;Endlosschleife !zone copyColor copyColor lda #0 ;Rahmenfarbe schwarz sta $d020 lda #15 ;Hintergrundfarbe hellgrau sta $d021 ldx #0 ;Schleifenzähler initialisieren .loop lda color,X ;Farben ins Color-RAM kopieren sta VICCOLORRAM,X lda color+256,X sta VICCOLORRAM+256,X lda color+512,X sta VICCOLORRAM+512,X lda color+768,X sta VICCOLORRAM+768,X lda char,X ;Farben in den Bildschirmspeicher kopieren sta VICSCREENRAM,X lda char+256,X sta VICSCREENRAM+256,X lda char+512,X sta VICSCREENRAM+512,X lda char+768,X sta VICSCREENRAM+768,X dex ;Schleifenzähler verringern bne .loop ;die nächsten BYTES kopieren rts ;zurück zum Aufrufer ;Daten fürs Farb-RAM (wird nur 1x benötigt) color !bin "MCI_CR.bin" ;Farben der 1. Bitmap für den Bildschrimspeicher char !bin "MCI_SR_1.bin" *=$2000 ;1. Bitmap !bin "MCI_BM_1.bin"
Wie ihr seht, beginnt das Programm mit einer Reihe Konstanten. Wir brauchen nicht alle, aber da die nur für den Assembler von Interesse sind, schaden sie auch nicht. Zu Beginn aktivieren wir zunächst den Multi-Color-Bitmap-Modus. Wir lassen die VIC-Speicherbereiche auf Standard und sorgen einzig in $d018 dafür, dass der Bitmapspeicher in der zweiten Hälfte der ersten 16KB großen VIC-Bank, also bei $2000, beginnt.
Dann kopieren wir mit jsr copyColor die benötigten Farbwerte in den Bildschirmspeicher und ins Color-RAM. Außerdem setzen wir dort die Rahmen- und Hintergrundfarbe. Die Routine sollte euch schon aus VIC-II: Grafikmodes – BITMAP (Multi-Color) bekannt sein, da haben wir sie für die Anzeige des Koala-Bildes genutzt.
Zum Schluß bleibt das Programm einfach in einer Endlosschleife „hängen“.
Jetzt brauchen wir natürlich noch die Daten für das Bild. Ich habe dieses Mal auf das Koala-Format verzichtet und einfach getrennte Dateien für Color-RAM, Bildschirmspeicher und Bitmap angelegt. Das Farb-RAM ist für beide Bilder identisch, daher brauchen wir das nur einmal. Bildschirmspeicher und Bitmap sind aber unterschiedlich, deshalb habe ich die durchnummeriert. Wir binden die drei Dateien einfach hinter unserem Programm ein und sorgen mit *=$2000 dafür, dass die Bitmap direkt an der richtigen Speicherposition liegt. Darum müssen nur, wie oben erwähnt, die Farben einmal kopiert werden.
Um das Programm starten zu können, braucht ihr jetzt natürlich noch die erwähnten Dateien. Im folgenden Download findet ihr bereits alles, was ihr bis zum Ende dieses Beispiels benötigt.
MCI Beispieldaten
Entpackt bitte alle Dateien und kopiert sie mit ins Verzeichnis zu eurem Programmcode.
Erstellt nun das Programm und startet es. Ihr solltet folgendes Bild sehen:
Das Bild ist nun nichts anderes, als eine normale Bitmap. Wie bereits erwähnt, brauchen wir für MCI aber zwei Bilder. Lasst uns das Programm so ändern, dass wir auch die zweite Grafik anzeigen und mit den F-Tasten zwischen den Bildern umschalten können.
Wir wollen ja gleich automatisch, bei jedem neuen Bildaufbau, zwischen den beiden Grafiken hin- und herschalten. Dass wir dies nicht durch Umkopieren erreichen können, ist euch sicherlich klar. Wir müssten ja jedes Mal die 8000 Bytes der Bitmap plus den 1000 Bytes des Bildschirmspeichers kopieren. Dies schaffen wir aber nicht schnell genug. Also werden wir die zweite Grafik in eine andere VIC-Bank legen und nur die Bänke umschalten. Da ich ein fauler Hund bin, machen wir es uns mit der zweiten Grafik ganz einfach. Wir nehmen die VIC-Bank-1. Dabei legen wir den Bildschirmspeicher und die Bitmap so, dass sie relativ betrachtet, an den gleichen Positionen liegen, wie eben bei der ersten Bitmap.
Fügt dazu am Programmbeginn eine neue Konstante hinzu:
VICSCREENRAM_2 = $4400 ;hier liegen die Farben für die 2. Bitmap
Jetzt binden wir am Programmende, hinter der ersten Bitmap von eben, noch die beiden weiteren Dateien ein. Beachtet, dass wir dieses Mal für beide Dateien eine neue Adresse angeben.
;Farben für die 2. Bitmap *=VICSCREENRAM_2 !bin "MCI_SR_2.bin" *=$6000 ;2. Bitmap !bin "MCI_BM_2.bin"
Wenn ihr von den Adressen, den Beginn der von uns verwendeten nächsten VIC-Bank $4000 abzieht, dann landet ihr wieder bei den gleichen Adressen für den Bildschirmspeicher und die Bitmap wie eben $0400 / $2000. Daher müssen wir gleich nur die Bank umschalten, um die Bilder zu wechseln.
Fügt jetzt die folgende Funktion checkKeyboard, am besten direkt hinter jmp *, ein:
!zone checkKeyboard checkKeyboard sei ;Interrupts sperren! ;Sonst funkt man uns evtl. dazwischen lda #%11111110 ;wir wollen PA0 maskieren sta $DC00 ;Wert ins Register CIA-1 Port A schreiben lda $DC01 ;hole Register-Inhalt vom CIA-1 Port B tax ;im X-Register merken and #%00010000 ;hier PB4 prüfen F1 bne .checkF3 ;wenn KEINE 0, weiter mit F3 ;sonst sind wir fertig lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $DD02 ;zum Schreiben freigeben lda #%00000011 ;Bank-0 sta $DD00 ;für das 1. Bild wählen jmp .exit ;und raus .checkF3 txa ;hole Register-Inhalt vom CIA-1 Port B and #%00100000 ;hier PB5 prüfen F3 bne .checkF5 ;wenn KEINE 0, weiter mit F5 lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $DD02 ;zum Schreiben freigeben lda #%00000010 ;Bank-1 sta $DD00 ;für das 2. Bild wählen jmp .exit ;und raus .checkF5 txa ;hole Register-Inhalt vom CIA-1 Port B and #%01000000 ;hier PB6 prüfen F-5 bne .exit ;wenn KEINE 0, dann raus .exit cli ;Interrupts wieder freigeben rts ;zurück zum Aufrufer
Hier prüfen wir einfach, ob F1, F3 oder F5 gedrückt wurde. Bei F1 zeigen wir das erste Bild an und bei F3 das zweite. F5 hat aktuell noch keine Funktion, damit werden wir zum Schluß das automatische Umschalten aktivieren.
Jetzt müssen wir abschließend noch den Aufruf für unsere neue Funktion einfügen. Ersetzt dazu bitte jmp * durch folgende drei Zeilen:
.loop jsr checkKeyboard ;Tastatur prüfen jmp .loop ;Endlosschleife
Wenn ihr das Programm jetzt startet, seht ihr zunächst wieder die Grafk von oben. Drückt einmal F3 und ihr seht die zweite. Euch sollte auffallen, dass sich die Bilder geringfügig unterscheiden. Drückt einfach abwechselnd F1 und F3.
;*** VIC-II Speicher-Konstanten VICBANKNO = 0 ;Nr. (0 - 3) der 16KB Bank | Standard: 0 VICSCREENBLOCKNO = 1 ;Nr. (0 -15) des 1KB-Blocks für den Textbildschirm | Standard: 1 VICCHARSETBLOCKNO = 2 ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz | Standard: 2 VICBITMAPBBLOCKNO = 1 ;Nr. (0 - 1) des 8KB-Blocks für die BITMAP-Grafik | Standard: 0 VICBASEADR = VICBANKNO*16384 ;Startadresse der gewählten VIC-Bank | Standard: $0000 VICCHARSETADR = VICBASEADR+VICCHARSETBLOCKNO*2048 ;Adresse des Zeichensatzes | Standard: $1000 ($d000) VICSCREENRAM = VICBASEADR+VICSCREENBLOCKNO*1024 ;Adresse des Bildschirmspeichers VICSCREENRAM_2 = $4400 ;hier liegen die Farben für die 2. Bitmap VICBITMAPADR = VICBASEADR+VICBITMAPBBLOCKNO*8192 ;Adresse der BITMAP VICCOLORRAM = $d800 ;*** Startadresse *=$0801 ;** BASIC-Zeile: 2018 SYS 2062 !word main-2, 2018 !byte $9e !text " 2062" !byte $00,$00,$00 !zone main main ;Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren lda $d016 ;VIC-II Register 22 in den Akku ora #%00010000 ;Multi-Color über BIT-4 sta $d016 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit BIT-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des Bitmap- sta $d018 ;festlegen jsr copyColor ;Farben kopieren .loop jsr checkKeyboard ;Tastatur prüfen jmp .loop ;Endlosschleife !zone checkKeyboard checkKeyboard sei ;Interrupts sperren! ;Sonst funkt man uns evtl. dazwischen lda #%11111110 ;wir wollen PA0 maskieren sta $dc00 ;Wert ins Register CIA-1 Port A schreiben lda $dc01 ;hole Register-Inhalt vom CIA-1 Port B tax ;im X-Register merken and #%00010000 ;hier PB4 prüfen F1 bne .checkF3 ;wenn KEINE 0, weiter mit F3 ;sonst sind wir fertig lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000011 ;Bank-0 sta $dd00 ;für das 1. Bild wählen jmp .exit ;und raus .checkF3 txa ;hole Register-Inhalt vom CIA-1 Port B and #%00100000 ;hier PB5 prüfen F3 bne .checkF5 ;wenn KEINE 0, weiter mit F5 lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000010 ;Bank-1 sta $dd00 ;für das 2. Bild wählen jmp .exit ;und raus .checkF5 txa ;hole Register-Inhalt vom CIA-1 Port B and #%01000000 ;hier PB6 prüfen F-5 bne .exit ;wenn KEINE 0, dann raus .exit cli ;Interrupts wieder freigeben rts ;zurück zum Aufrufer !zone copyColor copyColor lda #0 ;Rahmenfarbe schwarz sta $d020 lda #15 ;Hintergrundfarbe hellgrau sta $d021 ldx #0 ;Schleifenzähler initialisieren .loop lda color,X ;Farben ins Color-RAM kopieren sta VICCOLORRAM,X lda color+256,X sta VICCOLORRAM+256,X lda color+512,X sta VICCOLORRAM+512,X lda color+768,X sta VICCOLORRAM+768,X lda char,X ;Farben in den Bildschirmspeicher kopieren sta VICSCREENRAM,X lda char+256,X sta VICSCREENRAM+256,X lda char+512,X sta VICSCREENRAM+512,X lda char+768,X sta VICSCREENRAM+768,X dex ;Schleifenzähler verringern bne .loop ;die nächsten BYTES kopieren rts ;zurück zum Aufrufer ;Daten fürs Farb-RAM (wird nur 1x benötigt) color !bin "MCI_CR.bin" ;Farben der 1. Bitmap für den Bildschrimspeicher char !bin "MCI_SR_1.bin" *=$2000 ;1. Bitmap !bin "MCI_BM_1.bin" ;Farben für die 2. Bitmap *=VICSCREENRAM_2 !bin "MCI_SR_2.bin" *=$6000 ;2. Bitmap !bin "MCI_BM_2.bin"
Wir nähern uns der Zielgeraden. Wie eingangs beschrieben, müssen wir die Bilder regelmäßtig umschalten und das zweite Bild um einen Pixel nach rechts scrollen. Laßt uns dies jetzt einbauen.
Damit das Umschalten kontrolliert abläuft, sollten wir es immer zum selben Zeitpunkt machen. Außerdem wäre es ratsam, dies außerhalb des sichtbaren Bereichs vorzunehmen.
Baut die folgende kleine Routine, die auf eine bestimme Rasterzeilenposition wartet, vor checkKeyboard ein. Falls euch Rasterzeilen noch fremd sind, werft mal einen Blick auf Der Rasterzeileninterrupt.
!zone waitRaster waitRaster lda #255 ;gewünschte Rasterzeile .wait cmp $d012 ;falls wir schon in der beq .wait ;gewünschten Zeile sind -> warten .wait1 cmp $d012 ;jetzt warten, bis die gewünschte bne .wait1 ;Rasterzeile erreicht wurde rts ;zurück zum Aufrufer
Die wahrscheinlich schon bekannte Funktion wartet einfach solange, bis die im Akku stehende Rasterzeile (hier 255) erreicht wurde.
Fügt nun eine weitere Konstante zum Programm hinzu:
ZP_AUTO = $02
Diese verwenden wir, um zu erkennen, ob wir automatisch umschalten oder nicht. Nehmt anschließend folgende Änderungen hinter jsr copycolor ;Farben kopieren vor, die neuen Zeilen sind gelb hervorgehoben.
jsr copycolor ;Farben kopieren lda #0 ;0 = automatisch umschalten sta ZP_AUTO .loop jsr waitRaster ;auf Rasterzeile warten jsr checkKeyboard ;Tastatur prüfen lda ZP_AUTO ;ist ZP_AUTO = 0? bne .loop ;falls nicht -> .loop lda #%00000001 ;Datenrichtung für BIT 0 des CIA-Port-A sta $dd02 ;zum Schreiben freigeben lda $dd00 eor #%00000001 ;VIC-Bank zwischen 0 und 1 umschalten sta $dd00 lda $d016 ;VIC-II Register 22 in den Akku eor #%00000001 ;Scrollposition links / rechts um sta $d016 ;einen Pixel umschalten jmp .loop ;endlos wiederholen
Wir initialisieren ZP_AUTO erstmal so, dass direkt beim Start automatisch umgeschaltet wird. Dann warten wir hinter .loop auf unsere Rasterzeile 255. Danach kontrollieren wir die Tastatur und prüfen, ob ZP_AUTO noch 0 ist. Falls nicht, springen wir einfach wieder zum Schleifenanfang. Ist der Wert noch 0, dann schalten wir um. Dazu setzen wir zur Sicherheit noch die Datenrichtung im Port A des CIA auf schreiben fürs erste Bit. Um zwischen der VIC-Bank 0 und 1 hin- und herzuschalten, brauchen wir nur das unterste Bit. Dieses lesen wir von $dd00 und schalten es mit eor %00000001 bei jedem Durchlauf um. Da wir auch scrollen müssen, verfahren wir dort genau so! Nach dem Systemstart steht die links / rechts Scrollposition immer auf %111, also ganz links! Wir lesen den Inhalt von $d016 und müssen nur das unterste Bit immer zwischen 1 und 0 umschalten.
Zum Schluß springen wir wieder an den Schleifenanfang.
Jetzt müssen wir noch auf F5 in unserer checkKeyboard-Funktion reagieren. Nehmt dazu die drei kleinen, gelb markierten, Änderungen vor:
!zone checkKeyboard checkKeyboard sei ;Interrupts sperren! ;Sonst funkt man uns evtl. dazwischen lda #%11111110 ;wir wollen PA0 maskieren sta $dc00 ;Wert ins Register CIA-1 Port A schreiben lda $dc01 ;hole Register-Inhalt vom CIA-1 Port B tax ;im X-Register merken and #%00010000 ;hier PB4 prüfen F1 bne .checkF3 ;wenn KEINE 0, weiter mit F3 ;sonst sind wir fertig lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000011 ;Bank-0 sta $dd00 ;für das 1. Bild wählen sta ZP_AUTO ;Automatik deaktivieren jmp .exit ;und raus .checkF3 txa ;hole Register-Inhalt vom CIA-1 Port B and #%00100000 ;hier PB5 prüfen F3 bne .checkF5 ;wenn KEINE 0, weiter mit F5 lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000010 ;Bank-1 sta $dd00 ;für das 2. Bild wählen sta ZP_AUTO ;Automatik deaktivieren jmp .exit ;und raus .checkF5 txa ;hole Register-Inhalt vom CIA-1 Port B and #%01000000 ;hier PB6 prüfen F5 bne .exit ;wenn KEINE 0, dann raus sta ZP_AUTO ;Automatik wieder aktivieren .exit cli ;Interrupts wieder freigeben rts ;zurück zum Aufrufer
Wir machen es uns hier ganz einfach! Der Akku hat schon immer einen passenden Wert, sodass wir diesen an den markierten Stellen nur noch ZP_AUTO schreiben müssen, damit die Automatik aktiviert bzw. deaktiviert wird.
Wenn ihr das Programm jetzt startet, stolpert ihr evtl. über zwei Probleme. Das erste fällt euch sicherlich direkt auf. Links entsteht eine unschöne weiße Line.
Das zweite kann auftreten, sobald ihr die Automatik mit F1 oder F3 unterbrecht und dann mit F5 fortsetzt. Dadurch kann unser Timing aus dem Tritt kommen. Ihr müsst dann evtl. wiederholt anhalten / fortfahren bis es wieder passt. Da diese Funktionen nur der Veranschaulichung dienen, kümmere ich mich nicht weiter darum. Ihr solltet aber zur Übung mal dafür sorgen, dass immer richtig angehalten und fortgestetzt wird.
Die störende Line muss aber unbedingt weg!
Die Linie entsteht durch unser Scrolling. Wie ihr durch die Linie seht, ist das Bild anscheinend viel kleiner, als der zur Verfügungstehende Ausgabebereich. Zur Kontrolle könnt ihr ja mal die Rahmenfarbe ändern:
Wir können also einfach, wie bei Scrolling – Laufschrift gesehen, die Bildschirmausgabe auf 38 Spalten reduzieren. Fügt dazu am Programmanfang, wo wir den Multi-Color-Modus aktivieren die markierte Zeile ein:
lda $D016 ;VIC-II Register 22 in den Akku ora #%00010000 ;Multi-Color über BIT-4 and #%11110111 ;auf 38 Spalten umstellen sta $D016 ;aktivieren
Jetzt könnt ihr das Programm wieder starten und die nervige Linie ist weg.
Erstellt ihr eigene Bilder und sollten diese bis zum Rand reichen, dann könnt ihr auch Sprites verwenden, um die Linie zu überdecken. Damit könnt ihr auf einen Pixel genau arbeiten und somit, bis auf eine vertikale Pixelzeile, den gesamten Bildschirm ausnutzen.
;*** VIC-II Speicher-Konstanten VICBANKNO = 0 ;Nr. (0 - 3) der 16KB Bank | Standard: 0 VICSCREENBLOCKNO = 1 ;Nr. (0 -15) des 1KB-Blocks für den Textbildschirm | Standard: 1 VICCHARSETBLOCKNO = 2 ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz | Standard: 2 VICBITMAPBBLOCKNO = 1 ;Nr. (0 - 1) des 8KB-Blocks für die BITMAP-Grafik | Standard: 0 VICBASEADR = VICBANKNO*16384 ;Startadresse der gewählten VIC-Bank | Standard: $0000 VICCHARSETADR = VICBASEADR+VICCHARSETBLOCKNO*2048 ;Adresse des Zeichensatzes | Standard: $1000 ($d000) VICSCREENRAM = VICBASEADR+VICSCREENBLOCKNO*1024 ;Adresse des Bildschirmspeichers VICSCREENRAM_2 = $4400 ;hier liegen die Farben für die 2. Bitmap VICBITMAPADR = VICBASEADR+VICBITMAPBBLOCKNO*8192 ;Adresse der BITMAP VICCOLORRAM = $d800 ZP_AUTO = $02 ;*** Startadresse *=$0801 ;** BASIC-Zeile: 2018 SYS 2062 !word main-2, 2018 !byte $9e !text " 2062" !byte $00,$00,$00 !zone main main ;Bitmap-Modus aktivieren lda $d011 ;VIC-II Register 17 in den Akku ora #%00100000 ;Bitmap-Modus sta $d011 ;aktivieren lda $d016 ;VIC-II Register 22 in den Akku ora #%00010000 ;Multi-Color über BIT-4 and #%11110111 ;auf 38 Spalten umstellen sta $d016 ;aktivieren ;*** Start des Bitmapspeichers festlegen lda $d018 ;VIC-II Register 24 in den Akku holen and #%11110111 ;Mit BIT-3 ora #VICBITMAPBBLOCKNO*8 ;den Beginn des Bitmap- sta $d018 ;festlegen jsr copyColor ;Farben kopieren lda #0 ;0 = automatisch umschalten sta ZP_AUTO .loop jsr waitRaster ;auf Rasterzeile warten jsr checkKeyboard ;Tastatur prüfen lda ZP_AUTO ;ist ZP_AUTO = 0? bne .loop ;falls nicht -> .loop lda #%00000001 ;Datenrichtung für BIT 0 des CIA-Port-A sta $dd02 ;zum Schreiben freigeben lda $dd00 eor #%00000001 ;VIC-Bank zwischen 0 und 1 umschalten sta $dd00 lda $d016 ;VIC-II Register 22 in den Akku eor #%00000001 ;Scrollposition links / rechts um sta $d016 ;einen Pixel umschalten jmp .loop ;endlos wiederholen !zone waitRaster waitRaster lda #255 ;gewünschte Rasterzeile .wait cmp $d012 ;falls wir schon in der beq .wait ;gewünschten Zeile sind -> warten .wait1 cmp $d012 ;jetzt warten, bis die gewünschte bne .wait1 ;Rasterzeile erreicht wurde rts ;zurück zum Aufrufer !zone checkKeyboard checkKeyboard sei ;Interrupts sperren! ;Sonst funkt man uns evtl. dazwischen lda #%11111110 ;wir wollen PA0 maskieren sta $dc00 ;Wert ins Register CIA-1 Port A schreiben lda $dc01 ;hole Register-Inhalt vom CIA-1 Port B tax ;im X-Register merken and #%00010000 ;hier PB4 prüfen F1 bne .checkF3 ;wenn KEINE 0, weiter mit F3 ;sonst sind wir fertig lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000011 ;Bank-0 sta $dd00 ;für das 1. Bild wählen sta ZP_AUTO ;Automatik deaktivieren jmp .exit ;und raus .checkF3 txa ;hole Register-Inhalt vom CIA-1 Port B and #%00100000 ;hier PB5 prüfen F3 bne .checkF5 ;wenn KEINE 0, weiter mit F5 lda #%00000011 ;Datenrichtung für BIT 0 & 1 des Port-A sta $dd02 ;zum Schreiben freigeben lda #%00000010 ;Bank-1 sta $dd00 ;für das 2. Bild wählen sta ZP_AUTO ;Automatik deaktivieren jmp .exit ;und raus .checkF5 txa ;hole Register-Inhalt vom CIA-1 Port B and #%01000000 ;hier PB6 prüfen F-5 bne .exit ;wenn KEINE 0, dann raus sta ZP_AUTO ;Automatik wieder aktivieren .exit cli ;Interrupts wieder freigeben rts ;zurück zum Aufrufer !zone copyColor copyColor lda #0 ;Rahmenfarbe schwarz sta $d020 lda #15 ;Hintergrundfarbe hellgrau sta $d021 ldx #0 ;Schleifenzähler initialisieren .loop lda color,X ;Farben ins Color-RAM kopieren sta VICCOLORRAM,X lda color+256,X sta VICCOLORRAM+256,X lda color+512,X sta VICCOLORRAM+512,X lda color+768,X sta VICCOLORRAM+768,X lda char,X ;Farben in den Bildschirmspeicher kopieren sta VICSCREENRAM,X lda char+256,X sta VICSCREENRAM+256,X lda char+512,X sta VICSCREENRAM+512,X lda char+768,X sta VICSCREENRAM+768,X dex ;Schleifenzähler verringern bne .loop ;die nächsten BYTES kopieren rts ;zurück zum Aufrufer ;Daten fürs Farb-RAM (wird nur 1x benötigt) color !bin "MCI_CR.bin" ;Farben der 1. Bitmap für den Bildschrimspeicher char !bin "MCI_SR_1.bin" *=$2000 ;1. Bitmap !bin "MCI_BM_1.bin" ;Farben für die 2. Bitmap *=VICSCREENRAM_2 !bin "MCI_SR_2.bin" *=$6000 ;2. Bitmap !bin "MCI_BM_2.bin"
Sobald ihr das Programm laufen lasst, sollte euer Bild ungefähr so aussehen:
Das Standbild ist selbstverständlich nur eine Annäherung an die C64 Ausgabe des MCI Bildes. Es flackert nicht, zeigt aber wie es ungefähr am C64 wirkt. Wenn ihr dieses Bild mit den beiden Einzelbildern vergleicht, dann seht ihr bestimmt, dass es viel detaillierter aussieht. Dies kommt durch die Überlagerung der beiden Bilder.
Hier noch ein Versuch als animiertes GIF. Dies wird dem aber auch nicht gerecht, die Wahrheit liegt irgendwo da draußen 😉 dazwischen und läßt sich wohl nur direkt am C64 finden.
Das Flackern bekommt ihr durch Programmänderungen leider nicht weg! Dies ist aber für sog. Interlace-Auflösungen typisch. Falls ihr einen Amiga habt / hattet kennt ihr das bestimmt, von den entsprechenden Bildschirmauflösungen. Beim Amiga hilft ein Flickerfixer, beim MCI-Modus am C64 muss man es einfach „ertragen“ 😉 .
Die MCI Bilder kommen aber auf alten Röhren sehr viel besser rüber, als auf den modernen LCD- / TFT- / LED-Bildschirmen. Durch die „alte“ Technik, ist das Bild fast ganz ruhig! Probiert es einfach selbst mal aus.
Wir (OK, ich war es) haben in diesem Beispiel aus Bequemlichkeit, eine Menge Platz für das MCI Bild verschwendet. Ihr könnt die Speicherbereiche natürlich auch besser positionieren und dann beim Umschalten neben der VIC-Bank auch noch die Speicheradressen ändern.
Gute Erklärung der Thematik.