*************************************** ***** ***** ***** DDTZ ***** ***** ***** *************************************** Ein Programmentwicklungs- und Fehlersuch-Werkzeug fuer Z80- Mikrocomputer Einfuehrung =========== Das DDTZ ist ein komfortables Werkzeug zum Entwickeln und Austesten von Z80-Programmen, sowie zum Ueberpruefen des Zusam- menwirkens zwischen Programm und Hardware-System. Folgende Komponenten sind im DDTZ enthalten: - Assembler zum Direkt-Eingeben von Programmaenderungen oder kleineren vollstaendigen Programmen in Z80-Assemblersprache. - Disassembler zum Rueck-Uebersetzen von Maschinenprogrammen. - Tracer zum Ausfuehren von Programmen in Einzelschritten und zur Programmausfuehrung mit vorgebbaren Abbruchbedingungen. - Disk Ein/Ausgaberoutinen erlauben das Lesen und Schreiben von Files. - Ausdruck-Interpreter erlaubt bei allen Kommandos die Verwen- dung von arithmetischen und logischen Ausdruecken mit HEX-, Dezimal-, Binaer- und ASCII-Werten, sowie Speicher- und Registerinhalten und Variablen. Das DDTZ laeuft unter dem CP/M-Betriebssystem (Digital Research, ab Version 1.4) und anderen dazu kompatiblen Sys- temen. Es benoetigt eine Z80-CPU und belegt 8,5 KBytes Spei- cher. Da Konsol-Eingaben nur ueber die CP/M-Stringeingabefunktion erfolgen, ist das DDTZ auch mit dem CP/M-Hilfsprogramm XSUB lauffaehig. Der Gebrauch des DDTZ ===================== Der Aufruf ---------- Auf Ihrer DDTZ-Originaldiskette befindet sich die File DDTZ.COM. Bevor Sie diese das erste Mal aufrufen, kopieren Sie bitte die File auf eine andere Diskette, die Sie dann zum Arbeiten benutzen. Bewahren Sie die Originaldiskette an einem sicheren Ort auf und benutzen Sie sie nur zum Anfertigen weiterer Arbeitsdisketten. Verwenden Sie also nie das Original als Arbeitsdiskette. Das DDTZ wird entsprechend den CP/M-Regeln folgendermassen aufgerufen: DDTZ oder DDTZ d:filename.ext Bei beiden Aufrufen laedt das Disk Operating System das DDTZ bei Adresse 100H beginnened in den Speicher. Das DDTZ verlagert sich danach automatisch direkt vor das BDOS und ueberschreibt dabei den CCP. Dadurch wird der Speicher ab 100H fuer das zu untersuchende Programm frei. Der Adressteil des Befehls JP BDOS auf Adresse 5 wird erniedrigt, um dem Anwenderprogramm die durch das DDTZ verringerte Speichergroesse mitzuteilen. Der urspruenglich vom DDTZ belegte Speicher wird daraufhin mit Nullen geloescht. Wurde im Aufruf ein Filename angegeben, so laedt das DDTZ die File in den Speicher. Nach Ausgabe des Prompt-Zeichens '>' ist das DDTZ betriebs- bereit. Die Kommandos ------------- Jede Taetigkeit des DDTZ, z.B. Lesen einer File, Disassemblie- ren eines Programm-Abschnittes usw. wird mit einem Kommando eingeleitet. Kommandos koennen immer dann eingegeben werden, wenn das DDTZ mit dem Prompt-Zeichen '> ' oder '>>' seine Bereitschaft anzeigt. Kommandos beginnen mit einem der Zeichen '@' bis 'Z', eventuell gefolgt von weiteren optionalen Buchstaben, sowie Argumenten. Bei einigen Kommandos sind alle Argumente obligat, d.h. alle Argumente muessen angegebnen werden. Bei anderen Kommandos sind jedoch die Argumente alle oder zum Teil optional, d.h. sie koennen entweder explizit angegeben werden, duerfen aber auch weggelassen werden. Wird eine optionale Anfangsadresse wegge- lassen, so wird die Adresse benutzt, bei der das Kommando zuletzt beendet wurde. Wird eine optionale Endadresse weggelas- sen, so wird das Kommando (z.B. L oder D) so lange ausgefuehrt, bis etwa ein Bildschirm vollgeschrieben ist. Ein weggelassenes optionales Argument, hinter dem weitere Argumente angegeben werden sollen, muss durch ein Komma ersetzt werden. Optionale Elemente sind in den folgenden Kommando-Beschreibungen durch eckige Klammern gekennzeichnet (die Klammern sind also nicht mit einzugeben). Zwischen zwei Argumenten muss ein Blank, ein Tab (^I) oder ein Komma stehen. Argumente werden im allgemeinen als HEX-Zahlen eingegeben, duerfen aber auch als Dezimal- und Binaerzahlen, als ASCII- Werte, Variablen oder in Form arithmetischer Ausdruecke einge- geben werden. HEX-Zahlen sind im DDTZ Zahlen, die aus den Ziffern 0 bis 9 und den Buchstaben A bis F (oder a bis f) bestehen und nicht durch weitere Zusaetze (z.B. Buchstabe H) als HEX-Zahl gekennzeichnet sein muessen. Im Gegensatz zu den meisten Assemblern sind HEX-Zahlen, deren erstes Zeichen ein Buchstabe ist, im DDTZ erlaubt. Dezimal-Zahlen werden zur Unterscheidung mit einem Punkt abgeschlossen und Binaerzahlen tragen am Ende ein doppeltes Anfuehrungszeichen. Naeheres zur Eingabe von Zahlen, Variablen und Ausdruecken finden Sie bei der Beschreibung des H-Kommandos und im Anhang. Bei Kommandos, die eine Start- und eine Endadresse erfordern, kann anstelle der Endadresse auch der Buchstabe 'S', gefolgt von einer Laengenangabe verwendet werden. z.B. bedeutet D 1000 S 100 oder D1000s100 das selbe wie D 1000 10FF oder d1000,10ff Bei allen Eingaben ist es einerlei, ob Gross- oder Kleinbuch- staben verwendet werden. Die einzige Ausnahme ist die Eingabe von ASCII-Zeichen und Zeichenketten. Die Wiederhol-Funktion ---------------------- Beim Gebrauch des DDTZ kommt es oefters vor, dass man einen Befehl nicht nur einmal benutzt und danach einen anderen Befehl anwendet, sondern das man ein und denselben Befehl mehrmals wiederholen will. Moechte man z.B. ein Programm in Einzel- schritten ausfuehren lassen, um nach jedem Schritt die Register zu inspizieren, so waere fuer jeden Schritt die Eingabe eines Trace-Kommandos ohne Argumente notwendig (also der Buchstabe 'T' und die Return-Taste). Ein weiteres Beispiel ist das Ueber- pruefen der Hardware eines Ausgabeports: Will man mit einem Oszilloskop Signale eines Ausgabeports ueberpruefen, so waere es sehr laestig, zur wiederholten Ausgabe eines Testbytes an den Port waehrend der Beobachtung des Oszilloskops immer wieder das 'O'-Kommando eingeben zu muessen. Aus diesen Gruenden besitzt das DDTZ die Wiederholfunktion. Diese bewirkt, dass bei einer leeren Eingabe (nur Return-Taste) das letzte Kommando ohne Argumente wiederholt wird. Die Bereit- schaft der Wiederhol-Funktion wird durch einen doppelten Prompt '>>' anstelle des einfachen '> ' angezeigt. Die Kommandos des DDTZ ====================== Im Folgenden werden alle Kommandos des DDTZ erklaert und mit Beispielen verdeutlicht. Im Bereich der Computertechnik hat es sich international eingebuergert, englische Bezeichnungnen zu benutzen. Deshalb sind auch beim DDTZ die Kommandos Abkuer- zungen englischer Woerter. Diese sind neben einer deutschen Bezeichnung am Anfang jeder Kommando-Erklaerung mit angegeben. Zur Einarbeitung empfiehlt es sich, an dieser Stelle des DDTZ schon einmal zu starten und die im kommenden Abschnitt erklaer- ten Kommandos der Reihe nach auszuprobieren. Assemblieren Sie ein simples Testprogramm mit dem A-Kommando, z.B.: > A100 0100 NOP ld a,0 0102 NOP dec a 0103 NOP jp nz,102 0106 NOP jp 0 0109 NOP . Listen Sie das Programm dann mit dem L-Kommando in disassem- blierter Form aus, setzen Sie einen Breakpoint auf Adresse 0 mit dem B-Kommando und starten Sie es mit dem G-Kommando usw. Nach einigem Ausprobieren und Spielen mit dem DDTZ werden Sie sicher schnell die vielen Moeglichkeiten dieses komfortablen Werkzeugs kennen und nutzen koennen. @ - Anzeigen und eventuell Aendern des Displacement-Registers. (examin [substitude] displacement register @) Der derzeitige Wert wird angezeigt und ein neuer - angefor- dert. Eine leere Eingabe (nur Return-Taste) belaesst den alten Wert. Ein mit dem DDTZ zu bearbeitendes Programm kann natuerlich nur innerhalb des verfuegbaren Adressraums in den Speicher geladen werden, muss also mindestens bei Adresse 100H beginnen und darf sich nicht mit dem DDTZ oder dem System ueberlappen. Um ein Programm, das beispielsweise bei Adresse 0 oder F000H beginnt, zu bearbeiten, muss dieses entsprechend verschoben in den Spei- cher geladen werden. Damit beim Disassemblieren, Modifizieren mit Hilfe des eingebauten Assemblers, Auslisten in HEX/ASCII usw. trotzdem die korrekten Adressen angezeigt werden, ist ein Displacement-Register @ (Verschiebungsregister) vorhanden, dessen Wert auf die Differenz Solladresse minus Ladeadresse gesetzt werden kann. Ist @ ungleich Null, so zeigt das DDTZ ueberall, wo Adressen ausgelistet werden, die Adressen auch in der Form @xxxx an, wobei xxxx die Solladresse des verschobenen Programms ist. Eine andere Anwendungsmoeglichkeit des Displacement-Registers ist das Bearbeiten von Subroutinen, die mit Hilfe eines Linkers in ein Programm eingebunden wurden, und zu denen im Allgemeinen nur ein Listing beginnend ab Adresse 0 vorhanden ist. In diesem Fall wird das @-Register auf die aus der Symboltabelle des Linkers zu entnehmende Anfangsadresse der Routine gesetzt. Jeder Adresse xxxx im Listing entspricht dann die Adresse @xxxx im Speicher. Achtung: Programme, die (ohne Linker) im Speicher verschoben wurden, koennen zwar z.B. disassembliert oder modifiziert, jedoch nicht ausgefuehrt werden. A - Assemblieren von Z80-Befehlen. (Assemble Zilog Z80 mnemonics) Beginnend bei der optionalen Anfangsadresse werden als Z80- Mnemonics eingegebene Befehle direkt in den Speicher assem- bliert. Das DDTZ zeigt jeweils den an dem betreffenden Spei- cherplatz bereits stehenden Befehl zur Kontrolle an, worauf ein neuer Z80-Befehl eingegeben werden oder mit einer leeren Ein- gabe zum naechsten Befehl uebergegangen werden kann. Die Ein- gabe eines Minuszeichens bewirkt ein Ruecksetzen auf den vor- letzten Befehl zur Kontrolle oder Korrektur, ein Punkt beendet das Assemblieren. Die Form der Befehle ist Zilog-kompatibel mit einigen Erweiterungen: Statt ADD A,... SBC A,... usw. koennen auch Kurzformen ADD ... SBC ... usw. benutzt werden. Bei den Befehlen IN A,(ausdruck) und OUT (ausdruck),A koennen die Klammern weggelassen werden. Der Opcode ist von dem Argument durch Tabs oder Blanks ge- trennt. Auf die Adresse des Z80-Befehls kann - wie bei Assemblern ueblich - mittels des $-Zeichens Bezug genommen werden, z.B. ist der Befehl JR Z,$+4 identisch mit JR 204, wenn der Befehl bei Adresse 200 steht. Achtung: Da beim DDTZ HEX-Zahleneingaben ohne fuehrende Dezi- malziffer zulaessig sind, koennen beim Assemblieren Zweideut- igkeiten entstehen oder Fehler unerkannt bleiben, z.B. soll das Register A mit dem Hex-Wert 0B geladen werden, so ist LD A,0B einzugeben, da mit LD A,B das Register B angesprochen wird. Der Befehl LD BC,DE wird als LD BC,0DE interpretiert, da es einen Z80-Befehl, der das BC-Register aus dem DE-Register laedt, nicht gibt. B - Anzeigen aller Breakpoints. (display all breakpoints) Die Adressen, Wiederholungszaehler und Bedingungen aller ge- setzten Breakpoints werden aufgelistet. B breakp [breakp..] ------------------- Breakpoints setzen. (set breakpoints) Zum Austesten eines Programms ist es erforderlich, das Programm nicht nur starten zu koennen, sondern der Ablauf des Programms muss sich auch bequem verfolgen und beobachten lassen. Neben den Tracen (siehe Kommandos T und C) ist das Setzen von Break- points (Unterbrechungspunkten) eine sehr komfortable Moeglich- keit, den Programmablauf zu verfolgen. Ein Breakpoint wird auf das erste Byte (den Opcode) eines Maschinenbefehls gesetzt und bewirkt, dass der Programmablauf unterbrochen wird, sobald der Programmzaehler bei dieser Adres- se angekommen ist. Man kann dann die Registerinhalte inspizie- ren, Speicherinhalte kontrollieren usw., um danach den Pro- grammablauf fortzusetzen oder an einer anderen Stelle fortzu- fahren. Neben der Adresse, die bestimmt, wo der Breakpoint zu setzen ist, koennen noch zusaetzliche Optionen gewaehlt werden. Ein Breakpoint wird in folgender Form definiert: [R] adresse [:zaehler] [I bedingung] Der optionale Buchstabe R bedeutet, dass jedesmal beim Errei- chen des Breakpoints die CPU-Registerinhalte ausgelistet werden sollen, auch dann, wenn wegen eines Zaehlers oder einer Bedin- gung der Breakpoint keinen Programmstopp bewirkt. Die Adresse ist ein beliebiger Ausdruck, der auf einen Opcode zeigen muss. Der Zaehler kann auf einen Wert n<>1 gesetzt werden und be- wirkt, dass jedesmal, wenn die Breakpointadresse durchlaufen wird, der Zaehler um Eins erniedrigt wird und erst beim n-ten Mal ein Programmstop erfolgt. Er steht dann auf 1. Eine Bedingung (der Buchstabe I fuer 'if'='wenn', gefolgt von einem Ausdruck) bestimmt, ob ein Programmstop bzw. ein Dekre- mentieren des Wiederholungs-Zaehlers erfolgen soll. z.B.: > B R 200 I ^A=0 listet jedesmal, wenn Adresse 200 angelaufen wird, die Register aus und unterbricht den Programmlauf, falls das A-Register den Wert 0 hat. > B Y0:16., R $ I0 setzt zwei Breakpoints: 1. Wird 16 mal die Adresse, die in der Variablen Y0 steht, angelaufen, so wird das Programm unterbrochen. 2. Wird die Adresse, auf der der Programmzaehler zum Zeitpunkt der Breakpoint-Eingabe stand, durchlaufen, so werden die Register ausgelistet, aber nicht unter- brochen (Bedingung immer 'falsch'). Um den Benutzer zusaetzliche Eingriffsmoeglichkeiten zu geben, werden alle Breakpoints, auch mit Zaehlern ungleich Null oder unerfuellten Bedingungen, trotzdem aktiv, wenn eine beliebige Taste an der Konsole gedrueckt wird. Wird ein Breakpoint auf eine Adresse gesetzt, auf der sich bereits ein Breakpoint befindet, so wird der bereits vorhandene automatisch geloescht. Achtung: Breakpoints koennen nur im RAM gesetzt werden; in Programmen die in ROM's oder EPROM's enthalten sind, sind Breakpoints nicht moeglich (Siehe folgenden Abschnitt). Interne Breakpointbehandlung des DDTZ: Wird ein Programm mit dem G-Kommando gestartet, so ersetzt das DDTZ alle Opcodes, auf die eine Breakpoint-Adresse zeigt, durch einen Restart-Befehl RST n und bewahrt die Opcodes auf. In die Adresse n, auf die der RST-Befehl springt, wird ein Sprungbe- fehl eingesetzt, der in den Breakpoint-Handler des DDTZ fuehrt. Nach einem Programmstop werden die Opcodes wieder eingesetzt, sodass das Programm immer dann, wenn es dem Benutzer zugaeng- lich ist, unmodifiziert ist. Als RST-Adresse ist 38H voreinge- stellt. Ist die Adresse 38H jedoch fuer andere Zwecke bereits vergeben, so kann der RST-Befehl geaendert werden, z.B. auf 30H: > AT4 xxx9 RST 38 rst 30 xxxA xxx . BX -- Loeschen aller Breakpoints. (clear all breakpoints) BX adresse [adresse..] ---------------------- Loeschen der Breakpoints an den angegebenen Adressen. (clear breakpoints) C[N][J] ]befehlsanzahl] C[N][J] W ausdruck C[N][J] U ausdruck ------------------ Tracen ueber CALLs [ohne Ausgabe] [nur Sprungbefehle] / ..solange.. / ..bis.. (trace over CALLs [No list] [Jumps only] /..While../..Until.. Tracen wie mit dem T-Kommando, nur mit dem Unterschied, dass eine Subroutine wie ein einzelner Maschinenbefehl gehandhabt wird. Bei jedem CALL-Befehl wird also die aufgerufene Routine in Echtzeit abgearbeitet und erst bei Erreichen des auf den CALL-Befehl folgenden Befehls wird wieder in den Trace-Modus zurueckgekehrt. (siehe T-Kommando). Achtung: Das C-Kommando funktioniert nur dann, wenn die Subrou- tine nach ihrer Beendigung zu der auf den CALL-Befehl folgenden Adresse zurueckkehrt. Ein Programm der Form CALL SUBR DB ARG mit einer Routine SUBR, die nach Abarbeitung hinter dem Argu- ment ankommt, kann nicht mit C bearbeitet werden. D [startadr] [endadr] --------------------- Auslisten des Speichers in HEX und ASCII (Display memory in hex and ASCII) Der Speicher-Inhalt wird beginnend bei der Startadresse bis zur Endadresse in HEX und ASCII auf der Konsole ausgelistet. Die ASCII-Anzeige ignoriert das Bit 7 des jeweiligen Bytes. Ist der Wert eines Bytes nicht als ASCII-Zeichen druckbar, so wird statt dessen ein Punkt ausgegeben. F-Kommandozeile --------------- File-Cointrolblock und CP/M-Kommandozeile spezifizieren. (specify Filename and command line) Dieses Kommando hat zwei Anwendungen: 1. Vor einem Einlesen oder Ausschreiben einer File vom DDTZ aus wird mit dem F-Kommando der Filename angegeben. z.B. Einlesen eines zu testenden Kopier-Programms mit dem Namen 'COPY.COM' von der Diskette A: > Fa:copy.com > R 2. Soll ein Programm ausgetestet werden, das beim Aufruf vom CP/M aus eine Kommandozeile im Kommandopuffer bei 80H und File-Control-Blocks bei 5CH und 6CH erwartet, so kann mit dem F-Kommando des DDTZ der CP/M-Aufruf simuliert werden. z.B. Das im obigen Beispiel eingelesene Programm soll so ab- laufen als sei es vom CP/M aus mit dem Aufruf A>COPY A:DESTIN.*=B:SOURCE.* gestartet worden. Die Kommandozeile wird deshalb vor dem Programmablauf mit > FA:DESTIN.*=B:SOURCE.* eingegeben. G [startadr] [;breakp..] ------------------------ Starte ein geladenes Programm, eventuell mit temporaeren Breakpoints. (Go [to start] [with temporary breakpoints]) Wird eine Startadresse angegeben, so wird der Programmzaehler des Z80 auf diese Adresse gesetzt, andernfalls wird bei dem letzten Programmzaehlerstand fortgefahren. Im G-Kommando koen- nen temporaere Breakpoints angegeben werden. Sie werden in der gleichen Form wie die permanenten Breakpoints beim B-Kommando spezifiziert und haben auch die gleiche Wirkung mit dem Unter- schied, dass bei einem Programmstop an einem der temporaeren oder permanenten Breakpoints die temporaeren automatisch ge- loescht werden. z.B. Vollstaendiges Abarbeiten eines CP/M-Programms, das mit JP 0 endet: > GL;0 H - Groesse und maximale Groesse von Files anzeigen. (display High and maximal size of files) Die hoechste von der zuletzt eingelesenen File belegte Adresse wird angezeigt, sowie die hoechste von irgendeiner der einge- lesenen Files belegte Adresse. Erstere ist auch in der Varia- blen H, letztere in der Variablen M enthalten. (Siehe auch W- und R-Kommando) H ausdruck H ausdruck ausdruck ------------------- Berechnen eines Ausdrucks / Summe und Differenz zweier Ausdrucke. (compute expressions / Hex and other sum and difference) Wird ein Ausdruck angegeben, so zeigt das DDTZ dessen Ergebnis an, werden zwei Ausdruecke angegeben, so werden deren Summe und Differenz angezeigt. Ergebnisse werden in HEX, als negative HEX-Zahl, in Dezimal, als negative Dezimalzahl, in Binaer und das niederwertige Byte zusaetzlich als ASCII-Zeichen darge- stellt. Nicht druckbare ASCII-Zeichen werden dabei als Control- Zeichen in der Form Buchstabe minus '@' angezeigt. Wie Ausdruecke formuliert werden, ist der Uebersichtlichkeit halber im Anhang angegeben. z.B.: Was ist die Endadresse eines 17 KByte langen Programms, das bei Adresse 100H beginnt? > H17.*1024.+100 4500 -BB00 17664. -47872. 01000101"00000000" '@'-'@' Der freie Speicher beginnt also bei 4500H. z.B.: Beim Disassemblieren eines unbekannten Programms wird eine Subroutine gefunden, die nacheinander mit den Werten D8F0H, FC18H, FF9CH usw. in den Registern aufgerufen wird. Was kann das fuer eine Routine sein? > HD8F0 D8F0 -2710 55536. -10000. 11011000"11110000" 'p'. > H fc18 FC18 -03E8 64536. -1000 11111100"00011000" 'X'-'@' > H FF9CH FF9C -0064 65436. -100 ... Bei den Werten handelt es sich offenbar um dezimal - 10000, -1000 usw.; die Routine hat also wahrscheinlich etwas mit einer Binaer-zu-Dezimal-Umrechnung zu tun. I [port] -------- Einlesen eines Daten-Bytes von einem Port. (input a byte from port) Zum Austesten der Computer-Hardware koennen mit diesem Kommando Bytes von Ports eingelesen und in HEX und binaer angezeigt werden. Wird die Portadresse nicht angegeben, so wird der zuletzt in einem frueheren I-Kommando angegebene Port ange- sprochen. Die Moeglichkeit, bei Z80-I/O-Befehlen hardwareseitig auch die Adressleitungen A15 bis A8 zur Informationsuebertra- gung mitzuverwenden, ist im DDTZ realisiert. DDTZ-intern wird die Portadresse als Zwei-Byte-Wort in das BC-Register geladen und mit IN A,(C) der Port gelesen. Bei diesem Kommando zeigt zeigt sich besonders der Vorteil der Wiederholungsfunktion des DDTZ: Nachdem einmal das I-Kommando explizit gegeben wurde, kann man, waehrend man verschiedene Pegel an die Anschluesse des Ports anlegt, durch einfaches Druecken der Return-Taste die Portabfrage wiederholen. L [startadr] [endadr] --------------------- Listen eines Speicherbereichs in Z80-Mnemonics. (List disassembled code) Dieses Kommando disassembliert im Speicher stehende Programme. (Beispiel: siehe Q-Kommando) M[V] startadr endadr zieladr ---------------------------- Umladen eines Speicherbereichs in einen anderen, eventuell ver- gleichen. (Move memory [and verify]) Der Speicherinhalt beginnend bei der angegebenen Startadresse bis (einschliesslich) zur angegebenen Endadresse wird in einen anderen Bereich, beginnend bei der angegebenen Zieladresse, kopiert. Wird der optionale Buchstabe V gegeben, so wird die Kopie mit dem Original verglichen und etwaige Diffrenzen in HEX ausgelistet. Differenzen koennen bei defektem Speicher ent- stehen oder dann, wenn versehentlich in Bereiche kopiert wird, die kein RAM enthalten. Das M-Kommando wird auch dann korrekt ausgefuehrt, wenn der Quell- und der Zielbereich gegenseitig ueberlappen. In diesem Fall ist ein Vergleichen allerdings nicht moeglich, da beim Kopieren ja ein Teil des Quellbereichs ueberschrieben wird. Achten Sie bei diesem Kommando besonders darauf, dass Sie nicht das DDTZ oder das Disk Operating System versehentlich ueber- schreiben. O [byte] [port] --------------- Ausgeben eines Datenbytes an einen Ausgabeport. (Output a byte to a port) Zum Austesten der Computer-Hardware koennen mit diesem Kommando Bytes an Ports des Computersystems ausgegeben werden. Achtung: Im Gegensatz zu dem Z80-Befehl OUT port,byte ist hier aus folgendem Grund erst das Datenbyte und dann die Portadresse anzugeben: Die Portadresse kann weggelassen werden, falls ein Datenbyte an den selben Port, wie in einem vorherigen O-Kommando spezifi- ziert, ausgegeben werden soll. Die Moeglichkeit, bei Z80-I/O-Befehlen hardwareseitig auch die Adressleitungen A15 bis A8 zur Informationsuebertragung mitzu- verwenden, ist im DDTZ realisiert. DDTZ-intern wird die Port- adresse als Zwei-Byte-Wort in das BC-Register geladen und mit OUT (C),A das Byte an den Port ausgegeben. Q[J] startadr endadr bytes -------------------------- Durchsuchen des Speichers nach einer gegebenen Folge von Bytes. (Query memory for a byte string [justified]) Der Speicher wird beginnend bei der angegebnen Startadresse und endet (einschliesslich) bei der angegebenen Endadresse auf eine angegebene Byte-Folge hin durchsucht. Fundstellen werden wie beim D-Kommando in HEX und ASCII ausgelistet. Das erste ge- suchte Byte steht dabei jeweils am linken Bildrand. Wird der optionale Buchstabe J gegeben, so werden jeweils noch 8 vorher- gehende Bytes mit ausgelistet, sodass die gesuchte Byte-Folge in der Bildmitte beginnt. Die Byte-Folge kann wie beim S- Kommando eine Folge von HEX-Zahlen, Ausdruecken, Worten und Text-Strings sein. z.B. Ein zu untersuchendes Programm gibt an einem bestimmten Punkt seines Ablaufes aus unbekannter Ursache die Meldung "Hardware error" auf die Konsole aus und stoppt. Woher kommt diese Meldung ? > QJ l h 'Hardwar' 1502 73 74 65 64 24 4E 6F 20 48 61 72 64 77 61 ... Der Text "Hardware error beginnt also bei Adresse 150A. Wo wird er ausgegeben ? > QJ l h w150a > (Keine Meldung) Auf die Adresse wird also nicht direkt zugegriffen. Vielleicht haben wir Glueck, indem wir suchen, wo 'No Hardware error" ausgegeben wird. Dieser Text beginnt bei 1507H. > QJ l h w1507 08FE 00 00 00 00 00 AF C9 21 07 15 CD 65 07 30 ... > L8FE+7 0905 LD HL,1507 0908 CALL 0765 090B JR NC,0910 090D INC HL 090E INC HL 090F INC HL 0910 CALL 0654 Die Subroutine, die bei Adresse 908 aufgerufen wird, fuehrt also offenbar einen Test durch und meldet einen Fehler im Carry-Flag. Der Text wird dann bei Adresse 910 ausgegeben. R [displacement] ---------------- Einlesen einer Binaer- oder HEX-File in den Speicher, eventuell verschoben. (Read a binary or hex file [add displacement]) Eine File, deren Name mit dem F-Kommando spezifiziert worden sein muss, wird von der Diskette in den Speicher eingelesen. Eine File, deren Name mit ".HEX" endet, wird als Intel-HEX-File interpretiert; die Daten werden bei den in der File enthaltenen Adressen im Speicher abgelegt. Jede andere File wird ohne jede weitere Interpretation bei Adresse 100H beginnend in den Spei- cher geladen. Wird im R-Kommando ein Displacement angegeben, so wird eine HEX-File bei der entsprechenden Adresse erhoeht um das Dis- placement abgelegt, andere Files bei 100H+Displacement. Nach dem Einlesen der File wird erst die hoechste von dieser File belgte Speicheradresse ausgelistet und dann die hoechste von irgendeiner File seit Starten des DDTZ belegte Adresse. Falls das DDTZ statt dessen ein Fragezeichen ausgibt, konnte entweder die File nicht gefunden werden, beim Lesen einer HEX-File wurde ein Checksummenfehler entdeckt, oder die File belegt Speicher- plaetze ausserhalb des Bereichs L bis T. z.B.: Eine File TEST.BIN soll bei Adresse 2000H beginnend in den Speicher geladen werden: > Ftest.bin > R2000-l High = 277F Max = 277F S [startadr] ------------ Anzeigen und Aendern von Daten im Speicher (Substitute memory) Die Startadresse, oder wenn diese nicht angegeben wurde, die Adresse bei der das letzte S-Kommando beendet wurde, wird auf der Konsole ausgegeben, und danach wird das an dieser Stelle im Speicher befindliche Byte in HEX angezeigt. Anschliessend erwartet das DDTZ eine Eingabe, und zwar gibt es folgende Moeglichkeiten: - Eine leere Eingabe (nur Return-Taste) schreitet ohne Spei- cheraenderung zur naechsten Adresse weiter. - Ein Minus-Zeichen geht ohne Speicheraenderung einen AdressSchritt zurueck. - Ein Punkt (alleine in einer Zeile) beendet das Kommando. - Ein Datenbyte oder eine Folge von von Datenbytes wird in den Speicher eingetragen. Datenbytes koennen folgendermassen eingegeben werden: - Ausdruecke (im einfachsten Fall HEX-Zahlen) werden der Reihe nach berechnet und eingetragen. - W ausdruck berechnet den Ausdruck als Zwei-Byte-Wort und traegt ihn in zwei Speicher-Bytes ein; erst das niederwer- tige, dann das hoeherwertige Byte. - Ein Apostroph, gefolgt von ASCII-Zeichen und einem weiteren Apostroph bewirkt ein Eintragen einer ASCII- Zeichenfolge. Kommt der Apostroph selbst in der Zeichen- folge vor, so muss er zweimal gegeben werden. Folgt auf den abschliessenden Apostroph ein Punkt, so wird das Bit 7 des letzten Zeichens auf Eins gesetzt. z.B. der Programmteil 0200 CALL 1234H 0203 DM 'Test ''1''' ; Test '1' kann mit dem S-Kommando folgendermassen eingegeben werden: > S200 0200 00 cdW1234 0203 00 'Test ''1'''. 020B 00 - 020A A7 . T[N][J] ]befehlsanzahl] T[N][J] W ausdruck T[N][J] U ausdruck ------------------ Tracen [ohne Ausgabe] [nur Sprungbefehle] / ..solange.. / ..bis.. (Trace [no list] [Jumps only] / ..While.. / ..Until..) Im Gegensatz zum Starten eines Programms mit dem G-Kommando, bei dem die Kontrolle voll dem auszufuehrenden Programm ueber- geben wird und erst bei einem Breakpoint dem DDTZ zurueckge- geben wird, behaelt beim Tracen das DDTZ die ganze Zeit die Kontrolle. Das wird dadurch erreicht, dass das DDTZ automatisch hinter jedem Befehl, bevor er ausgefuehrt wird, einen Break- point einsetzt und nach Ausfuehrung des Befehls wieder loescht. Bei bedingten Spruengen werden sogar zwei Breakpoints gesetzt, einer hinter dem Sprungbefehl, der andere am Sprungziel. Das Programm wird also in Einzelschritten ausgefuehrt. Nach jedem Schritt legt das DDTZ die aktuellen Werte aller Register in Speicherplaetze innerhalb des DDTZ ab, sodass die Register- inhalte jederzeit ueberwacht werden koennen. Das Tracen beginnt jeweils beim derzeitigen Stand des Programm- zaehlers. Soll an einer anderen Stelle mit dem Tracen begonnen werden, so muss der Programmzaehler mit dem X-Kommando neu gesetzt werden. Nach jedem Schritt werden alle Registerinhalte und der naechste Z80-Befehl wie beim X-Kommando angezeigt. Die einfachste Form des T-Kommandos ist nur der Buchstabe T (gefolgt von der Return-Taste), worauf ein Einzelschritt ausge- fuehrt wird. Falls das letzte Kommando bereits ein T-Kommando war, genuegt wegen der Wiederholfunktion des DDTZ auch die Return-Taste alleine, was das Einzelschritt-Tracen sehr er- leichtert. Wird im T-Kommando eine Befehlsanzahl angegeben, so werden entsprechend viele Schritte hintereinander ausgefuehrt. In diesem Fall kann, wie auch bei dem im Folgenden erlaeuterten Tracen mit Abbruchkriterium, der Trace-Vorgang durch Druecken einer beliebigen Taste der Konsole vorzeitig abgebrochen werden. Das Tracen wird unabhaengig von einer angegebenen Befehlsanzahl oder Bedingung abgebrochen, wenn ein Breakpoint erreicht wird. Wird der Buchstabe W, gefolgt von einem Ausdruck angegeben, so wird das Programm solange im Trace-Modus abgearbeitet, wie der Ausdruck 'wahr' ist, d.h. vor jedem Schritt wird der Ausdruck berechnet und nur dann fortgefahren, wenn er ein von Null ver- schiedenes Ergebnis hat. Wird der Buchstabe U, gefolgt von einem Ausdruck angegeben, so wird das Tracen dann abgebrochen, wenn der Ausdruck ein von Null verschiedenes Ergebnis hat. Bei allen Formen des T-Kommandos kann man durch Angabe des Buchstaben N das Auslisten der Register abschalten, was die Ausfuehrungszeit erheblich verkuerzt. In diesem Fall werden nur beim Beenden des Trace die Registerinhalte angezeigt. Die Angabe des Buchstabens J veranlasst das DDTZ, nur hinter Befehle, die den Programmzaehler beeinflussen, Breakpoints zu setzen, also bei den Befehlen JP,JR,CALL,RET. Es werden dann auch nur bei diesen Befehlen die Registerinhalte angezeigt und ein Abbruchkriterium geprueft. Achtung: Da die Einzelschritt-Abarbeitung durch automatisches Setzen von Breakpoints erreicht wird, ist es unmoeglich, Pro- gramme in ROMs zu tracen. Subroutinen in ROMs koennen mit dem G-Kommando und geeigneten Breakpoints oder mit dem C-Kommando uebersprungen werden. Falls Teile des BIOS in ROMs stehen, stoert dies nicht, solange das zu untersuchende Programm nur BDOS-Aufrufe enthaelt. Bei BDOS-Aufrufen wird der Trace-Modus verlassen und erst nach der Rueckkehr aus dem BDOS wieder aufgenommen. z.B.: > TNU(1234)='A' traced das Programm ohne Registeranzeige, bis der Spei- cherplatz 1234H das ASCII-Zeichen A enthaelt. > TJW[^hl=0]&[^a<80] traced die Sprungbefehle, solange das HL-Register Null ist und das A-Register kleiner als 80H ist. V startadr endadr zieladr ------------------------- Vergleichen zweier Speicherbereiche. (Verify (compare) two memory areas) Der Inhalt des Speichers beginnend bei der angegebenen Start- adresse bis (einschliesslich) zur angegebenen Endadresse wird mit dem Inhalt eines gleich langen Bereichs beginnend bei der angegebenen Zieladresse verglichen. Unterschiede werden in HEX ausgelistet. Das Auslisten kann durch Druecken einer beliebigen Taste der Konsole abgebrochen werden. W startadr endadr ----------------- Ausschreiben eines Speicherbereichs in eine File. (Write a file to disk) Der Inhalt des Speichers beginnend bei der angegebenen Start- adresse bis (einschliesslich) zur angegebenen Endadresse wird in eine File auf der Diskette geschrieben. Der Filename muss vorher mit dem F-Kommando spezifiziert werden. Die Laenge des abgespeicherten Bereiches wird vom DDTZ auf volle Saetze aufge- rundet. z.B.: In ein Programm namens PROG-ALT.COM sollen Aenderungen, die in einer File PATCH.HEX enthalten sind, eingefuegt werden, und das modifizierte Programm soll in einer File namens PROG-NEU.COM auf Diskette B: abgelegt werden: > Fprog-alt.com > R High = 257F Max = 257F > Fpatch.hex > R High = 2345 Max = 257F > Fb:prog-neu.com > Wl m X - Anzeigen aller Register und des Befehls, auf den der Programm- zaehler zeigt. (eXamine all cpu registers) Jedesmal, wenn ein Breakpoint angelaufen wird oder ein Pro- grammschritt getraced wird, legt das DDTZ die Registerinhalte in einem innerhalb des DDTZ befindlichen Speicherbereich ab. Wird mit G oder T die Ausfuehrung des Programms fortgesetzt, so laedt das DDTZ vorher diese Daten wieder in die Register. Mit dem X-Kommando koennen diese abgespeicherten Registerinhalte jederzeit kontrolliert werden. Die Anzeige erfolgt, wie immer im DDTZ, in HEX. Die sechs gueltigen Bits des F- und des F'-Registers werden als Buchstaben dargestellt. Das Interrupt-Flag wird wie ein Bit des F-Registers angezeigt. Der Z80-Befehl, auf den der Programmzaehler zeigt, wird in dis- assemblierter Form ausgegeben. Falls das Displacement-Register @ von Null verschieden ist, wird der Programmzaehler auch relativ dazu angezeigt. z.B. Das Displacement-Register enthalte den Wert F00H, alle Flags seien gesetzt, der Interrupt sei eingeschaltet und die Register enthalten willkuerliche Werte: > X SZHVNCE A =12 BC =3456 DE =789A HL =BCDE SP=F012 PC=3456.. SZHVNC A'=78 BC'=9ABC DE'=DEF0 HL'=1234 IX=5678 IY=9ABC.. Nach einem Neustart des DDTZ enthalten die Register folgende Werte: E A =00 BC =0000 DE =0000 HL =0000 SP=AC00 PC=0100.. A'=00 BC'=0000 DE'=0000 HL'=0000 IX=0000 IY=0000.. Das Interrupt-Enabled-Flag ist gesetzt, falls beim Start des DDTZ der Interrupt eingeschaltet war. Das I-Register enthaelt den Wert, den es beim Start des DDTZ enthielt. Der Programm- zaehler steht auf 100H, zeigt also auf den Anfang des Benutzer- speichers. Der Stackpointer zeigt auf das obere Ende des Be- nutzerspeichers, abgerundet auf volle 100H. Alle anderen Re- gister enthalten Nullen. X register ---------- Anzeigen und eventuell modifizieren eines Registers. (eXamine [and substitute] a register) Nach Eingabe des Buchstabens X, gefolgt von einem Register- namen, wird der betreffende Registerinhalt ausgegeben und ein neuer Wert angefordert. Eine leere Eingabe (nur Return-Taste) laesst den Registerinhalt unveraendert; ein eingegebener Wert oder Ausdruck wird in das Register eingetragen. Ist das ange- waehlte Register das F- oder F'-Register, so werden die Flags als Buchstaben angezeigt. Daraufhin koennen durch Eingabe neuer Buchstaben in beliebiger Reihenfolge die entsprechenden Flags gesetzt werden, wobei nicht gegebene Flags zurueckgesetzt werden. Das Interrupt-Flag wird im DDTZ wie ein Flag des F- Registers behandelt. Die Namen der Register und der Flags der F-Register sind im Anhang aufgelistet. z.B. Setzen des HL-Registers auf ABCDH, des C-Registers auf den ASCII-Wert 'A', und Setzen des Carryflags des F-Registers und des Interrupt-Flags: > Xhl HL=1234 abcd > Xc C=40 'A' > Xf S VNCE ce Y - Anzeigen aller Y-Variablen. (examine all Y variables) Beim Untersuchen eines Programms ist es vielfach von Vorteil, wenn man bestimmte Adressen, Registerstaende, Zwischenergebnis- se bei Berechnungen usw. festhalten kann und bei weiteren Berechnungen oder DDTZ-Kommandos als Argumente einsetzen kann. Fuer diesen Zweck haelt das DDTZ zehn frei verfuegbare Varia- blen bereit, die mit Y0 bis Y9 bezeichnet sind. Die derzeitigen Werte in diesen Variablen koennen mit dem Y-Kommando angezeigt werden. z.B. Nach dem Starten des DDTZ enthalten die Y-Variablen alle den Wert Null: > Y Y0=0000 Y1=0000 Y2=0000 Y3=0000 Y4=0000 Y5=0000 Y6=0000 Y7=0000 Y8=0000 Y9=0000 Yziffer0bis9 ------------ Anzeigen und eventuell Modifizieren einer Y-Variablen. (examine [and substitute] an Y variable) Nach Eingabe des Buchstabens Y, unmittelbar gefolgt von einer Ziffer 0 bis 9, wird der derzeitige Wert der berteffenden Y- Variable angezeigt und ein neuer Wert angefordert. Eine leere Eingabe (nur Return-Taste) laesst den Wert unveraendert, ein angegebener Wert wird in die Variable eingetragen. z.B. Ein File-Control-Block (33 Bytes lang), auf den zur Zeit das DE-Register zeigt, soll im weiteren Verlauf eines Programmtests oefters inspiziert werden. Statt sich den Stand des DE-Registers zu merken oder zu notieren und immer wieder einzugeben, kann er in eine Variable, z.B. Y1, eingetragen werden: > Y1 Y1=0000 ^de Mit D y1 s 33. oder dy1s21 kann jetzt jederzeit der File- Control-Block angesehen werden. Z startadr endadr bytes ----------------------- Vorbesetzen eines Speicherbereiches mit einer Byte-Folge. (Zap (fill) memory with a byte string) Der Speicher wird beginnend bei der angegebenen Startadresse bis (einschliesslich) zur angegebenen Endadresse mit der ange- gebenen Bytefolge belegt. Die Bytefolge wird genauso wie beim S-Kommando angegeben. Ist sie kuerzer als der zu besetzende Speicher, so wird die Bytefolge wiederholt, bis die Endadresse erreicht ist. z.B. Loeschen des gesamten Benutzerspeichers mit Nullen: > Z l t 0 z.B. Fuellen eines bei der Adresse 1000H beginnenden, 10H Bytes langen Puffers mit dem Text 'leer!', Carriage Return, Linefeed: > Z1000s10 'leer!',d,a > D1000s12 1000 6C 65 65 72 21 0D 0A 6C 65 65 72 21 0D 0A 6C.. 1010 00 00 .. z.B. Durchfuehren eines einfachen Speichertests: Erst wird der gesamte Benutzerspeicher mit einer krummen Anzahl, z.B. sieben, Testbytes gefuellt und dann der Speicher mit sich selbst, um die Laenge der Testbytefolge verschoben, ver- glichen: > Zl t 0 ff aa 55 a5 5a 0f > Vl t-7 l+7 ANHANG ====== Zusammenfassung der Kommandos ----------------------------- > @ examine [substitute] displacement register @ Anzeigen und eventuell Aendern des Displacement-Registers > A [startadresse] Assemble Zilog Z80 mnemonics Assemblieren von Z80-Befehlen > B display all breakpoints Anzeigen aller Breakpoints > B breakp [breakp..] set breakpoints Breakpoints setzen > BX clear all breakpoints Loeschen aller Breakpoints > BX adresse [adresse..] clear breakpoints Breakpoints loeschen >>C[N][J] [befehlsanzahl] >>C[N][J] W ausdruck >>C[N][J] U ausdruck trace over calls [No list] [Jumps only] /.While./.Until. Tracen ueber CALLs [ohne Ausgabe] [nur Sprungbefehle] /.solange./.bis. >>D [startadr] [endadr] Display memory in hex and ASCII Auslisten des Speichers in HEX und ASCII > Fkommandozeile specifiy filename and command line File-Controlblock und CP/M-Kommandozeile spezifizieren > G [startadr] [;breakp..] Go [to start] [with temporary breakpoints] Starte ein geladenes Programm, eventuell mit temporaeren Breakpoints > H display High and maximal size of files Groesse und maximale Groesse von Files anzeigen > H ausdruck compute hex and other expressions Berechnen eines Ausdrucks > H ausdruck ausdruck Hex and other sum and difference Summe und Differenz zweier Ausdruecke >>I [port] Input a byte from port Einlesen eines Daten-Bytes von einem Port >>L [startadr] [endadr] List disassembled code Listen eines Speicherbereichs in Z80-Mnemonics > M[V] startadr endadr zieladr Move memory [and verify] Umladen eines Speicherbereiches in einen anderen, evtl. Vergleichen >>O [byte] [port] Output a byte to a port Ausgeben eines Datenbytes an einen Ausgabeport > Q[J] startadr endadr bytes Query memory for a byte string [Justified] Durchsuchen des Speichers nach einer gegebenen Folge von Bytes > R [displacement] Read a binary or hex file ]add displacement] Einlesen einer Binaer- oder HEX-File in den Speicher, evtl. verschoben > S [startadr] Substitute Memory Anzeigen und Aendern von Daten im Speicher >>T[N][J] [befehlsanzahl] >>T[N][J] W ausdruck >>T[N][J] U ausdruck Trace [no List] [Jumps only] / .While. / .Until. Tracen [ohne Ausgabe] [nur Sprungbefehle] /.solange./.bis. > Vstartadr endadr zieladr Verify (compare) two memory areas Vergleichen zweier Speicherbereiche > Wstartadr endadr Write a file to disk Ausschreiben eines Speicherbereichs in eine File > X eXamine all cpu registers Anzeigen aller Register und des Befehls, auf den der Pro- grammzaehler zeigt > X register eXamine [and substitute] a register Anzeigen und eventuell Modifizieren eines Registers > Y examine all Y variables Anzeigen aller Y-Variablen > Yziffer0bis9 examine [and substitute] an Y variable Anzeigen und eventuell Modifizieren einer Y-Variablen > Z startadr endadr bytes Zap (fill) memory with a byte string Vorbesetzen eines Speicherbereiches mit einer Byte-Folge Registernamen ------------- A , F , B , C , D , E , H , L ,BC , DE , HL A', F', B', C', D', E', H', L',BC', DE', HL' IX oder X , IY oder Y , Sp oder S , PC oder P , I Flags des F- und des F'-Registers: S Sign Vorzeichen Z Zero Null H Half carry Uebertrag von Bit 3 nach Bit 4 V oVerflow/parity Ueberlauf/ gerade Paritaet N Negation NEG, DEC, SUB o.ae. wurde ausgefuehrt C Carry Uebertrag von Bit 7 E Interrupt Enabled Das Interrupt-Flag wird im DDTZ wie ein Flag des F-Registers behandelt. Variablen und Konstanten ------------------------ L Low Benutzerspeicher-Anfang. Festwert 100H H High Hoechste Adresse der letzten gelesenen File M Max Maximale Adresse aller gelesenen Files T Top Oberes Ende des Benutzerspeichers @ Displacement Register $ beim Assemblieren Anfangsadresse des Befehls sonst = PC Y0..Y9 Frei verwendbare Variablen ^register Inhalt eines Registers (adresse) Inhalt eines Speicherplatzes (Byte) (adresse). Inhalt eines Speicherplatzes (Wort) Ausdruecke ---------- In allen Situationen, in denen Zahlen eingegeben werden koen- nen, ist auch die Eingabe von Ausdruecken erlaubt. Ausdruecke sind im allgemeinen arithmetische Ausdruecke, koen- nen aber auch (zum Formulieren von Bedingungen) Relationen sein. Relationen bestehen aus zwei arithmetischen Ausdruecken, zwischen denen einer der folgenden Relationsoperatoren steht: = <> > >= <= < Relationen haben den Wert -1 (=0FFFFH), wenn die Relation wahr ist, 0 sonst. z.B. der Ausdruck 1+2=3 hat den Wert -1, und 'A'>'B' den Wert 0 Ein arithmetischer Ausdruck hat die folgende Form faktor arithmetikoperator faktor arith... faktor Die Arithmetikoperatoren sind + - * / % Addition, Subtraktion, Mult., Division, Modulo & ! # bitweise AND, OR, XOR Ein Faktor hat die Form [ausdruck] geklammerter Ausdruck +faktor -faktor Negation ~faktor bitweise NOT (1er-Komplement) 'a' Wert eines ASCII-Zeichens (a=druckbares Zeichen) 'a'. " mit gesetzem Bit 7 'ab' Wert zweier ASCII-Zeichen (a,b=druckbare Zeichen) 'ab'. " das niederwertige Zeichen mit gesetztem Bit 7 (ausdruck) ein Byte im Speicher (ausdruck). ein Wort im Speicher hhhh[H] Hex-Zahl (h=0..9,A..F oder a..f) ddddd. Dezimal-Zahl (d=0..9) bbbbbbbb"bbbbbbbb" Binaer-Zahl (beliebig mit '"' unterteilt (b=0,1) Enthaelt ein Ausdruck einen Relationsoperator, so werden erst die beiden arithmetischen Ausdruecke berechnet und dann die Relation. Ein arithmetischer Ausdruck wird von links nach rechts be- rechnet, also ohne Beachtung "Punktrechnung vor Strichrech- nung", die Reihenfolge kann jedoch mit Klammern '[' und ']' geaendert werden. Ein Pluszeichen darf, wenn dabei der Ausdruck eindeutig bleibt, weggelassen werden; z.B. ist @1000 dasselbe wie @+1000. Ausdruecke duerfen keine Leerzeichen enthalten!