Erstellt: 9. Februar 2014 (zuletzt geändert: 19. April 2022)

VIC-II: Eigener Zeichensatz

Den Zeichensatz verändern

C64 Studio, AMCE & TASM

Eine herausragende Eigenschaft des C64 ist es, dass ihr sehr einfach eure eigenen Zeichensätze verwenden könnt. Was sich auf den ersten Blick relativ unspektakulär anhört, entpuppt sich als eine der wichtigsten Funktionen für Spiele und Demos.

Als erstes solltet ihr euch mit dem Speichermanagment des VIC unter VIC-II: Speicherbereiche festlegen vertraut machen, falls ihr es noch nicht getan habt.
Auch ein Blick auf die Beiträge Char-ROM und evtl. PETSCII, sollte zur Vorbereitung gehören.

Zwischen den beiden Standardzeichensätzen umschalten

Wir betrachten hier den Standardzeichensatz-Modus, der ist allen, die schon mal einen C64 eingeschaltet haben, bereits begegnet. Direkt nach dem Einschalten bietet der C64 zwei verschiedene Zeichensätze, die sich im ROM befinden:

  1. Zeichensatz: Großbuchstaben und viele grafische Symbole, dieser wird automatisch verwendet
  2. Zeichensatz: Groß- und Kleinbuchstaben, dafür weniger Symbole! Dieser muss extra aktiviert werden.

Zwischen den beiden Zeichensätzen könnt ihr mit folgenden Aktionen wechseln:

  • Tasten: Gleichzeitig die Tasten C= und Shift drücken, um zwischen den Layouts zu wechseln.
  • BASIC: PRINT CHR$(141) für den 1. Zeichensatz (Großbuchstaben und viele Symbole) bzw. PRINT CHR$(142) für den 2. Zeichensatz (Groß- und Kleinbuchstaben)
  • Assembler: Wer bei VIC-II: Speicherbereiche festlegen aufgepasst hat, der wird bereits wissen, wie man unter Assembler zwischen den beiden Zeichensätzen umschaltet. Im Register 24 $d018 des VIC (s. VIC-II: Die Register) wird der Beginn des Zeichensatzes festgelegt. Daher müssen wir nun einfach den Beginn des gewünschten Zeichensatzes dort hineinschreiben.
    Da hier der Zustand nach dem Einschalten vorausgesetzt wird, können wir einfach
    lda #$15 für den ersten bzw. lda #$17 für den zweiten Zeichensatz in den Akku laden und dies dann mit sta $d018 ins Register schreiben.
    Dies könnten wir natürlich auch unter BASIC mit POKE 53272,21 und POKE 53272,23 erreichen.

Vorbereitungen

Nun können wir schon zwischen zwei Zeichensätzen umschalten, aber wir wollen ja einen eigenen verwenden. Dazu gibt es nun zwei Möglichkeiten, wir können komplett einen eigenen Zeichensatz entwerfen oder wir kopieren den vorhandenen und verändern ihn nach unseren Wünschen. Da wir im Laufe des Tutorials Ein C64 Spiel in Assembler programmieren ab Level 3 – Die Fahrt zur Basis einen eigenen Zeichensatz entwickeln, verwenden wir hier das Kopieren.

Als Erstes sollten wir einen freien Speicherbereich suchen, wo wir unseren Zeichensatz ablegen. Wir lassen den VIC weiterhin auf die erste Bank zugreifen, so wie es nach dem Einschalten standard ist.
Als Speicherort für unseren Zeichensatz scheidet die Zero-Page natürlich aus. Auch die Adressen von $1000 bis $1fff sind tabu, wir befinden uns schließlich in der VIC-Bank 0! Dort greift der VIC (wie auch in Bank 2) immer direkt auf das ROM zu (s. VIC-II: Speicherbereiche festlegen) und würde somit nie unseren kopierten Zeichsatz lesen.
Für unseren Test schlage ich daher das Ende des ersten 16KB-Blocks vor. Lasst uns den Zeichensatz in den letzten 2KB-Block (Nr. 7), also von $3800-$3fff, legen. Dort landen wir zwar im BASIC-Speicher, aber das ist für unseren Test nicht schlimm!

Zeichenspeicher festlegen

;*** 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       = 7                             ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz         | Standard: 2
VICBITMAPBBLOCKNO       = 0                             ;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           = VICCHARSETBLOCKNO*2048        ;Adresse des Zeichensatzes                              | Standard: $1000 ($d000)
VICCHARSETADR           = VICCHARSETADR+VICBASEADR

