ASDIS intern


ASDIS ist ein (DER!) Assembler/Disassembler für den ZX81. Wir haben nix besseres, und wenn man viel mit ASDIS arbeitet, kommt man oft an dessen Grenzen. Zum einen wird bei langen Listings der Speicher knapp, daher sollte man schon sehr sparsam mit Labels und Marken umgehen. Das Drucken von langen Listings wird ebenfalls zur Qual, da ASDIS immer nur eine Seite druckt. Und könnte man dann auch noch mit Makros arbeiten...

Leider fehlen uns für das Programm selbst Unterlagen, wie ASDIS intern arbeitet. Aus diesem Grund habe ich einen Anfang gemacht, und das Gedächtnis von ASDIS analysiert: die Variable A$, in der der gesamte Quelltext gespeichert wird. Mit diesen Erkenntnissen sollten schon einige Arbeitserleichterungen machbar sein, dazu abschließend.


Die Variable A$ wird von ASDIS dynamisch verwaltet, d.h. ihre Länge ist veränderlich. Der Speicherknappheit kann man leicht Abhilfe schaffen, indem man RAMTOP einfach auf 65535 hochsetzt (durchgängig RAM vorausgesetzt). Lange Listings sind dann kein Problem mehr, sofern man sie auf einen Datenträger auch sichern kann.

In A$ steht nun alles drin, was ASDIS an Informationen zum Quelltext braucht. ASDIS hat zwar auch noch ein paar Systemvariablen, aber die brauchen uns vorerst noch nicht zu interessieren.

Der Aufbau von A$ ist nun recht einfach. Zu Anfang steht ein Header mit folgendem Inhalt:


Position

1/2

3/4

5/6

7/8

Inhalt

Anzahl d. Marken

Anzahl d. Labels

Ablegeadresse

Laufadresse


Zum Nachmachen: PRINT (CODE A$(5)-28)+256*(CODE A$(6)-28) zeigt uns ganz einfach die Ablegeadresse des Programmes an. Die Einträge sind also allesamt 16bit-Zahlen im gewohnten Format. Als nächstes folgt eine Tabelle mit allen Marken im Klartext und ihren Adressen. Jede Marke belegt damit 7 Bytes (5 Bytes Name, 2 Bytes Adresse) im Header. Ein simples PRINT A$ läßt diese Einträge schon sichtbar werden, da die Codierung im ZX-Format erfolgt. Nach den Marken folgt im selben Muster die Tabelle mit allen Labels.

ASDIS speichert Marken und Labels nur einmal als Klartext im Header. Im Quelltext wird dann nur noch die relative Position im Header, bezogen auf den Anfang der jeweiligen Tabelle, eingetragen. Jedes Label und jede Marke hat also seine Nummer, bei „0“ beginnend. Ist aber der Opcode eines Mnemonics ein Label oder eine Marke, steht diese auch im Klartext in der jeweiligen Zeile.

Nach dem Header folgt nun der eigentliche Quelltext, wobei jede Zeile ebenfalls im Klartext abgelegt wird. Der Zeilenaufbau ist sehr unterschiedlich, aber einfach zu lesen:


Position

1

2

3/4

>5

Inhalt

Code

Zeilenlänge

Labelnummer

Zeileninhalt


Eine Labelnummer wird nur eingetragen, wenn ein Label vorhanden ist, logisch. Wenn nicht, entfällt der Eintrag und nach der Zeilenlänge schließt sich sofort der Zeileninhalt an. Eine Zeilenendekennung wie im ZX (119=“Newline“) gibt es nicht, ASDIS muß also über die Zeilenlängen die nächste Anfangsadresse berechnen. Als Zeilenlänge wird immer nur die Länge des eigentlichen Codes eingetragen!

Am ersten Byte („Code“) erkennt ASDIS, um welche Art einer Zeile es sich im folgenden handelt. Jede Zeile hat entsprechend ihrem Inhalt einen speziellen, eigenen Aufbau, der nachfolgend für alle möglichen Fälle dargestellt wird. Die Beispiele werden so geschrieben, wie sie auch ASDIS selbst anzeigt.


eine einfache Mnemoniczeile ohne Labels/Marken

Länge (Bytes)

1

1

n

Eintrag (dez. / hex.)

24 / $18

Zeilenlänge (n)

Code


Bsp.: LD A,B sieht so aus: 24 - 1 - 120


eine einfache Mnemoniczeile mit Label

Länge

1

1

2

n

Eintrag

152 / $98

Zeilenlänge (n)

Position d. Labels

Code


Bsp.: LABEL LD A,B sieht so aus: 152 - 1 - 0 - 0 - 120 (wenn erstes Label im Header)


eine Kommentarzeile:

Länge

1

1

n

Eintrag

52 / $34

Zeilenlänge (n)

ZX-Klartext


Bsp.: ;ANFANG sieht so aus: 52 - 6 - 38 - 51 - 43 - 38 - 51 - 44


ein Freiraum (Platzhalter)

Länge

1

1

Eintrag

40 / $28

n (Größe des Freiraumes)


Damit ist klar, warum man nur maximal 256 Bytes Freiraum in einer Zeile angeben kann!


eine Datenzeile (Tabelle):

Länge

1

1

n

Eintrag

56 / $38

Zeilenlänge (n)

Tabelleninhalt


eine Textzeile:

Länge

1

1

n

Eintrag

60 / $3C

Zeilenlänge (n)

ZX-Klartext



ein Freiraum mit Label (Platzhalter):

Länge

1

1

2

n

Eintrag

168 / $A8

Zeilenlänge (n)

Position d. Labels

Tabelleninhalt



eine Datenzeile mit Label:

Länge

1

1

2

n

Eintrag

184 / $B8

Zeilenlänge (n)

Position d. Labels

Tabelleninhalt



der Operand ist ein Label:

Länge

1

1

5

n

2

Eintrag

88 / $58

Zeilenlänge (n)

Labelname im Klartext

Opcode

Adresse (assembliert)


Bsp.: LD A,(LABEL) : 88 - 3 - 49 - 38 - 39 - 42 - 49 - 58 - (2 Bytes Adresse)


der Operand ist eine Marke:

Länge

1

1

2

5

n

2

Eintrag

216 / $D8

Zeilenlänge (n)

Position d. Marke

Name der Marke im Klartext

Opcode

Adresse

(assembliert)


Bsp.: LD HL,(VARS) : 216 - 3 - 0 - 0 - 59 - 38 - 55 - 56 - 0 - 42 - 16 - 64


eine Textzeile mit Label:

Länge

1

1

2

n

Eintrag

188 / $BC

Zeilenlänge (n)

Position d. Labels

Klartext


Es wird klar, daß bestimmte Konstruktionen viel Platz fressen, diese machen aber gerade den Vorteil eines Assemblers aus. Hier stehen sich also wieder einmal Komfort und Speicherbedarf gegenüber.


Als erste Übung habe ich mir einen Kommentarkiller geschrieben. In einem Rutsch entfernt dieser alle Kommentarzeilen aus einem Listing und schafft wieder etwas Platz. Ob’s sinnvoll ist, wenn keine Kommentare mehr drin stehen? Es läßt sich ja erweitern, indem man entbehrliche Kommentare invers schreibt und nur noch diese entfernt würden.

Die nächste Anwendung wird eine Druckroutine sein, die das Listing übersichtlich formatiert. Später will ich dann zur Makroverwaltung kommen, mit der definierte Blöcke gelöscht, verschoben, kopiert oder eingefügt werden können. Die Routinen zur A$-Behandlung habe ich bereits fertig.


Kai Fischer, email: kai@zx81.de