C64 Assembler Programmierung – Syntax
In diesem Teil der Serie geht es nun endlich um Assembler und dessen Syntax. In den vorangegangenen Teilen habe ich das CBM Studio und Visual Studio Code als IDEs für die Assembler Programmierung für den C64 vorgestellt.
C64 Assembler Programmierung – Syntax
Die Syntax von Assembler Programmen ist recht einfach. Ein Programm besteht aus einer Folge von Befehlen, ein Befehl pro Zeile. Je nach Befehl kann dieser noch Parameter wie Werte oder Adressen haben. Der Prozessor vom Commodore 64 versteht nur einige dutzend Befehle und hat ganze 64 Kilobyte an Speicher zur Verfügung. Die Aufgabe vom Entwickler ist nun diese Befehle zu lernen und zu beherrschen. Zusätzlich muss man lernen wo im Speicher was steht. Dazu gibt es detaillierte Beschreibungen der Speicherbelegung aus der man herauslesen kann, auf welchen Adressen Beispielsweise die Sprites liegen oder der Videomemory liegt.
Je nach verwendeten Editor können zusätzlich zu den definierten Befehlen noch Sprungmarken, Makros oder Pseudocodes verwendet werden, dazu aber in einem folgenden Artikel mehr.
Opcodes
Die vollständige Liste aller Opcodes vom Commodore 64 umfasst 256 mögliche Befehle. Wieso 256? Ein Opcode ist eine Nummer aus einem Byte (8-bit), beispielsweise $8D (STA). Wir erinnern uns: ein Byte kann im Hexadezimalsystem aus 2 Ziffern im Bereich von jeweils 1-F dargestellt werden. Das ist die übliche Schreibweise für Bytes und wird auch heute noch so verwendet. Im verlinkten Dokument werden die Opcodes in einer 16×16 Matrix dargestellt, die beiden hexadezimalen Ziffern spannen die Dimensionen auf. Die Matrix zeigt alle dokumentierten Befehle samt Opcodes.
In der Dokumentation vom Prozessor (6510 Microprozessor datasheet) ist folgendes ersichtlich:
Der Prozessor hat 16 Adress-Pins A0-A15 mit diesen 16 Bits (2 Bytes) kann man 64 kByte Speicher adressieren.
- $0000 ist dabei die niedrigste Adresse im Speicher
- $FFFF die höchste.
Für die Kommunikation stehen 8 Daten-Pins DB0-DB7 zur Verfügung und für die Kommunikation mit der Peripherie 5 IO-Pins P0-P5. Der Prozessor ist ein 8-bit Prozessor, das bedeutet sein Verhalten wird über 8-bit Opcodes gesteuert, in einem Schritt können 8 Bit Daten manipuliert werden. Ein Beispiel verdeutlicht worum es geht:
Das in der Einleitung erwähnte Kommando STA bedeutet STore Akkumulator. Der Akkumulator ist ein Speicher in der CPU in dem ein 8-bit Wert steht. Mit dem Befehl STA speichert man den dort gespeicherten Wert an die angegebene Adresse im Speicher. Die Syntax in Assembler Sprache sieht nun wie folgt aus:
1 | STA $D020 |
Um mit diesem Zwischenspeicher sinnvoll zu arbeiten gibt es das gegensätzliche Kommando LDA, das bedeutet LoaD Akkumulator. Um also den Wert 2 in im Speicher an der Adresse $D020 zu setzen kombiniert man beide Befehle wie folgt:
1 2 | LDA #$02 STA $D020 |
Der Wert 2 wird hexadezimal in den Akkumulator geladen, dieser Wert dann in den Speicher an die Adresse $D020.
Beispiel
Das Beispiel findest du auf meiner GitHub Seite. Am besten wird es deutlich wie Assembler funktioniert, wenn man sich das fertig kompilierte Programm ansieht. CBM Studio erstellt aus dem Source Code eine *.prg Datei. Öffnet man diese in einem Hex-Editor, dann findet man dort die erstellten Opcodes.
Der erste Befehl *=$1000 gibt die Startadresse an von dem aus das Programm in den 64kB Speicher vom C64 geladen wird. Danach ist im Source Code eine Sprungmarke definiert, diese findet sich nicht im erstellten Code, jedoch wird die Adresse mit jedem Vorkommen dessen Namen ersetzt. Als nächstes findet man den Assembler Befehl INC $D020. Dieser führt einen Increment auf den Wert auf der angegebenen Adresse aus, das heißt der Wert an Stelle $D020 wird um eins erhöht. In der *.prg Datei ist der Opcode von INC hinterlegt (EE) gefolgt von dessen Parameter. Aufgrund der Architektur (little-endian) wird beim C64 das LSB vor dem MSB geschrieben. Aus der Adresse $D020 wird 20 D0. Zuletzt bleibt noch das JMP mit dem Opcode von 4C und der Adresse der zuvor definierten Sprungadresse. Diese Zeigt auf den Start vom Programm, den wir ja im ersten Statement auf $1000 gesetzt haben. Deshalb steht nach 4C der hexadezimale Wert 00 10.
Das Programm:
1 2 3 4 | *=$1000 LOOP INC $D020 JMP LOOP |
wird vom Assembler also in EE 20 D0 4C 00 10 übersetzt. Das Programm liefert folgende Ausgabe:
Warum sehen wir diese Ausgabe? $D020 ist jenes Byte im Speicher, in dem die aktuelle Hintergrundfarbe vom Rahmen gespeichert ist. Dieses ändern wir nun in einer Endlosschleife und schalten reihum jede der 16 möglichen Farben. Das geht so schnell, dass der Rasterstrahl beim Bildaufbau in jeder Zeile mehrere unterschiedliche Farben zeichnet.
Fazit
Das war der erste Einstieg in die C64 Assembler Programmierung. Neben der Syntax habe ich auch ein erstes kleines Beispiel gezeigt und besprochen wie das fertig kompilierte Programm aussieht.
Eine Antwort
[…] Beispiel findet man wie immer auf meiner GitHub Seite. In einem früheren Tutorial habe ich bereits gezeigt, dass man den Hintergrund in bunten Farben zeichen kann. Das war damals […]