;*** Startadresse 
*=$0801
;** BASIC-Zeile: 2018 SYS 2062
 !word main-2, 2018 
 !byte $9e
 !text " 2062"
 !byte $00,$00,$00

main
;*** Start des Zeichensatzes festlegen
 lda #VICSCREENBLOCKNO*16+VICCHARSETBLOCKNO*2
 sta $d018                          ;Adresse für Bildschirm und Zeichensatz festlegen
 rts                                ;zurück zum BASIC

Wir legen hier die Bank-/Block-Nr. fest und berechnen daraus die benötigten Adressen. Auf die Ausführungsgeschwindigkeit hat dies natürlich keinen Einfluss, da diese Berechnungen der Assembler bei der Programmerstellung vornimmt.
Das Programm macht erstmal nichts weiter, als dem VIC-II mitzuteilen, dass der Zeichensatz jetzt ab der Speicherstelle $3800 zufinden ist.

Das erste Ergebnis sieht auch dementsprechend unbefriedigend aus:

Sieht fast wie ein Morsecode aus.
Sieht fast wie ein Morsecode aus.

Dass der C64 nicht abgestürzt ist, erkennt ihr z. B. daran, dass ihr immer noch blind BASIC-Befehle (wie POKE 53280,0) benutzen könnt.

Den Zeichensatz kopieren

Jetzt ist es an der Zeit, dass wir die Zeichen aus dem ROM, an unsere gewählte Adresse kopieren. Das erste Hindernis ist die Frage, wie sind die Zeichen überhaupt gespeichert?

Da wir uns im Standardzeichensatz-Modus (s. o.) befinden, hat jedes Zeichen eine Breite von 8 Pixeln und ist dabei 8 Zeilen hoch.

So sieht das Zeichen 'A' im Speicher aus.
So sieht das Zeichen ‚A‘ im Speicher aus.

Somit kommen wir also auf 8 Bytes je Zeichen. Da ein kompletter Zeichsatz aus 256 Zeichen besteht, benötigt dieser also 256 * 8 Bytes = 2048 Bytes = 2KB. Das erklärt dann wieder, warum der Speicher für den Zeichsatz in 2KB-Schritten gewählt werden kann. Im Speicher (ROM) findet ihr alle Zeilen eines Zeichens direkt hintereinander, also die orangen Zeilen 0 – 7 aus dem obigen Bild.

Als zweites fragt sich der eine oder andere, wie wir nun überhaupt an die Zeichen kommen? Wie bereits geschrieben, finden wir an der Adresse $1000 keines Wegs die Zeichen, nur der VIC sieht diese in der VIC-Bank-0 an der Adresse. Tatsächlich befindet sich das Char-ROM an der Speicherstelle $d000.

Moment mal, dort befinden sich doch auch die VIC-Register!?!

Hier haben wir die, in Kleine Hardwarekunde beschriebene, dreifache Benutzung eines Speicherbereichs. Wir haben dort RAM, die Register vom VIC-II (und anderen Bausteinen) sprich den E/A-Bereich, sowie das Char-ROM. Um nun auf das Char-ROM zugreifen zu können, müssen wir den E/A-Bereich abschalten. Diese Möglichkeit ist der Hauptunterschied zwischen dem 6502 und dem 6510 aus dem C64. Die ersten beiden Speicherstellen (also die Adressen $0000 und $0001 sind für Sonderfunktionen reserviert, für weitere Infos, nochmal der Hinweis auf die Kleine Hardwarekunde).

Wir müssen also das Bit-2 auf 0 setzen, damit der E/A-Bereich verschwindet. Das sollten wir tunlichst nur machen, wenn keine Interrupts möglich sind, sonst ist ein Absturz nahezu unvermeidlich. Nach dem Abschalten können wir dann die 2KB, für einen Zeichensatz, aus dem Char-ROM einfach kopieren. Zum Schluß den E/A-Bereich wieder einblenden und die IRQs freigeben, schon haben wir unseren eigenen Zeichensatz. Laßt uns dies nun in unser obiges Programm einbauen.

Ändert dazu erstmal main wie hier gelb hervorgehoben:

