64'er Sonderheft 71
Kitzeln auch Sie das Letzte aus Ihrem C64 heraus. Programmieren Sie in Maschinensprache. Dieser Super-Assembler macht's möglich.
Ein wichtiges Werkzeug für Maschinensprache-Fans ist der Assembler. Wenn Sie schon immer schnelle Grafiken oder tolle Sounds bewundert haben, finden Sie in Hypra-Ass genau das Richtige. Er ist ein in Maschinensprache geschriebener Drei-Paß-Assembler, d.h. Sie editieren komfortabel in einem eigenen Editor Ihre Quelltexte, danach assemblieren Sie. Hypra-Ass prüft zunächst auf richtige Schreibweise, dann werden Ablageadressen und Tabellen berechnet und in die entsprechenden Speicherzellen abgelegt. Im dritten Paß geschieht (falls gewünscht) die Quelltextaufbereitung.
Sie laden mit:
LOAD "HYPRA-ASS",8
und starten mit RUN. Hypra-Ass meldet sich mit:
BREAK IN 0
Dieser Text ist kein Fehler, sondern zeigt an, daß alle Funktionen einsatzbereit sind.
Der Quelltext wird automatisch in Basic-Programmzeilen abgelegt. Soweit wie möglich werden unnötige Blanks (Leerzeichen) dabei eleminiert. Für die einzelnen Quelltextzeilen gelten dabei folgende Vereinbarungen:
Beispiele:
100 -.BA $C000 110 -; REINE KOMMENTARZEILE 120 - LDA $14; KOMMENTAR HINTER EINEM BEFEHL 130 -MARKE LDX $15; MIT LABEL DAVOR
Zur bequemeren Eingabe und Bearbeitung des Quelltextes stellt Hypra-Ass im Editor 25 Befehle zur Verfügung (Tabelle 1).
Erlaubt sind die vier Grundrechenarten plus Potenzierung, die logischen Operationen NOT, AND und OR, die Vergleiche »gleich«, »kleiner« und »größer«, sowie der Einsatz der Funktionen <(...) und >(...), die das Low- bzw. High-byte eines Arguments liefern. Die logischen Operatoren und Vergleiche werden wie folgt abgekürzt:
!n! = not
!a! = and
!o! = or
!=! = gleich
!<! = kleiner als
!>! = großer als
Das Ergebnis eines Vergleichs ist -1, falls wahr, 0, falls nicht wahr:
(1!=!2) = 0
(1!=!1) = -1
Auch die NOT-Verknüpfung arbeitet wie in Basic:
!n!1 = -2
Das Argument in den Low/High-Byte-Funktionen muß im Bereich 0 < = Argument < = 65535 liegen.
Außer Dezimalzahlen sind Hex-Zahlen erlaubt, die durch ein vorangestelltes Dollarzeichen kenntlich gemacht werden:
$c000 = 49152
$10 = 16
$a = 10
Die Hexzahlen können nicht auch in den Basic-Befehlen verwendet werden.
Der Wert einer Hypra-Ass-Variablen liegt immer zwischen 0 und $FFFF. Variablennamen dürfen beliebig lang sein, wobei das erste Zeichen des Variablennamens ein Buchstabe sein muß. Weitere Zeichen können Buchstaben, Ziffern oder das Hochkomma (') sein.
In Zusammenhang mit der Verwendung von Makros muß zwischen globalen und lokalen Variablen unterschieden werden. Jede Variable erhält beim Anlegen ein sog. Ordnungszahl, die angibt, im wievielten Makroaufruf das Anlegen stattfand. Befindet man sich in keinem Makro, ist die Ordnungszahl dementsprechend Null.
Variable mit unterschiedlicher Ordnungszahl sind trotz gleichen Namens nicht gleich, sondern nur Variablen gleicher Ordnungszahl.
Die Konstruktion mittels Ordnungszahlen dient dazu, Fehler durch doppelte Benutzung von Labels auszuschließen.
Andererseits sind aus einem Makro heraus gesehen alle Variablen mit anderer Ordnungszahl als im Makro selbst »unsichtbar«. Um aber bequem Makros in Makros aufrufen und Label verwenden zu können, die in mehreren Makros benutzt werden sollen (etwa Betriebssystemroutinen), gibt es die globalen Variablen.
Globale Variablen sind, wie der Name schon verrät, im Gegensatz zu den lokalen Variablen unabhängig von der Ordnungszahl überall definiert.
Alle Makronamen sind per Definition global.
Alle Variablen sind bei Hypra-Ass redefinierbar gehalten, das heißt alle Variablen können durch eine Wertzuweisung jederzeit verändert werden.
Eine doppelte Benutzung von Variablen wird jedoch durch einen »Label twice«-Error (Tabelle 2) geahndet, da dies zu einem falschen Ergebnis der Assemblierung führen wurde.
Makros sind meist kürzere Befehlsfolgen, die im Quelltext häufiger vorkommen, und deshalb unter einem Makro zusammengefaßt werden. Zu jedem Makro gehört ein Name, mit dem es aufgerufen werden kann. An jedes Hypra-Ass-Makro können beliebig viele Parameter übergeben werden, deren aktueller Wert dann bei der Assemblierung im Makro eingesetzt wird. Makros können bei Hypra-Ass an beliebiger Stelle im Quelltext definiert werden. Alle Makronamen sind global, alle Parameter und makrointernen Label sind lokal. Das heißt verschiedene Makros können durchaus Label bzw. Parameter gleichen Namens verwenden.
Ein Beispiel für ein einfaches Makro:
Es wird immer wieder die Befehlsfolge benötigt, Akkumulator und x-Register mit dem Inhalt zweier aufeinanderfolgender Speicherstellen zu laden. Ein Makro dazu könnte folgendermaßen aussehen:
100 -.ma ldax (adresse) 110 - lda adresse 120 - ldx adresse+1 130 -.rt
Dem .ma-Pseudobefehl folgt ein Variablenname, der Makroname, und eine Parameterliste in runden Klammern, falls die Parameter vorhanden sind. In unserem Beispiel ist es ein Parameter, die Adresse der Speicherzelle, die in den Akku soll. Sind mehrere Parameter vorhanden, werden sie durch Komma getrennt. In die Parameter setzt der Assembler bei jedem Aufruf den aktuellen Wert, der im Aufruf steht. Rufe ich also ldax(2) auf, entsteht bei der Assemblierung des Makros die Folge lda 2, ldx 3, entsprechend führt der Aufruf mit ldax (label) zu lda label, ldx label+1.
Die Parameterliste darf in der Definitionszeile eines Makros nur aus einer die Folge von Variablennamen bestehen, während im Aufruf als aktuelle Parameter beliebige Ausdrücke erlaubt sind. Hinter der Definitionszeile mit dem .ma-Pseudo folgt der eigentliche Makroinhalt, also das, was bei einem Aufruf des Makros assembliert werden soll.
Natürlich sind hier nicht nur einfache Befehle wie in unserem Beispiel gestattet. Genausogut können im Makro Verzweigungen und Sprünge ausgeführt werden, es kann bedingt assembliert werden und weitere Makros lassen sich aufrufen. Für die Schachtelung von Makros besteht keine Grenze außer der begrenzten Fassungskapazität des Prozessor-Stacks.
Als Beispiel: Wird ein Makro mit zehn internen Labeln 100mal aufgerufen, ergibt sich schon für die dadurch erzeugten lokalen Label ein Platzbedarf von 7000 Byte.
Sollte irgendwann der Fall eintreten, daß Label und Quelltext zusammen nicht mehr ins RAM passen, erhalten Sie den »too many labels«-Error. Dies ist allerdings mehr ein theoretischer Fall, denn auch bei der Assemblierung von Hypra-Ass selbst wurden trotz extensiver Benutzung von Labels nicht einmal 500 gebraucht. Sie können aber davon ausgehen, daß Ihnen immer mindestens Platz für 1170 Labels zur Verfügung steht -- in den meisten Fällen erheblich mehr.
Selbstaufrufe von Makros sind nicht verboten. Inwieweit eine solche Konstruktion überhaupt sinnvoll sein kann, muß jeder selbst prüfen.
Zurück zur Makrodefinition: Jede Makrodefinition muß unbedingt mit dem Pseudo .rt (return) abgeschlossen sein. Trifft der Assembler bei der Abarbeitung eines Makros auf ».rt«, heißt das für ihn, die Assemblierung hinter dem Aufruf fortzusetzen.
Vor der .ma und .rt-Anweisung dürfen in derselben Zeile kein Label stehen. Die Makrodefinition selbst wird in Pass 1 und Pass 2 überlesen. Er zählen also nur die Makroaufrufen bei der Assemblierung.
Der Aufruf eines Makros erfolgt durch den Pseudobefehl ..., gefolgt vom Makronamen und der aktuellen Parameterliste in runden Klammern.
Zwei Pseudobefehle stehen zur Verfügung, um Label einen Wert zuzuweisen:
Beide Pseudos werden der eigentlichen Wertzuweisung vorangestellt, wie auch LET in Basic:
100 -.eq marke = $ffc0 110 -.gl label = $200
Bei der Wertzuweisung an Label ist immer der Bereich einzuhalten, in dem ein Labelwert liegen darf (0 bis $FFFF).
Drei Pseudo-Ops erleichtern das Einfügen von Tabellen und Text in den Quelltext:
Immer wenn Byte-Werte im Quelltext erwartet werden (z.B. bei unmittelbarer Adressierung) können Strings der Länge 1 verwendet werden. Ein befehl lda # "x" ist damit erlaubt.
Zur Unterstützung der bedingten Assemblierung bietet Hypra-Ass die Befehlsfolgen IF/THEN/ELSE und IF/THEN. Außerdem steht ein unbedingter Sprungbefehl zur Verfügung:
Mit dem Pseudo .ap (append) kann ein weiterer Quelltext am Ende des Pass 2 automatisch nachgeladen werden, wobei der Programmzähler aus der vorangegangenen Assemblierung erhalten bleibt.
Hinter .ap muß der Name des nachzuladenen Files in Anführungszeichen stehen.
Eine Besonderheit von Hypra-Ass bildet im Zusammenhang mit verketteten Quelltexten der Pseudo-Opcode .co (common).
Dieser befehl bewirkt zunächst, daß alle Variablen/Label, die hinter der .co-Anweisung in einer Liste stehen, an den nachgeladenen Teil übergeben werden.
Zweitens bleiben alle Quelltextzeilen bis zur common-Zeile beim Nachladen erhalten. Steht also ein Makro vor der common-Zeile, wird auch das Makro übergeben. Zu beachten ist dabei:
Der Pseudobefehl .ob (object), gefolgt vom Filenamen,p,w (in Anführungszeichen), sendet den erzeugten Objektcode direkt zur Floppy.
Geschlossen wird das so erzeugte Objekt-File durch den Pseudobefehl .en.
Sollte während der Assemblierung ein Fehler entdeckt werden und das Objekt-File nicht schon durch die Hypra-Ass-Fehlerroutine geschlossen worden sein, geben Sie ein:
CLOSE 14
.li 1,3,0
sendet ein formatiertes Listing des Quelltextes unter der logischen Filenummer 1 an das Gerät 3 mit der Sekundäradresse 0 (Bildschirm). Die Parameter hinter .li entsprechen denen des OPEN-Befehls. Dadurch wird es auch möglich, das Listing auf eine User-Datei umzuleiten:
.li 2,8,2,"test,u,w"
Der .li-Befehl muß der erste im Quelltext sein, Zeilen bis einschließlich .li werden nicht ausgegeben. Formatierte Zeilen haben folgendes Format:
C000 A0B0C0: 1000 -marke befehl ;kommentar
Das Listing des Quelltextes erhält die Kopfzeile »Hypra-Ass Assemblerlisting:«. Die Steuerung der Formatierung erfolgt mit dem Editor-Befehl »/t«. Bei Zeilen, die Pseudobefehle enthalten, wie .eq..., werden keine Adressen und Opcodes ausgegeben.
.sy 1,3,0
sendet am Ende von Pass 2 die sortierte Symboltabelle. Die Formatierung wird hier duch »/t3,...« gesteuert. Die Labelwerte werden hexadezimal ausgegeben:
sprungziel = $ffd2
Die symboltabelle erhält die Kopfzeile »Symbols in alphabetical order«.
.dp t0,t1,t2,t3
setzt auf dem Quelltext heraus die Tabulatoren für:
Nach dem zweiten Pass wird die Meldung »end of assembly«, gefolgt von der Assemblierungsdauer in Minuten, Sekunden und Zehntelsekunden ausgegeben. Dahinter folgt die Zeile »Base = $XXXX last byte at $YYYY«.
Die Zusammenfassung aller Pseudobefehle finden Sie in Tabelle 3.
Um das Editieren der Texte komfortabler zu gestallten, besitzt Hypra-Ass einige neue Eingabefunktionen.
Grundlage dafür blieb dabei der Basic-Editor. Ein Hypra-Ass-Editor wird also genauso eingegeben wie ein Basic-Programm. Allerdings muß hinter der Zeilennummer grundsätzlich ein Minuszeichen eingegeben werden. Es zeigt den Beginn einer Quelltextzeile an. So eingegebene Zeilen werden als ASCII-Zeilen in den Speicher übergenommen.. Alle überflüssigen Blanks werden dabei entfernt und unmittelbar danach wird die Zeile formatiert am Bildschirm ausgegeben.
Im Gegensatz zu Basic kann eine Zeile nicht durch Eingabe der Zeilenummer gelöscht werden, sie wird mit »/D Zeilennumer« und <RETURN> entfernt. Eine Ausnahme bildet die Zeilennummer »0«. Sie wird weiterhin mit »0« und <RETURN> entfernt. Eine Beschreibung der Editor-Befehle finden Sie in Tabelle 1. Trotzdem einige Anmerkungen:
(Gerd Möllmann/RvB)
Zur Unterstützung des Umgangs mit dem Floppy-Laufwerk 1541 sind drei Befehle implementiert:
Diese drei Befehle entsprechen denen des DOS 5.1.
Auch zur Farbgehung des Bildschirms sind zwei Befehle vorhanden, die die Hintergrund- und Rahmenfarbe setzen:
Nach erfolgter Assemblierung kann nun die erzeugte Symboltabelle mit zwei Befehlen ausgegeben werden:
Es werden nur Label ausgegeben, die entweder global oder von der Ordnung Null sind.
Beide Dumps können mit der CTRL-Taste verlangsamt und mit der STOP-Taste angehalten werden.
Mit OPEN... und CMD... können die DUMP an andere Geräte gesendet werden.
Als Ergänzung zum Basic-Befehl PRINT, der aufgrund der Tokenbildung nicht alle Labelnamen verarbeiten kann, kann der Befehl verwendet werden.
Basic-Funktionen wie PEEK sind nur über den PRINT-Befehl erreichbar. Die Funktionen <(...) und >(...) sind außerhalb des Quelltextes nur durch zu verwenden. Mit dem -Befehl kann genau wie im Quelltext gerechnet werden.
Zusätzlich zu den Fehlermeldungen, die von Interpreter-Routine wie »illegal quantity« oder »syntax« stammen, gibt Hypra-Ass folgende Meldungen aus:
Hinzuweisen ist noch auf eine einfache Möglichkeit den »label twice-error« zu vermeiden:
Legt man eine Makrodefinition um einen beliebigen Block des Quelltextes, so sind alle Label in dem Block automatisch lokal. Auf diese Weise kann schon vorhandene Quelltext in neuen eingefügt werden, ohne daß man sich um doppelt verwendete Labelname kümmern muß.
Vor den Anweisungen 12, 13, 14, 16 und 17 dürfen in derselben Zeile keine Label stehen.