VIC-II: Eigener Zeichensatz

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

CBM prg StudioDen Zeichensatz verändern

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.

 

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 durch folgende ‚Aktionen‚ wechseln:

  • Tasten:
    Gleichzeitig die Tasten  C=  und  SHIFT drücken, um zwischen den Layouts zu wechseln.
     
  • BASIC:
    PRINT CHR$(142) für den 1. Zeichensatz (Großbuchstaben und viele Symbole)
    PRINT CHR$(14) 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.

 

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

Wir legen hier die Bank-/Block-Nr. fest und berechnen daraus die benötigten Adressen. Da das CBM prg Studio nur einen Operator je Zeile erlaubt, müssen wir den Umweg über mehrere Berechnungen gehen und teilsweise auf DUMMY-Konstanten zurückgreifen. 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 wie ein Morsecode aus
Sieht wie ein Morsecode aus

Dass der C64 nicht abgestürzt ist, erkennt ihr z. B. daran, dass ihr immer noch ‚blind‚ BASIC-Befehle (wie z.B. 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 dass nun in unser obiges Programm einbauen.

Ändert dazu erstmal main wie hier gelb hervorgehoben:

Hier sperren wir zu Beginn, wie angekündigt, die Interrupts und blenden dann den E/A-Bereich aus. Dann 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.

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:

 

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>.

Erste Zeile vom Leerzeichen geändert.
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:

Ü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.

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:

Hier könnt ihr einfach durch 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.

CharSet_05 

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 bieten sowohl das CBM prg Studio, als auch das C64 Studio einen solchen Editor an (die kommen 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.


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 ggf. ‚VIC-II: Grafikmodes – Text‚ an.

 

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

Der 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 dass habt ihr ja eben schon gesehen.

 

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

 


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

Loading...


 

<<< zurück | weiter >>>

 

weitersagen ...
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedIn

5 Gedanken zu „VIC-II: Eigener Zeichensatz“

  1. 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