main
;*** Start des Zeichensatzes festlegen
 lda #VICSCREENBLOCKNO*16+VICCHARSETBLOCKNO*2
 sta $d018                          ;Adresse für Bildschirm und Zeichensatz festlegen
 
 sei                                ;IRQs sperren

 lda $01                            ;ROM-'Konfig' in den Akku
 pha                                ;auf dem Stack merken
 and #%11111011                     ;BIT-2 (E/A-Bereich) ausblenden
 sta $01                            ;und zurückschreiben

 jsr copyCharROM                    ;Zeichensatz kopieren

 pla                                ;ROM-Einstellung vom Stack holen
 sta $01                            ;wiederherstellen

 cli                                ;Interrupts freigeben

 rts                                ;zurück zum BASIC

Hier sperren wir zu Beginn, wie angekündigt, die Interrupts und blenden dann den E/A-Bereich aus. Anschließend können wir zur Routine copyCharROM springen und den Zeichensatz kopieren. Zum Schluß stellen wir die Speicheradresse $01 auf ihren ursprünglichen Wert zurück, damit der E/A-Bereich wieder sichtbar wird und aktivieren natürlich auch noch die IRQs.

Jetzt kümmern wir uns um die Kopierfunktion.

copyCharROM
 lda #<CHARROMADR                   ;Quelle (CharROM) auf die Zero-Page
 sta ZP_HELPADR1
 lda #>CHARROMADR
 sta ZP_HELPADR1+1

 lda #<VICCHARSETADR                ;Ziel (RAM-Adr. Zeichensatz) in die Zero-Page
 sta ZP_HELPADR2
 lda #>VICCHARSETADR
 sta ZP_HELPADR2+1

 ldx #$08                           ;wir wollen 8*256 = 2KB kopieren
loopPage
 ldy #$00                           ;Schleifenzähler für je 256 Bytes
loopChar
 lda (ZP_HELPADR1),Y                ;Zeichenzeile (Byte) aus dem CharROM holen
 sta (ZP_HELPADR2),Y                ;und in unseren gewählten Speicherbereich kopieren
 dey                                ;Blockzähler (256 Bytes) verringern
 bne loopChar                       ;solangen ungleich 0 nach loopChar springen
 inc ZP_HELPADR1+1                  ;Sonst das MSB der Adressen auf der Zeropage
 inc ZP_HELPADR2+1                  ;um eine 'Seite' (256 Bytes) erhöhen
 dex                                ;'Seiten'-Zähler (acht Seiten zu 256 Bytes) verringern
 bne loopPage                       ;solange ungleich 0 nach loopPage springen

 rts                                ;zurück zum Aufrufer

Wir benutzen hier die Zero-Page, um die Adressen für das Char-ROM und den von uns gewählten Speicherbereich zuspeichern. Dann verwenden wir zwei Schleifen, um die 2KB zu kopieren. Die innere Schleife kopiert immer 256 Bytes, mit der Y-nach-Indizierten-Adressierung. Die äußere sorgt dafür, dass das ganze achtmal geschieht und erhöht bei jedem Durchlauf das MSB der Adressen auf der Zero-Page um eins, damit der nächste 256-Byte-Block kopiert werden kann.

Vergesst abschließen nicht, die drei neuen Konstanten für copyCharROM festzulegen:

CHARROMADR              = $d000
ZP_HELPADR1             = $fb
ZP_HELPADR2             = $fd

Ein Start und mit offenen Mündern blicken wir aufs schier unfassbare Ergebnis:

Na toll, was soll der Quatsch?
Na toll, was soll der Quatsch?

:mrgreen: OK, das Ergebnis ist nun nicht spektakulär, eigentlich eher enttäuschend.

Aber der Zeichensatz gehört jetzt uns!

Das können wir nun ganz einfach gegenprüfen, gebt nach dem Programmstart direkt POKE 14336+(8*32),255 ein und bestätigt die Eingabe mit RETURN.

Hier haben wir die erste „Zeile“ vom Leerzeichen geändert.
Hier haben wir die erste „Zeile“ vom Leerzeichen geändert.

Wir haben hier die erste Zeile des Leerzeichens geändert. Auf die Funktionsweise haben Änderungen des Zeichensatzes übrigens keine Auswirkung, für den C64 bleibt der Screencode 32 das Leerzeichen, egal ob es leer ist oder wie hier als Linie dargestellt wird.

Nun könnt ihr also euren eigenen Zeichensatz entwerfen, indem ihr die Bytes für euer Zeichen an die entsprechenden Speicherstellen schreibt.

