5.
INHLT. (INHALT) Diese Funktion verschafft per Tabelle einen
Überblick über den Inhalt des Assemblerlistings, wobei die
einzelnen Worte folgendes bedeuten:
LAUFADR: Laufadresse,
also die Adresse, an welcher das Programm nach dem Assemblieren
lauffähig ist. (Siehe Funktion A)
ABLEGEN Adresse, wo das
Programm nach dem Assemblieren abgelegt werden soll. (Siehe Funktion
A)
M-CODE gibt die Länge
des Maschinencodes an, der im Listing enthalten ist, also die Länge
(in Bytes), die das reine Maschinenprogramm bisher hat (wenn man alle
Labels, Kommentare, interne Codierung usw. abrechnet).
LISTING gibt die Länge
des Listings (in Bytes) an. Das ist die Länge der Variablen A$
(die durch Eingabe eines Assemblerprogramms vergrößert
wurde) inklusive Labels, Kommentare, usw.
ZEILEN
Zahl der Zeilen, die das Listing enthält.
KOMMENT
Zahl der Kommentare
BEFEHLE
Zahl der Befehlszeilen
VARIABL
Zahl der definierten Arbeitspeicher (Frei-, Text-, Datenzeilen)
MARKEN
Zahl der definierten Marken.
LABELS
Zahl der verwendeten Labels.
AUFRUFE Zeigt an,
wieviele Symbole durch das Listing aufgerufen wurden. (Siehe Symbole)
FREI AB Adresse des
ersten Bytes, das vom Basic (also auch vom Listing) nicht mehr
benötigt wird.
BYTES Anzahl der freien
Bytes zwischen FREI und dem Maschinenstack. Zeigt also
die Größe des Speicherbereiches an, der für
Maschinencode frei ist.
(Alle
Werte werden dezimal und hexadezimal angezeigt.)
6.
RNAM. (RENAME) Ein Symbol kann umbenannt werden. Es erscheint
das Wort ALT: und man gibt die bisherige Schreibweise
ein, danach erscheint NEU: und man gibt den neuen Namen
ein. Wenn 2 richtig geschriebene Symbole eingegeben wurden,
durchsucht das Programm das komplette Listing und ersetzt jedes
Vorkommen des alten Symbols durch das neue und sagt anschließend
OK.
Diese
Funktion ist vor allem im Zusammenhang mit dem Reverse Assembler
interessant. wenn man automatisch erzeugte Symbole umbenennen will.
7.SYMBL.
(SYMBOL) Sämtliche Symbole werden aufgelistet und deren
dezimale und hexadezimale Werte angezeigt. Zuerst erscheint das Wort
MARKEN und nach den Marken das Wort LABELS
und alle Label. Es werden jeweils max. 18 Symbole angezeigt, bei
Tastendruck erscheinen die nächsten. Normalerweise werden die
Symbole relativ ungeordnet abgespeichert und deshalb auch ungeordnet
angezeigt. Wenn man aber Shift und 7 drückt statt 7, dann werden
die Symbole vor der Anzeige zuerst alphabetisch geordnet (im
Fast-Modus).
8.
RETURN Kehrt ins Basic zurück.
9.
DRUCK. Ausgabe des oberen Bildschirmteils an den Drucker.
A.
ASSMB. Diese Taste startet den Assembler. Da es sich bei ASDIS um
einen 2-Paß-Assembler handelt, dauert dieser Vorgang im
allgemeinen nur Sekundenbruchteile. (Längere Listings
brauchen aber schon ein paar Sekunden bis knapp eine Minute.) Im
ersten Assembler-Paß werden die Werte aller Labels berechnet
und im 2. Lauf werden diese Werte überall eingesetzt, wo das
entsprechende Symbol aufgerufen wird.
Da
der Editor so gestaltet ist, daß Syntaxfehler verhindert
werden, können Fehler nur noch im Zusammenhang mit Symbolen
auftreten: Entweder wird durch einen Befehl ein Symbol aufgerufen,
das nicht definiert wurde oder ein relativer Sprung ist so auf ein
Label gerichtet, daß die maximale Sprungweite von +127 oder
-128 überschritten wird. Es gibt also keine Fehlermeldungen.
Wenn
ein Fehler entdeckt wird, wird der Assemblerlauf abgebrochen und
direkt in die Eingabefunktion gesprungen (dies ist die einzige
Funktion, die nicht immer ins Hauptprogramm zurückkehrt). Der
Arbeitszeiger ist jetzt auf die Zeile gerichtet, in der der Fehler
entdeckt wurde, man kann ihn also schnell beheben.
Wenn
kein Fehler im Programm ist, wird der reine Maschinencode automatisch
an der Ablegeadresse (nicht Laufadresse) abgelegt und es erscheimt:
OK. Anfänger im Programmieren mit Assembler sollten
sich nicht durch die Möglichkeit erschrecken lassen, ein
Programm an eine andere Stelle zu legen, als an die, wo das Programm
laufen soll. Sie ist für Spezialfälle gedacht.
Im
Zweifelsfall gilt immer: Laufadresse=Ablegeadresse.
Um
zu zeigen, wie einfach diese Funktion benutzt werden kann ein
Beispiel:
Basic-REM-Zeile
mit der Zeilennummer 1 und vielen Blanks (oder irgendwelchen anderen
Zeichen) eingeben - Assembler wieder starten - Ablege- und
Laufadresse auf 16384 richten.
Wenn
man jetzt ein geschriebenes Programm assemblieren läßt,
wird es in diese REM-Zeile gelegt und ist dort lauffähig, kann
also an der Adresse 16384 gestartet werden.
Diese
Vorgehensweise ist für die meisten Fälle am sinnvollsten.
Um bestimmte Programme zu schreiben, kann es aber wünschenswert
sein, Lauf- und Ablegeadresse zu trennen.
Ein
Beispiel: Sie wollen ein Programm schreiben, das später oberhalb
des RAMTOP laufen soll, wo jetzt z.B. der Assembler steht. Das ist
ganz einfach möglich, indem Sie das Programm für
irgendeinen anderen Speicherbereich im freien RAM schreiben. Und dort
testen Sie das Programm auch aus. Lauf- und Ablegeadresse haben
während dieser Zeit den Wert des Test-Speicherbereichs. Wenn das
Programm fehlerfrei ist, geben Sie als Laufadresse die Anfangsadresse
an, die Ihr Programm haben soll, die Ablegeadresse bleibt
unverändert. Dann laßen Sie noch einmal assemblieren.
Dadurch wird erreicht, daß das Programm jetzt an der
ursprünglich beabsichtigten Stelle arbeitsfähig ist. Dort
wird es aber nicht hingelegt, sondern wieder an die Stelle, an der es
bisher getestet wurde. Es wird also nichts ungewollt überschrieben.
Es
geht jetzt nur noch darum, diesen Maschinencode an seine
Bestimmungsadresse zu bringen. Dazu braucht man noch ein
Verschiebeprogramm. Aber zuerst empfiehlt es sich, das Listing und
den Maschinencode abzuspeichern. B ist eine Spezialfunktion, die das
Abspeichern von Maschinencode erleichtert.
Wenn
man erreichen möchte, daß ein Listing nur überprüft
aber nicht abgelegt wird, legt man als Ablegeadresse 0 fest, denn ins
ROM kann bekanntlich nichts geschrieben werden. Vorsicht: es gibt
Hardware, die ein Schreiben in den ROM-Bereich erkennt und für
Schaltvorgänge nutzt. Stichwort: POKE-Karte!
Der
Assembler läuft im Fast-Modus und kann mit 8
angehalten werden.
B.
M-CODE. REM-Zeilen haben für das Ablegen von Maschinencode
einige Nachteile:
1. Man muß sie erst
eintippen, was sehr mühselig sein kann.
2. Man muß immer
darauf achten, daß die REM-Zeile mindestens so lang wie der
Maschinencode ist.
3. Je nach Maschinencode
kann so etwas wie ein ungewollter Listschutz entstehen,
das Basic zeigt dann einfach große Teile des Basic-Programms
nicht mehr an.
4. Wenn REM-Zeilen mit
Maschinencode sehr lang werden, hängt sich das Basic beim Listen
sehr oft auf.
Diese
Nachteile können durch die Funktion B vermieden werden, wobei
man allerdings darauf verzichten muß, das Maschinenprogramm in
eine Basic -Zeile zu schreiben.
Diese
Funktion ersetzt das komplette Assemblerlisting durch den
entsprechenden Maschinencode, d.h. die Variable A$, die bisher das
Assembler-Listing enthält, wird mit dem entsprechenden
Maschinencode überschrieben. Diese Variable wird außerdem
zu B$. A$ existiert dann nicht mehr.
Das
funktoniert auch dann, wenn das Listing so groß geworden ist,
daß es den gesamten Speicher belegt.
Wenn
man ein Maschinenprogramm so ausgetestet hat, wie in Funktion A
beschrieben, dann erzeugt diese Funktion den direkt abspeicherbaren
Maschinencode.
Dieser
Maschinencode muß nach dem Laden natürlich jeweils an die
Stelle geschoben werden, für die er berechnet ist, deshalb
empfiehlt es sich, an den Anfang eines Maschinenprogramms immer
folgendes kleine Verschiebeprogramm zu schreiben:
LD
HL,($4010) Richtet HL auf Variable (B$).
INC
HL
LD
C,(HL) Lädt in BC die Länge dieser Variablen
INC
HL
LD
B,(HL)
LD
DE,$0012 Richtet HL auf Programmbyte
ADD
HL,DE
LD
DE,LABEL Richtet DE auf Laufadresse
LDIR Verschiebt
das Programm nach LABEL
RET Rückkehr
ins Basic
LABEL.... Hier
fängt das eigentliche Programm an.
Diese
Verschiebefunktion läßt sich immer so aufrufen: RAND USR
(PEEK 16400+256*PEEK 16401+3) und erspart eine zeitraubende PEEK- und
POKE-Schleife. Dieses Programm funktioniert aber nur, wenn B$ die
erste Variable im Variablenteil des Basic ist. Das läßt
sich dadurch erreichen, daß man vor Neubeginn einer
Programmeingabe erst CLEAR eingibt und dann ASDIS startet.
Bei
der Verwendung von großen Frei-Zeilen ist zu beachten. daß
sie möglichst nicht ganz am Anfang des Listings stehen sollten,
sonst könnte die Funktion 6 in Ausnahmesituationen zum Absturz
führen. Im Zweifelsfall kann das immer dadurch verhindert
werden, daß man vor einer Freizeile einen Kommentar einfügt,
der so viele Zeichen enthält, wie durch die Frei-Zeile Bytes
freigehalten werden.
Zur
Sicherheit wird diese Funktion nicht sofort ausgeführt, sondern
zeigt zunächst ein ? und erwartet ein J
zur Bestätigung, andernfalls Return ins Hauptprogramm. Nach der
Ausführung wird der Assembler automatisch verlassen.
C.
RASS. (REASSEMBLER) Mit dem Reverse-Assembler (umgekehrter
Assembler) kann man Maschinencode, der irgendwo im Speicher steht, in
ein Assemblerlisting umwandeln lassen. Man gibt die Adresse des 1.
umzuwandelnden Befehls und die Menge der Befehle (nicht Bytes) an.
Danach wird die entsprechende Zahl Befehle ins Listing aufgenommen.
Alle vorkommenden 16-Bit-Zahlen werden durch Symbole ersetzt und
überprüft, ob ein Symbol mit diesem Wert schon besteht.
Wenn es nicht existiert, wird automatisch ein Label oder eine Marke
erzeugt.
Der
Reverse-Assembler dient dazu, vorhandene Programme entweder an
anderer Stelle lauffähig zu machen oder sie in ein eigenes
aufzunehmen.
Datenbereiche
werden von dieser Routine nicht erkannt. Der Reverse Assembler
erzeugt also keine Frei-, Daten- oder Text-Zeilen. Sollten solche
Bereiche im Programm vorkommen, so muß man sie anschließend
von Hand korrigieren.
D.
DISAS. Der Disassembler erwartet zunächst eine Anfangsadresse
und zeigt dann 18 Befehle disassembliert an. Die Anzeige ist 3teilig:
links Befehlsadresse, Mitte vollständige Mnemonik und rechts
alle Codes aus denen der Befehl besteht.
Eine
Ausnahme machen die relativen Sprünge, denn es nützt ja
nicht viel, wenn man die Weite eines Sprunges sieht, sondern man
möchte sehen, wohin gesprungen wird, deshalb wird das Sprungziel
berechnet und angezeigt.
5: Die oberen 18 Zeilen
werden fließend nach oben gescrollt und unten jeweils eine neue
Zeile sichtbar.
6:
Die nächsten 18 Befehle werden disassembliert.
7: Wenn man beim
Disassemblieren etwas zu weit vorgerückt ist, möchte man
wieder zurück, ohne eine neü Adresse einzutippen. Diese
Funktion zieht einfach von der laufenden Adresse 70 ab und
disassembliert die folgenden 18 Befehle. Man hat so die Möglichkeit,
Maschinenprogramme bequem zu studieren.
8:
Return ins Hauptprogramm.
9:
Ausgabe an Drucker.
E.
EINZL. Der Einzelschrittbetrieb führt sämtliche Z80-Befehle
fast ohne Absturzgefahr aus. Dazu unterscheidet das Programm intern
zwei Befehlsarten:
1. Befehle die den
Program Counter (PC) ändern, werden in einer Spezialroutine
simuliert (JP, JR, CALL, RET, usw.).
2. Alle anderen
Anweisungen werden ausgeführt, nachdem ein
Simulations-Stackpointer sowie alle Registerinhalte neu geladen
wurden. Nach der Ausführung werden die Registerinhalte wieder im
Speicher abgelegt. Der Simulationsstack ist anfangs auf $FF80 (bzw.
$7F80 bei 6K RAM) gerichtet, wo genügend Platz nach oben und
unten ist, er kann aber auch an jede andere Stelle im freien RAM
gerichtet werden.
In dieser Funktion sind
immer sämtliche Registerinhalte und Flags sichtbar. Bei den
Flags bedeutet 1 Flag gesetzt und 0 Flag
gelöscht. Es wurden nur der Interrupt Vector (IV) und der
Refresh Counter (RC) weggelassen, weil sie beim Sinclair kaum benutzt
werden können, ohne daß die Hardware durcheinander
gebracht wird.
Unterhalb des
PC-Registers wird der 2. Registersatz des Z80 aufgelistet, auf den
bekanntlich nur durch die Befehle EXX und EX AF,AF zugegriffen werden
kann.
Bevor der
Einzelschrittbetrieb beginnt, kann man die Inhalte aller Register
festlegen. Um ein bestimmtes Register auszuwählen, bewegt man
den Cursor mit den Tasten 6 und 7 auf und ab. Nach 5 oder Shift 8
(beliebig) kann das Register, neben dem der Cursor steht, verändert
werden. Auch hier können (wie immer) Symbole statt Zahlen
eingegeben werden. (Wenn man z.B ein soeben assembliertes und
abgelegtes Programm ab Label soundso testen will.)
Der Inhalt des PC
entscheidet darüber, an welcher Stelle der Einzelschrittbetrieb
aufgenommen wird. Sobald man die Registermanipulation (durch 8
) verläßt, wird der Befehl disassembliert, auf den der PC
gerichtet ist, aber zur Sicherheit noch nicht ausgeführt.
5: mit dieser
Unterfunktion werden alle Befehle mit Ausnahme an CALL und RST
Anweisungen im Einzelschrittbetrieb ausgeführt. CALLs und RSTs
werden echt ausgeführt. Diese Funktion hat ihren Sinn im Testen
rechenintensiver Programme, wo es aus Zeitgründen sinnlos wäre,
sie im Einzelschrittbetrieb zu testen.
Unterprogramme, die man
schon getestet hat und die mit CALL (oder RST) aufgerufen werden,
kann man also auf einmal ausführen lassen, um schneller zur
kritischen Stelle zu kommen, die man eigentlich testen möchte.
Man sollte natürlich vor der Benutzung dieser Taste sicher sein,
daß entsprechende Unterprogramme auch einwandfrei arbeiten.
6: Diese Taste bewirkt
den eigentlichen Einzelschrittbetrieb. Sooft man diese Taste drückt,
führt man eine Einzelschritt-Simulation aus. Der Bildschirm wird
gelöscht, der ausgeführte und der nächste
auszuführende Befehl werden disassembliert und die neuen
Registerinhalte angezeigt.
7: Mit dieser Taste gibt
man eine NOP-Anweisung, also die Anweisung den nächsten Befehl
zu überspringen statt auszuführen. Das hat immer dann einen
Sinn, wenn man einen normalen Programmablauf verlaßen möchte,
wie er durch Sprünge, CALLs oder RETs erzwungen würde, oder
wenn eine Anweisung nicht ausgeführt werden soll, weil sie z.B.
wichtige Speicher (wie Stack oder System-Variablen) überschreiben
würde. Andere Beispiele für nicht ausführbare Befehle
sind HALT, IM 0 und IM. 2.
8: Rückkehr ins
Hauptprogramm.
9: Ausgabe an den
Drucker.
F.
RUN. Maschinenprogramme können sowohl aus dem Basic als auch dem
Assembler aufgerufen werden. Es ist selbstverständlich, daß
jedes Maschinenprogramm irgendeine Rückkehranweisung, also ein
RET, enthalten muß. Bei Aufrufen aus dem Basic hat der
Assembler keinerlei Einfluß auf den Programmlauf, d.h. die
Registerinhalte zum Programmstart sind unbekannt und Programme können
sowohl im Fast- als auch im Slow-Modus ausgeführt werden.
Der
Programmstart aus dem Assembler bietet sich vor allem für das
Austesten einzelner Routinen an, wenn es darum geht, anfangs
Registerinhalte festzulegen - wie im Einzelschrittbetrieb - oder zu
wissen, welche Registerinhalte der Prozessor nach Ende des
Programmlaufs hat.
Zu
Beginn der Funktion wird die Registereingabe gestartet. Der Inhalt
des PC entscheidet über die Startadresse. Die Registereingabe
wird durch 8 beendet, der erste ausführbare Befehl
disassembliert und die Startanweisung R (RUN) erwartet. -Wenn man
stattdessen nochmals 8 eingibt, erfolgt Rückkehr ins
Hauptprogramm ohne Ausführung des Maschinencodes.
Sobald
ein Maschinenprogramm aufgerufen ist, ist es für jedes Bit
verantwortlich, mit dem es der Prozessor jetzt zu tun bekommt. Weder
ROM noch Assembler haben irgendeine Einflußmöglichkeit bis
zum RET. (Es empfiehlt sich also immer, rechtzeitig abzuspeichern).
Zur
Programmausführung aus dem Assembler wird automatisch in den
Fast-Modus umgeschalten und der Bildschirm gelöscht. Der
Fast-Modus hat den Vorteil, daß alle, auch die Index-Register
und der 2. Akku verwendet werden können (solange man keine
Routinen im ROM aufruft, die diese Register benötigen). Nach
Beendigung des Maschinenprogramms werden sämtliche
Registerinhalte und Flags angezeigt, so wie sie vom ausgeführten
Programm übergeben wurden
G.
VGL. Mit der Vergleichsroutine kann man 2 Speicherblöcke auf
Identität überprüfen. Es werden 2 Anfangsadressen
erwartet und danach die Blöcke Byte für Byte verglichen,
bis ein Unterschied auftritt (bzw. der 1.Block die Adresse 0
erreicht). Bei einem Unterschied wird die entsprechende Adresse der
beiden Blöcke dezimal und hexadezimal angezeigt und auf einen
Tastendruck als Fortsetzungsanweisung oder Return (8)
gewartet
H.
LAUF. Die bisherige Laufadresse wird angezeigt und kann geändert
werden.
I.
ABLEG. Die bisherige Ablegeadresse wird angezeigt und kann geändert
werden. Diese beiden Adressen brauchen nur einmal für jedes
Programm festgelegt werden, wenn man es immer an derselben Stelle
laufen laßen möchte
J.
DUMP. Die Speicherinhalte des ZX81 werden als Hex-Dump ausgelistet,
indem man eine Adresse eingibt und N/L drückt. Es werden auf 16
Zeilen 128 Bytes mit den Adressen angezeigt.
6: nächste 128 Bytes
auslisten
7: vorhergehende 128
Bytes auslisten
8: Rückkehr ins
Hauptprogramm
9: Ausgabe an Drucker
K.
MARKN. Alle Marken werden einzeln angezeigt und können gelöscht
oder deren Wert geändert werden.
5: Markenwert ändern
und nächste Marke anzeigen
6: keine Änderung
und nächste Marke zeigen
7: Marke löschen
8: Rückkehr ins
Hauptprogramm
Eingabefunktion
Die
Eingabefunktion ist so weit ausgebaut, daß man sie als ein
Programm im Programm ansehen kann. Interaktiv ist sie, weil sie den
Programmierer in folgenden Punkten unterstützt:
- Sofortige
Syntax-Prüfung, man kann also wie im Basic nur korrekte Zeilen
eingeben.
- Es
ist immer eine Statusinformation sichtbar, die Hinweise darauf gibt,
in welchem Zustand das Programm sich befindet, bzw. welche Eingaben
es erwartet.
- Zeilennummern
brauchen nicht eingegeben werden, die laufenden Adressen werden
automatisch berechnet und angezeigt.
- An
beliebiger Stelle kann man beliebig viele Zeilen einfügen oder
löschen.
- Den
Arbeitszeiger kann man bequem auf jede Zeile richten.
Bildaufbau
Die
Eingabefunktion hat einen speziellen Bildaufbau: der Bildschirm ist
in 2 Teile aufgeteilt. Im oberen Teil von 16 Zeilen ist immer ein
Teil des Assemblerlistings sichtbar. Er ist waagerecht wiederin 3 bis
4 Spalten gegliedert:
1.
Die linken 4 Zeichen enthalten die jeweiligen Hex-Adressen der
Zeilen.
2.
Die nächsten 5 Zeichen rechts daneben sind der Symbolteil, hier
werden eingegebene Labels angezeigt.
3.
Bei Sonderzeilen zeigen die restlichen 23 Zeichen den eingegebenen
Code an.
4.
Bei normalen Assemblerzeilen ist der Codeteil nur 15 Zeichen lang
(das genügt für die Darstellung sämtlicher
Z80-Mnemoniks). Die letzten 8 Zeichen zeigen den Hex-Code an, der den
Mnemoniks entspricht.
In
der 9. Zeile des oberen Teils sind die ersten 4 Zeichen immer
invertiert dargestellt, um die Adresse der Zeile hervorzuheben. auf
die der Arbeitszeiger gerichtet ist.
Der
untere Bildteil von 8 Zeilen enthält den Raum für die
Statusinformation und die Eingabe von Zeilen:
- Das
erste Zeichen der 17. Zeile enthält immer die Statusinformation
- einen invertierten Buchstaben.
- Die
nächsten 3 Zeichen sind ein Teil der Adresse, auf die der
Arbeitszeiger gerichtet ist.
- Die
nächsten 5 Stellen sind der Symbolteil, in den man entweder ein
Label schreibt oder die Angaben für eine Unterfunktion macht.
4.
Der Rest der unteren 8 Zeilen kann für die Eingabe von Zeilen
genutzt werden. (Codeteil)
Verkürzte
Darstellung
Sonderzeilen
können also bis zu 8 Zeilen lang werden. Leider kann der ZX81
pro Bildzeile aber nur 32 Zeichen anzeigen. Um einen ungleichmäßigen
Bildaufbau zu verhindern, der dadurch entstehen würde, daß
man auch Sonderzeilen die mehr als 32 Zeichen benötigen, in
voller Länge anzeigt, werden von allen Zeilen nur so viele
Zeichen angezeigt, wie in einer Bildzeile Platz haben. Lange Zeilen
werden also verkürzt dargestellt. Aber das Programm vergißt
die restlichen Eingaben nicht. Man kann mit der Korrekturfunktion
jede Zeile wieder in den unteren Bildteil holen, wo sie sichtbar und
veränderbar ist.
Statusinformationen
Die
möglichen Statusinformationen sind:
B
Befehlszeile eingeben
C
Codeteil
D
Datenzeile eingeben
F
Freizeile eingeben
6
Grundzustand
K
Kommentar eingeben
L
Zeilen löschen
M
Marke eingeben
R
Arbeitszeiger rückwärts bewegen
S
Symbolteil
T
Textzeile eingeben
V
Arbeitszeiger vorwärts bewegen
Z
Arbeitszeiger auf bestimmte Zeile richten
Grundzustand
der Eingabefunktion
Solange
das invertierte G" (Grundzustand) als Statusinformation
sichtbar ist, hat man die Wahl, entweder durch einfachen Tastendruck
eine Unterfunktion der Eingabefunktion aufzurufen oder in den Symbol-
bzw. Codeteil zu verzweigen. Sobald eine Unterfunktion ausgeführt,
eine Zeile eingegeben oder wenn ein Fehler entdeckt wurde, kehrt das
Programm automatisch wieder in diesen Grundzustand zurück.
Nur
wenn eine Zeile eingegeben wurde, wird der Eingabeteil gelöscht.
Der obere (Listings-) Teil wird durch Cursor-, Lösch- und
Eingabefunktionen gesteürt Wenn ein Fehler entdeckt wurde, wird
das Bild überhaupt nicht geändert.
Symbolteil
Wenn
im Grundzustand weder eine Ziffer noch ein Blank, N/L
oder Strichpunkt gedrückt werden, erwartet das Programm eine
Symboleingabe, was es durch die Statusinformation S
anzeigt. Außerdem erscheint das eingegebene Zeichen. Die
Symboleingabe muß mit N/L abgeschlossen werden, worauf das
Programm überprüft, ob das Symbol schon existiert und ob
die Schreibweise korrekt ist. Sollte das Symbol schon zuvor definiert
oder falsch geschrieben worden sein (siehe Symbole), dann kehrt das
Programm in den Grundzustand zurück, andernfalls springt es in
den Codeteil.
Man
muß aber nicht immer Eingaben im Symbolteil machen, sondern
kann ihn überspringen, indem man eine der 3 genannten Tasten
drückt.
-
N/L hat die Wirkung, daß der Inhalt des Symbolteils
überprüft wird.
-
Bei einem Druck auf Blank wird der Inhalt des Symbolteils gelöscht.
-
Der Strichpunkt ermöglicht die Eingabe einer Kommentarzeile.
Codeteil
Sobald
der Codeteil erreicht ist, erscheint die Statusinformation C.
Jetzt entscheidet der erste Tastendruck darüber, ob man eine
Befehlszeile, Marke oder einen Arbeitsspeicher eingibt.
Mit
Blank oder N/L kann man sofort wieder in den Grundzustand
zurückkehren, mit dem Unterschied, daß N/L den
Inhalt des Codeteils wie eine normale Befehlszeile betrachtet und
entsprechend reagiert, während ein Blank sonst nichts bewirkt.
Unterfunktionen
der Eingabefunktion
Zum
Grundzustand sind die Zifferntasten Funktionstasten.
- Rubout.
Die Zeile, auf die der Arbeitszeiger gerichtet ist, wird gelöscht.
- Korrekturfunktion.
Die Zeile, auf die der Arbeitszeiger gerichtet ist, wird im unteren
Bildteil angezeigt und im Listing gelöscht. Man kann sie jetzt
ändern oder auch unverändert wieder eingeben. Das Programm
weiß aber nicht mehr, um was für eine Zeilenart es sich
handelt. so daß man z.B. eine Befehlszeile in einen Kommentar
umwandeln kann und umgekehrt. Um zu verhindern, daß durch die
Autorepeatfunktion aus Versehen mehrere Zeilen gelöscht werden,
arbeitet die Korrekturfunktion nur, wenn das 1. Zeichen des
Codeteils (in der 17. Zeile) ein Blank ist.
- Löschen.
Wenn die Statusinformation L sichtbar ist, kann man eine
beliebige Anzahl Assemblerzeilen ab der Zeile löschen, auf die
der Arbeitszeiger gerichtet ist. Wenn man keine gültige Zahl
oder 0 eingibt, wird nichts gelöscht.
- Die
Statusinformation Z erscheint und man kann den
Arbeitszeiger auf eine beliebige Zeile richten. indem man deren
Adresse (Label) angibt.
- Bei
Druck auf diese Taste wird der Arbeitszeiger um eine bestimmte
Anzahl Zeilen vorgerückt. Bei Programmstart ist diese Zahl auf
16 eingestellt. Man kann sie aber beliebig ändern, indem man
Shift und 4 drückt. Es erscheint die Statusinformation V
und man kann angeben, in welcher Schrittweite ab jetzt vor- und
rückwärts gerückt werden soll.
- Die
Taste 5 entspricht in ihrer Funktion der Taste 4,nur daß eben
rückwärts gegangen wird. Die Statusinformation bei Shift 5
ist R.
- Der
Arbeitszeiger wird um 1 Zeile vorwärts gerückt.
- Es
wird um eine Zeile zurückgegangen.
- Rückkehr
ins Hauptprogramm.
- Ausgabe
an den Drucker und Ausführung der Funktion 4. (Die Schrittweite
wird dazu auf 16 eingestellt.)
Kommentar
Gibt
man im Grundzustand ; ein, verzweigt man damit in die
Eingabe einer Kommentarzeile; was man an der Statusinformation K
sieht. Kommentare sind selbständige Zeilen ohne Label, können
bis 250 Zeichen lang sein und invertierte Zeichen enthalten. Sobald
man N/L drückt, wird der untere Bildschirmteil bis
zum letzten Nicht-Blank als Kommentar angesehen. Eine
Kommentarzeile kann also nicht mit einem Blank aufhören oder aus
lauter Blanks bestehen.
Kommentarzeilen
dienen der Übersichtlichkeit des Listings und haben weder
Einfluß auf die Zeilenadressen noch werden sie nach dem
Assemblieren irgendwo abgelegt. Im Listing sind Kommentare maximal
bis zum 21. Zeichen sichtbar.
Befehlszeilen
Gibt
man im Codeteil weder eine Ziffer noch ein Blank, Dollar-, Pfund-,
Gleichheits- oder Anführungszeichen ein, dann erwartet das
Programm eine Befehlszeile, was es durch die Statusinformation B
anzeigt. Außerdem wird das eingegebene Zeichen sichtbar.
Für
die Eingabe der Mnemonik stehen die ersten 15 Zeichen hinter dem
Symbolteil zur Verfügung. Dieser Platz reicht für jeden
Befehl aus, da Daten und Symbole heechstens 5stellig sein dürfen,
alle Eingaben linksbündig beginnen müßen und keine
Rechenoperatoren erlaubt sind.
Die
richtige Schreibweise der Befehle (wie sie aus der Zusammenfaßung
der Z80-Befehle auf der letzten Seite entnommen werden kann) muß
eingehalten werden sonst wird die Zeile nicht akzeptiert und das
Programm kehrt nach N/L in den Grundzustand zurück.
Jeder
Befehl der Z80-Mnemonik besteht aus 1 bis 3 Kürzeln. Das erste
bezeichnet immer den Befehl, die beiden anderen im allgemeinen
Operatoren, mit denen gearbeitet wird. Hinter dem 1. Kürzel muß
auf jeden Fall ein Blank kommen. Wenn weitere Angaben erforderlich
sind, muß hinter der letzten ebenfalls ein Blank stehen. Bei
Verwendung von 2 Zusätzen müßen diese durch Punkt
oder wahlweise Komma getrennt werden (beliebig).
Der
Codeteil wird bei Befehlszeilen immer bis zum 2. Blank ab dem
Symbolteil interpretiert.
Mnemonikteile,
die eine Zahl darstellen, können immer durch Verwendung eines
Symbols ersetzt werden. Obwohl Symbole immer 16-Bit-Zahlen
darstellen, können sie auch für Befehle mit 8-Bit-Daten
verwendet werden. Wenn z.B. das Symbol ZAHL den Wert $643F hat. dann
wird der Assemblerbefehl LD B,ZAHL so assembliert, daß
nur das Low-Byte (also hier $3F) eingesetzt wird.
Bei
8-Bit-Index-Befehlen dürfen in der Klammer keine Symbole
vorkommen. (Bsp.:LD (IX+DIST),34 geht nicht, aber LD (IX+0),ZAHL)
Eine
Ausnahme machen die relativen Sprünge. Wenn man ein Symbol
angibt (z.B. JR NC,ENDE), dann wird immer angenommen, daß es
sich dabei um das Sprungziel handelt und die notwendige Sprungweite
wird berechnet. (Es wird also nicht - wie bei anderen 8-Bit-Daten -
einfach die niederwertige Hälfte des Symbols eingesetzt.) Ob die
Sprungweite mit einem relativen Sprung möglich ist, oder ob ein
absoluter Sprung nötig ist, zeigt sich, wenn man assemblieren
läßt.
Hat
man einen Befehl richtig eingegeben und die Eingabe mit N/L
abgeschlossen, wird er sofort übersetzt, und ins Listing
eingefügt.
Die
sofortige Befehlscodierung hat einige Vorteile:
-
Syntaxfehler werden sofort erkannt.
-
Der eigentliche Assemblerlauf braucht nur noch die Symbole überprüfen
und ist daher recht schnell (es handelt sich also genaugenommen um
einen 3-Paß-Assembler),
-
Fertig codierte Befehle belegen weniger Speicherplatz als die
Mnemoniks (Bsp.: EX (SP),HL = 10 Bytes, E9 = 1 Byte)
Arbeitsspeicher
Die
übrigen Sonderzeilen sind im wesentlichen Hilfsmittel um
Arbeitsspeicher einzurichten. Da auch Sonderzeilen Labels haben
können, ist es möglich, sie ähnlich zu benutzen wie
die Variablen im Basic. Allerdings muß beim Assembler der
Benutzer selbst die Länge der Variablen kontrollieren.
Frei-Zeile
Wenn
man als erstes Zeichen im Codeteil ein $ oder eine Ziffer
eingibt, erscheint die Statusinformation F und das
Programm erwartet eine Zahl von 1 bis 255. Diese Eingabe ist
vergleichbar mit dem Basic-Befehl DIM, mit dem Unterschied, daß
beim DIM-Befehl der entsprechende Speicherbereich mit Nullen
angefüllt wird, während der Assembler nur einen
Speicherbereich freihält, ohne ihn zu verändern. Im Listing
steht in der entsprechenden Zeile die dezimale und hexadezimale Länge
des eingerichteten Arbeitsspeichers. Beim Assembler sind
Arbeitsspeicher nicht an einen bestimmten Datentyp (Text oder Zahlen)
gebunden, es liegt im Ermeßen des Programmierers, wie die
Speicher benutzt werden.
Im
folgenden Anwendungsbeispiel werden so viele Bytes wie VAR2 angibt,
von der Stelle, die VAR1 angibt, in den Arbeitsspeicher VAR3
geschoben. Nach der Ausführung läßt sich das Ergebnis
mit der Dump- oder Disassembler-Funktion ab VAR3
betrachten.
5000LABEL LD
HL, (VAR1) 2ADF50
5003 LD
DE,VAR3 111250
5006 LD
A,(VAR2) 3A1150
5009 LD
C,A 4F
500A LD
B,0 0600
500C LDIR EDB0
500E RET C9
500FVAR1002=$02 (2-Byte-Variable)
5001VAR2001=$01 (1-Byte-Variable)
5012VAR3255=$FF (255-Byte-Arbeitsspeicher)
Daten
Zeile
Es
ist aber auch möglich, einen Arbeitsspeicher zu definieren und
gleichzeitig festzulegen, was drinstehen soll, indem man entweder das
Pfund- (Daten) oder das Anführungszeichen (Text) drückt
Diese Zeilen entsprechen dann den Basic-Statements LET X=... und LET
X$= ...
Nach
dem Pfundzeichen erscheint die Statusinformation D
(Datenzeile) und es kann eine Zeile mit bis zu 246 Hexzeichen
(0...F) eingegeben werden (also 123 Bytes),
die keinerlei Sonderzeichen wie Blanks oder $ enthalten
darf. Die Zeile wird nicht akzeptiert, wenn man andere Zeichen oder
eine ungerade Anzahl von Zeichen eingibt
Diese
Zeilenart kann man nicht nur als Variablendefinition, sondern auch
als Pseudo-Hexmonitor benutzen, wenn man z.B. einen bestimmten
Maschinencode eintippen und an eine bestimmte Stelle legen möchte.
Es ist ja möglich, beliebig viele Datenzeilen aneinander zu
hängen und mit der Ablegeadresse zu entscheiden, wo dieser Code
dann hingelegt werden soll. Im Listing sind von solchen Zeilen
jeweils max. 10 Bytes sichtbar.
Text-Zeile
Nach
dem Anführungszeichen erscheint die Statusinformation T
und man kann eine 246 Zeichen lange Zeile eingeben, wobei alle
Zeichen erlaubt sind, die über die Tastatur erreichbar sind. Wie
bei Kommentaren wird die Zeile bis zum letzten Nicht-Blank als gültig
angesehen. Im Listing sind von Textzeilen max. 21 Zeichen zu sehen.
Folgendes
Programm, das eine Text- und eine Datenzeile verwendet, löscht
zürst den Bildschirm (durch Aufruf der CLS-Routine, deren
Adresse man mittels einer Marke definieren muß) und schreibt
(mit Hilfe des RST 10) den Text, der im Arbeitsspeicher VAR2 steht
auf den Bildschirm, in der Länge, die in VAR1 angegeben ist.
5000LABEL CALL
CLS CD2A0A
5003 LD
HL,VAR2 211250
5006 LD
BC,(VAR1) ED4B1050
500ALOOP LD
A,(HL) 7E
500B RST
10 D7
500C INC
HL 23
500D DJNZ
LOOP 10FB
500F RET C9
5010VAR1 0012 (Datenzeile)
5012VAR2 DIES
IST EIN TEXT. (Textzeile )
5024;
KOMMENTAR
Rufen
Sie dieses Programm aus dem Basic auf.
Marken
Ein
Gleichheitszeichen zu Beginn des Codeteils ermöglicht die
Definition einer Marke. Dazu muß natürlich im Symbolteil
eine Eingabe gemacht worden sein. Es erscheint die Statusinformation
M und eine Zahl wird erwartet. Wenn man eine Zahl
eingibt, ist damit eine Marke definiert, die sich z.B. als Konstante
oder externes Label (wie im obigen Beispiel CLS) benutzen läßt.
Ändern
und löschen kann man Marken im Hauptprogramm mit der Funktion K.
Programmentwicklung
Der
normale Ablauf einer Programmentwicklung mit ASDIS sieht ungefähr
so aus:
- Laden,
lnitialisieren und Starten von ASDIS.
- Lauf-
und Ablegeadresse einstellen.
- Eingabe
des Programms mit der Eingabefunktion.
- Abspeichern
des Listings.
- Assemblieren
lassen.
- Testlauf
aus Basic und/oder ASDIS.
- Fehlersuche:
eventuell Neuladen des Listings (bei Kassettenversion zuerst ASDIS),
assemblieren, Einzelschrittbetrieb.
- Wiederholung
3. bis 7. bis zur Programmreife, die dann gegeben ist, wenn das
Programm unabhängig von ASDIS läuft.
- Eventuell
Laufadresse neu festlegen.
- Erzeugung
des abspeicherbaren Maschinencodes.
Die
Möglichkeiten, die ASDIS Ihnen bietet, sind umfangreicher, als
sie hier im Detail beschrieben werden können. Deshalb muß
es Ihrer Phantasie überlassen bleiben, für ihre Zwecke das
Beste daraus zu machen. Auf jeden Fall besitzen Sie mit diesem
Programm einen- Assembler, der sich mit Kollegen größerer
Rechner vergleichen kann, ohne rot werden zu müssen. Und die
Geschwindigkeit von Assemblerprogrammen spricht für sich. Das
Verhältnis Assembler zu ZX8I-Basic-lnterpreter ist ca 1:1000 und
das kann selbst vom besten Compiler nicht erreicht werden. Machen sie
den Geschwindigkeitsvergleich:
10
FOR I=1 TO 1000 Während es kein Problem ist, schneller zu
zählen, als dieses
20
PRINT AT 0,13;I Basic-Programm, werden Sie beim folgenden
30
NEXTI Assemblerprogramm kaum mit den Tausendern
mithalten können.
WDHLG CALL
ZAEHL Zählt um 1 hoch.
CALL HALT Fragt die
Break-Taste ab
JR NZ,WDHLG Wiederholung
wenn nicht gedrückt
RET Programmende
ZAEHL
LD HL,(DFILE) Richtet HL auf Anfang Bildspeicher.
LD DE,POSIT
ADD HL,DE Richtet HL
auf kleinste Ziffer.
ZIFER LD
A,(HL) Holt Ziffer in Akku
CP NEUN Kleiner als
9?
JR C, ENDE Wenn ja,
dann letzte Ziffer
LD (HL),NULL
Andernfalls 0 und nächstgrößere.
DEC HL Ziffer
hochzählen
JR ZIFER
ENDE
INC (HL) Ziffer vergrößern.
CP
NULL War sie < 0 ?
RET NC Return wenn
nein.
LD (HL), EINS
Andernfalls Ziffer= 1.
RET
HALT LD
A REIHE Tastenreihe in der Break liegt.
IN A,P0RT Break-Taste
abfragen
BIT 0,A
Zuvor
müsen noch folgende Marken definiert werden
DFILE 400C (Siehe
Handbuch Systemvariablen)
POSIT
beliebig (z.B.13)
NULL 28 (Sinclaircode
für 0)
EINS 29 (Sinclaircode
für 1)
NEUN 37 (Sinclaircode
für 9)
REIHE $7F
andere Werte fragen andere Tastengruppen ab
PORT $FE (Tastatur-Port)
Überblick über
alle Programmfunktionen
(Mit
den Tasten, durch welche sich die Funktionen aufrufen lassen.)
Hauptprogramm
1. Eingabefunktion
im
Grundzustand:
0. Zeile
beschen
1. Zeilenkorrektur
2. mehrere
Zeilen löschen
3. Cursor
auf eine bestimmte Zeile richten
4. Zeiger
vorwärts
Shift
4. Zeiger vorwärts mit Zeilenangabe
5. Zeiger
rückwärts
Shift
5. Zeiger rückwärts mit Zeilenangabe
6. Cursor
eine Zeile vorwärts
7. Cursor
eine Zeile rückwärts
8. Rückkehr
ins Hauptprogramm
9. Ausdrucken
Kommentar
N/L
oder Blank: Codeeingabe ohne Symboleingabe
alles
andere: Symboleingabe und anschließend Codeeingabe im Codeteil:
Blank : Rückkehr
in Grundzustand Eingabe der Zeile
N/L : Eingabe
der Zeile
= : Marke
definieren
: Textzeile
Pfundzeichen : Datenzeile
Dollar
oder Ziffer: Freizeile
alles
andere : Befehlszeile
2.
Dezimale und hexadezimale Darstellung einer Zahl oder eines Symbols.
3.
Daten verschieben
4.
Daten suchen
5.
Inhaltsangabe
6.
Symboländerung
7.
Symbollisting
Shift
7. Symbollisting mit vorherigem Sortieren
8.
Rückkehr ins Basic
9.
Ausgabe des Bildschirminhalts an den Drucker
A.
Assembler
B.
Assemblerlisting in Maschinencode umwandeln
C.
Reverse-Assembler
D.
Disassembler
5.
vorwärts
6.
8 Zeilen vorwärts
7.
70 Bytes rückwärts
8.
Rückkehr ins Hauptprogramm
9.
Ausdruck
E.
Einzelschrittbetrieb
Registermanipulation
5.
(oder Shift 8) Register ändern
6.
Cursor hoch
7.
Cursor runter
8.
Ende der Registermanipulation
5.
mit echten Calls
6.
normal
7.
NOPs
8.
Rückkehr ins Hauptprogramm
9.
Ausdruck
F. Start
eines Maschinenprogramms
8.
Rückkehr ins Hauotprogramm
R.
Start des Maschinenprogramms
G. Blockvergleich
H. Laufadresse
I. Ablegeadresse
J. Dump
6. vorwärts
7. rückwärts
8. Rückkehr
ins Hauptprogramn
9. Ausdruck
K. Markenänderung
5. Änderung
6. weiter
ohne Änderung
7. Marke
löschen
8. Rückkehr
ins Hauptprogramm