Laßt uns abschließend noch eine kleine Routine entwickeln, die ein beliebiges Zeichen ersetzt. Fügt dazu hinter das cli, am Ende von main, die beiden folgenden Zeilen ein:

 ldx #' '                           ;SPACE (Leerzeichen) ersetzen
 jsr replaceChar

Über das X-Register wählen wir das Zeichen aus, dass wir mit unserem ersetzen möchten, dann springen wir nach replaceChar um das Zeichen zu kopieren.

Nun fehlt natürlich noch die Funktion zum Kopieren eines Zeichens.

;*** ersetzt den Screencode im X-Register mit dem Zeichen von testchar
replacechar
 txa                            ;Screencode * 8
 and #%00011111
 asl
 asl
 asl
 clc
 adc #<VICCHARSETADR            ;LSB fürs Ziel (RAM-Adr. Zeichensatz) in die Zero-Page
 sta ZP_HELPADR2

 txa                            ;Screencode in den Akku
 lsr                            ;die oberen drei BYTEs für die Ermittlung
 lsr                            ;der Page verwenden
 lsr
 lsr
 lsr
 clc
 adc #>VICCHARSETADR            ;einfach aufs MSB der Ziel-Adresse addieren
 sta ZP_HELPADR2+1

 ldy #$07
@loop
 lda testChar,Y
 sta (ZP_HELPADR2),Y
 dey
 bpl @loop

 rts                            ;zurück zum Aufrufer

Um den korrekten Beginn, des zu ersetzenden Zeichens im Speicher zu finden, müssen wir dessen Position (Adresse) berechnen. Dazu kopieren wir das X-Register zunächst in den Akku und blenden die oberen drei Bits aus. Auf einer 256-Byte-Page haben 32 Zeichen platz (32 * 8 Byte je Zeichen). Daher behalten wir die unteren fünf Bits und multiplizieren diese dann mit 8 (dreimal nach links verschieben). Jetzt addieren wir das LSB unserer Zeichensatzadresse dazu und haben somit den korrekten Beginn des Zeichens innerhalb einer Page. Dann müssen wir noch die richtige Page ermitteln. Also den Screencode nochmal vom X-Register in den Akku kopiert, fünfmal nach rechts verschoben und einfach das MSB der Zeichensatzadresse addieren. Schon haben wir die dazugehörige Page. Beide Werte haben wir uns wieder auf der Zero-Page gemerkt. Da wir acht Bytes (Zeile 0 bis 7 vgl. Bild) kopieren müssen, füllen wir das Y-Register mit 7. Dann holen wir das erste Byte unseres Entwurfes von der Adresse testChar und kopieren es an die dazugehörige Adresse in unseren Zeichensatz. Abschließend noch Y verringern und das ganze solange wiederholen, bis Y negativ wird. Schon sind wir fertig und die Funktion wird verlassen.

Unser neues Zeichen ‚entwerfen‘ wir beim Label testChar:

testChar
 !byte %00100000
 !byte %00100000
 !byte %00100000
 !byte %11000000
 !byte %00010100
 !byte %00011000
 !byte %00010100
 !byte %00000000

Hier könnt ihr einfach durchs Setzen bzw. Löschen der einzelnen Bits, euer Zeichen entwerfen.

Startet ihr das Programm nun, dann wird statt des Leerzeichens ein dezenter Hinweis auf den Verfasser dieser Zeilen (also mich 😉 ) erscheinen.

Das Leerzeichen wurde durch meine Initialen ersetzt.
Das Leerzeichen wurde durch meine Initialen ersetzt.

Auf diese Weise (nur durch !byte-Anweisungen) einen kompletten Zeichensatz zu erstellen ist allerdings doch sehr mühsam 😉 . Man greift daher auf Zeichensatz-Editoren zurück, um den Zeichensatz bequem zu erstellen. Zum Glück bietet das C64 Studio einen solchen Editor an (der kommt im Spiele-Tutorial zum Einsatz). Im Prinzip müsst ihr nur den von euch erstellten Zeichensatz in den Source einbinden und ggf. an die richtige Stelle kopieren.
Natürlich gibt es auch externe Tools oder entsprechende Programme, die ihr direkt auf dem C64 verwenden könnt, die euch das Erstellen von eigenen Zeichensätzen erleichtern.

;*** 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       = 7                             ;Nr. (0 - 7) des 2KB-Blocks für den Zeichensatz         | Standard: 2
VICBITMAPBBLOCKNO       = 0                             ;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           = VICCHARSETBLOCKNO*2048        ;Adresse des Zeichensatzes                              | Standard: $1000 ($d000)
VICCHARSETADR           = VICCHARSETADR+VICBASEADR

CHARROMADR              = $d000
ZP_HELPADR1             = $fb
ZP_HELPADR2             = $fd

;*** Startadresse 
*=$0801
;** BASIC-Zeile: 2018 SYS 2062
 !word main-2, 2018 
 !byte $9e
 !text " 2062"
 !byte $00,$00,$00

main
;*** Start des Zeichensatzes festlegen
 lda #VICSCREENBLOCKNO*16+VICCHARSETBLOCKNO*2
 sta $d018                          ;Adresse für Bildschirm und Zeichensatz festlegen
 
 sei                                ;IRQs sperren

 lda $01                            ;ROM-'Konfig' in den Akku
 pha                                ;auf dem Stack merken
 and #%11111011                     ;BIT-2 (E/A-Bereich) ausblenden
 sta $01                            ;und zurückschreiben

 jsr copyCharROM                    ;Zeichensatz kopieren

 pla                                ;ROM-Einstellung vom Stack holen
 sta $01                            ;wiederherstellen

 cli                                ;Interrupts freigeben

 ldx #' '                           ;SPACE (Leerzeichen) ersetzen
 jsr replaceChar

 rts                                ;zurück zum BASIC


copyCharROM
 lda #<CHARROMADR                   ;Quelle (CharROM) auf die Zero-Page
 sta ZP_HELPADR1
 lda #>CHARROMADR
 sta ZP_HELPADR1+1

 lda #<VICCHARSETADR                ;Ziel (RAM-Adr. Zeichensatz) in die Zero-Page
 sta ZP_HELPADR2
 lda #>VICCHARSETADR
 sta ZP_HELPADR2+1

 ldx #$08                           ;wir wollen 8*256 = 2KB kopieren
loopPage
 ldy #$00                           ;Schleifenzähler für je 256 Bytes
loopChar
 lda (ZP_HELPADR1),Y                ;Zeichenzeile (Byte) aus dem CharROM holen
 sta (ZP_HELPADR2),Y                ;und in unseren gewählten Speicherbereich kopieren
 dey                                ;Blockzähler (256 Bytes) verringern
 bne loopChar                       ;solangen ungleich 0 nach loopChar springen
 inc ZP_HELPADR1+1                  ;Sonst das MSB der Adressen auf der Zeropage
 inc ZP_HELPADR2+1                  ;um eine 'Seite' (256 Bytes) erhöhen
 dex                                ;'Seiten'-Zähler (acht Seiten zu 256 Bytes) verringern
 bne loopPage                       ;solange ungleich 0 nach loopPage springen

 rts                                ;zurück zum Aufrufer



;*** ersetzt den Screencode im X-Register mit dem Zeichen von testchar
replaceChar
 txa                                ;Screencode * 8
 and #%00011111
 asl
 asl
 asl
 clc
 adc #<VICCHARSETADR                ;LSB fürs Ziel (RAM-Adr. Zeichensatz) in die Zero-Page
 sta ZP_HELPADR2

 txa                                ;Screencode in den Akku
 lsr                                ;die oberen drei BYTEs für die Ermittlung
 lsr                                ;der Page verwenden
 lsr
 lsr
 lsr
 clc
 adc #>VICCHARSETADR                ;einfach aufs MSB der Ziel-Adresse addieren
 sta ZP_HELPADR2+1

 ldy #$07
loopRow
 lda testChar,Y
 sta (ZP_HELPADR2),Y
 dey
 bpl loopRow

 rts                                ;zurück zum Aufrufer


testChar
 !byte %00100000
 !byte %00100000
 !byte %00100000
 !byte %11000000
 !byte %00010100
 !byte %00011000
 !byte %00010100
 !byte %00000000

OK, unser Beispiel ist nicht wirklich der Bringer, wer jetzt aber immer noch daran zweifelt, dass das Ändern des Zeichensatzes eine der wichtigsten Funktionen für Spiele und Demos ist, den überzeugen die folgenden Bilder hoffentlich. Dort seht ihr die Zeichensätze für den jeweils ersten Level von Uridium und Wizball in einem Editor und wie der gesamte Level dann aussieht. Diese sind zwar schon mehrfarbig, schaut euch also ggf. ‚VIC-II: Grafikmodes – Text‚ an.

Uridium

Den ersten Level von Uridium kennt doch bestimmt jeder (falls nicht unbedingt nachholen!).

Der 1. Level im Spiel.
Der 1. Level im Spiel.

Der Level ist sehr groß, wir sehen hier ja nur einen kleinen Ausschnitt. Seine gesamten Ausmaße erstrecken sich über mehrere Bildschirme…

Der erste Level von Uridium.
Der komplette erste Level von Uridium (zum Vergrößern einfach anklicken).

Wer nun glaubt, dies sei eine komplette Grafik im C64, der irrt!
Alles wird durch einen geänderten Zeichsatz zusammengebaut. Im Editor sehen die Zeichen z. B. so aus:

Die benötigten Zeichen.
Die benötigten Zeichen.

Aus den einzelnen Zeichen wird dann das komplette Raumschiff für den Level, die sog. Map, erstellt.

Das Raumschiff zusammenbauen.
Das Raumschiff zusammenbauen.

Wizball

Als ersten müssen auch hier die Zeichen definiert werden. Bei diesem Wizball Beispiel, werden außerdem sog. Tiles verwendet. Ein Tile besteht dabei aus mehreren Zeichen und bildet somit einen größeren Baustein. Vergleicht das nochmal mit Uridium, dort war ein Tile genau ein Zeichen groß (man kann auch sagen, es wurden keine Tiles verwendet). Hier bei Wizball besteht ein Tile aus 5×5 Zeichen.

Zeichen erstellen und zu Tiles zusammenfassen.
Zeichen erstellen und zu Tiles zusammenfassen.

Nun läßt sich der Level etwas bequemer erstellen, da man größere Bausteine hat. Allerdings ist man dann auch nicht mehr so flexibel. Alles hat halt seine zwei Seiten.

Den Level mit den Tiles erstellen.
Den Level mit den Tiles erstellen.

Das Ergebnis hat dann wieder das bekannte Aussehen:

...und so sieht dann der erste Level von Wizball aus.
Der erste Level von Wizball (zum Vergrößern anklicken).

Im Spiel finden wir die obige Grafik gleich im ersten Level wieder. Wir sehen hier natürlich auch nur einen kleinen Ausschnitt und die Farben werden vom Programm anders gesetzt. Immerhin geht es im Spiel darum die triste Welt wieder einzufärben, bunt wird es daher erst später. Auch hier gilt, wer es nicht kennt unbedingt anspielen.

Wizball in Aktion.
Wizball in Aktion.

Das wars erstmal zu den eigenen Zeichensätzen.
Wie man einen Multi-Color-Zeichensatz anzeigt, könnt ihr bei VIC-II: Grafikmodes – Text nachlesen. Dort gibt es ein einfaches Uridium-Beispiel, in dem der erste Level von uns verwendet wird.

Experimentiert nun am besten etwas mit den Zeichensätzen. Sie bieten eine unglaubliche Vielfalt an Möglichkeiten. Eine schöne Übung ist es z. B. den gesamten Bildschirm einmal auf den Kopf zu stellen.

1. Schritt den Zeichensatz auf den Kopf stellen.
1. Schritt den Zeichensatz auf den Kopf stellen.

Hier könnt ihr jetzt auch schön überprüfen, dass das Aussehen der Zeichen wirklich keinen Einfluss auf die Funktionsweise des BASICs hat. Ihr könnt mit dem Kopfüber-Zeichensatz ganz normal Programme schreiben und Befehle ausführen, probiert es selbst einmal…

2. Schritt die Zeilen umkopieren
2. Schritt die Zeilen umkopieren

Durch einfaches Ändern der Adresse des Zeichensatzes könnt ihr später schöne Effekte erzielen. Auch nicht zu verachten ist, dass sich durch Ändern eines Zeichens (sind ja nur 8 Bytes), sofort alle Zeichen auf dem Bildschirm anpassen, aber das habt ihr ja eben schon gesehen.

Jetzt viel Spaß beim erschaffen eurer eigenen Zeichensätze,
Jörn


Schrott!!Naja...Geht so...Ganz gut...SUPER! (6 Bewertungen | Ø 5,00 von 5 | 100,00%)

Loading...


ZurückWeiter

15 Gedanken zu „VIC-II: Eigener Zeichensatz“

  1. Hallo Jörn

    Bin wieder einmal dabei, Deinen Quellcode Zeile für Zeile zu kopieren (und versuchen zu verstehen). Beim ersten Abschnitt bei der Änderung des Zeichensatzes hat sich ein kleiner Schreibfehler eingeschlichen:
    jsr copyCharrROM ;Zeichensatz kopieren
    Hier muss das mittlere r wohl das Zeitliche segnen 😉

    Gruss, Markus

  2. Hallo Jörn

    Bei den BASIC-Befehlen haben sich 2 kleine Fehler eingeschlichen. Beim ersten Befehl muss es CHR$(142) heissen für die Umschaltung und beim zweiten Befehl ging das R vergessen.

    Sost vielen Dank, auch wenn ich das mit dem Umschalten von E/A und RAM zwar theoretisch verstehe, doch praktisch immer noch einen Knopf habe, was nun in welche Richtung gelesen und geschrieben wird 😉

    Gruss aus der Schweiz, Markus

  3. Hallo,
    ich weiß nicht, ob ich das überlesen habe, aber bedeutet das, dass man den RAM-Bereich von $D000 bis $DFFF nie auslesen kann? Wenn man durch das Deaktivieren von E/A nur E/A durch ROM ersetzen kann, dann kann man ja das RAM darunter nur beschreiben, oder gibt es fürs Lesen irgendeine mir nicht bekannte Möglichkeit?
    Gruß
    Julian

    1. Hallo Julian,

      das 2. Bit steuert eigentlich nur, ob E/A oder Zeichen-ROM sichtbar ist.
      Sobald die unteren beiden Bits (0 & 1) auf 0 gesetzt werden, ist direkt das RAM sichtbar.

      Da ist die Tabelle unter „Kleine Hardwarekunde“ leider irreführend, da dort 0 = RAM beim 2. Bit steht.
      Das sollte ich wohl mal überarbeiten.

      Gruß,
      Jörn

  4. Hallo Zusammen,

    ich verwende den Vice C64.
    Wie kann ich den Vice C64 so konfigurieren, dass mich mit deutschem Zeichensatz schreiben kann?

    Viele Grüße

    Robert

  5. Hallo Jörn,

    beim Versuch die Speicherbank zu wechseln ist mir aufgefallen, dass das Beispielprogramm noch unvollständig ist (weil, der Speicherbankwechsel nicht vorgesehen ist).

    Nachdem ich diese Hürde genommen hatte bin ich in die gleichen Probleme wie damals Carsten gelaufen.

    Hat eine ganze Weile gedauert bis ich eine Lösung gefunden habe.
    Folgender Code zwischen main & “Start des Zeichensatzes festlegen” funktioniert einigermaßen:
    ;*** 16KB-Bank wählen
    lda #%00000011 ;Datenrichtung für Bit 0 & 1 des Port-A (klappt auch ohne diese Zeile)
    sta $dd02 ;zum Schreiben freigeben (klappt auch ohne diese Zeile)

    lda #VICBANKNO
    cmp #3 ;Bank-3
    bne *+7
    lda #%00000000
    jmp bank
    cmp #2 ;Bank-2
    bne *+7
    lda #%00000001
    jmp bank
    cmp #1 ;Bank-1
    bne *+7
    lda #%00000010
    jmp bank
    lda #%00000011 ;Bank-0
    bank
    sta $dd00 ;Bank wegschreiben

    lda #>(VICBASEADR+(1024*VICSCREENBLOCKNO))
    sta $0288 ;MSB vom BS in Reg. $0288

    Wahrscheinlich reicht der Code nich an Deine Qualitätsvorstellungen heran aber falls hier nochmal jemand auf das Problem trifft….!

    Super Website übrigens. Ich habe eine halbes Regal voller Bücher zu Assembler aber nutze fast nur noch Deine HP wenn ich auf Probleme stoße.

    VG und weiter so!!

  6. Hallo Jörn,

    ich sauge gerade alle Informationen deiner tollen Artikel auf. Vielen Dank dafür!!!
    Ein Fehlerchen ist mir aufgefallen:
    Beim Codeschnipsel nach folgendem Text “Vergesst abschließen nicht, die drei neuen Konstanten für copyCharROM festzulegen:” ist “ZP_HELPADR2 = $fb” gesetzt, also auf denselben Wert wie ZP_HELPADR1.
    Weiter unten im vollständigen Code ist der korrekte Wert $fd gesetzt.
    Also nur ne Kleinigkeit, aber hatte mich beim ersten Lesen zunächst verwirrt 🙂

    Gruß,
    Sebastian

  7. Hallo Jörn,

    vielen Dank für das beste C64-Tutorial im Internet!

    Ich verstehe eigentlich alles bisher (dachte ich zumindest;), aber wenn ich bei VICSCREENBLOCKNO etwas anderes als 1 eintrage (also zB 4, damit der BS bei $1000/$D000 liegt), gibt es Zeichensalat, obwohl ich bspw. den zeichensatz-block frei verschieben kann (zB auf 4, also $2000/$E000). Warum ist das bloß so?

    Vielen Dank und Grüße!

    Carsten

    1. Hi Carsten,
      VICSCREENBLOCKNO ist der Bildschirmspeicher. Wenn du den verschiebst, zeigt er erstmal auf einen nicht initialisierten Speicherbereich und du siehst zufällige Zeichen. Lösch den Bereich mal und gib dort einen Text aus.
      1. Hi Jörn,

        vielen Dank für die schnelle Antwort!

        >>Wenn du den verschiebst, zeigt er erstmal auf einen nicht initialisierten Speicherbereich und du siehst zufällige Zeichen.

        ja, da steht erstmal Müll drinnen, aber auch wenn ich …

        >>Lösch den Bereich mal und gib dort einen Text aus.

        .. den Bereich lösche und/oder Zeichen reinschreibe, ändert sich überhaupt nichts! Wenn ich Dein Listing (“Hier nochmal das komplette Listing…”) 1:1 in CBM prg Studio 3.3 reinkopiere, ist alles OK. Wenn ich dann in der fünften Zeile die VICSCREENBLOCKNO auf 4 statt auf 1 setze (und damit den BS auf $1000 aus VIC-Sicht und auf $D000 aus CPU-Sicht) setze, ist weder Dein geänderter Zeichensatz noch sichtbar, noch kann man den Bildschirminhalt noch irgendwie verändern (also händisch auf der Tastatut rumtippen oder Werte nach $D000 sta’en). Wenn ich blind die Rahmenfarbe POKE’ , klappt das, d.h. kein Absturz oder so). Hat das evtl was mit der Überlagerung des E/A-Bereichs zu tun (der neue BS liegt ja dann bei $D000)? Aber auch das Ausgeblendet-Lassen des E/A-Bereichs ändert nichts….

        Viele Grüße!

        Carsten

        1. Hallo Carsten,
          ich ändere ja nur das Leerzeichen. Es kann sein, dass du nach VICSCREENBLOCKNO = 4 kein Leerzeichen auf dem BS hast (auch wenn es evtl. so aussieht). Such dir mal ein anderes Zeichen aus, am besten eine Zahl, das auf dem Bildschirm zu sehen ist. Ändere dann in der Zeile ldx #' ' ;SPACE (Leerzeichen) ersetzen das ‘ ‘ z. B. durch ‘0’, wenn du vorher eine 0 gesehen hast. Jetzt sollte sich eine Änderung zeigen.

          Über die Tastatur kannst du keine sichtbaren Änderungen vornehmen, da das BASIC noch davon ausgeht, dass der Bildschirm bei $0400 liegt. Für das System musst du das Highbyte der Bildschirmadresse nach $0288 schreiben.

          Für den Irrtum bei den letzten beiden Punkten, bin ich verantwortlich!
          Im Source steht zwar VICBANKNO = 3 ;Nr. (0 - 3) der 16KB Bank | Standard: 3, es ist aber eigentlich Bank-0 (die wird aber mit %11 = 3 in $DD00 aktiviert!).
          Du bist hier also in Bank-0 ($0000$3FFF)! Daher liegt der BS in deinem Beispiel auch für die CPU bei $1000 und dieser Bereich ist ungünstig, da der VIC in Bank-0 dort immer auf den Zeichensatz im ROM zugreift!

          Sorry, das muss ich in den nächsten Tagen unbedingt nochmal überarbeiten!!


          EDIT: Ich habe VICBANKNO im Source mal etwas geändert, es wird jetzt wirklich die Bank-Nr. genommen und ich habe stattdessen die anderen Berechnungen angepasst.

          1. Danke!!! Ja, jetzt schreibe ich auch in den richtigen Bereich und die Zeichen tauchen auf! Und das Setzen der für den VIC sichtbaren Bank mit
            $DD00 hatte ich auch vergessen;)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Protected by WP Anti Spam