CALMMAKR.DOK CALM-Makros 1 Einleitung Makros werden vom Makropräprozessor behandelt. Die Eingangsdatei enthält Programmtext und Makros, die zu expandieren sind. Der Makropräprozessor ist Teil des aktuellen CALM-Assemblers und kann mit ASCALM Datei/R/V/C emuliert werden (z.B. alle Makros entfernen). 1.1 Einsatz von Makros Der Assemblerprogrammierer trifft oft auf sich wiederholende Gruppen von Befehlen. Durch Verwendung eines einzigen Befehls, genannt Makrobefehl, der mehrere Assemblerbefehle zusammenfasst, bleiben dem Programmierer die lästigen Wiederholungen erspart. Hinzu kommt, dass man einen Makrobefehl als Anweisung in einer höheren Programmiersprache verstehen kann. Das ist besonders für den Programmierer interessant, da er diese Sprache selber entworfen hat. 1.2 Unterschied Unterprogramm - Makro Ein Unterprogramm ist dadurch charakterisiert, dass nur eine Kopie des Unterprogrammtextes im Programm vorhanden ist. Das Unterprogramm wird ausgeführt, wenn die Programmanweisung, die das Unterprogramm aufruft, ausgeführt wird. An das Unterprogramm übergebene Parameter bestimmen seine Funktion innerhalb der Grenzen, die beim Entwurf des Unterprogramms festgelegt wurden. Unterprogramme verkleinern die Gesamtlänge eines Programmes, sowie den Aufwand um diese zu schreiben, indem eine Aufrufanweisung als Ersatz für ein Unterprogramm dient. Die Speicher- und Aufwandeinsparungen kosten jedoch Zeit, um das Unterprogramm aufzurufen, um die Parameter zu übergeben und auf diese zuzugreifen und um vom Unterprogramm wieder zurückzukehren. Die Makro oder der "Zeilencode" bietet eine schnellere Alternative auf Kosten des Speicherplatzes und des Aufwandes. Eine Kopie des Makrobefehls anstatt eines Unterprogrammaufrufs wird in das Programm geschrieben. Änderungen erfolgen nicht während der Ausführung, sondern bereits bei der Programmierung und ermöglichen jede vom Programmierer gewünschte Funktion. Somit befinden sich mehrere Kopien spezialisierter Programmtexte im Programm, anstatt einer einzigen Kopie eines allgemeinen Textes. 2 Befehlszeile Bitte beachten Sie die Bedienungsanleitung zum CALM-Assembler. 3 Makrodefinition Der allgemeine Aufbau einer Makro sieht wie folgt aus: Makrobeginn definiert Makronamen, Vorgabeparameter Makrohauptteil bestimmt das Gerüst der Makro Makroschluss Es gibt fünf Pseudobefehle für Makros. 3.1 .MACRO .MACRO Makroname.Erweiterung,Parameter1,Parameter2,...,Parameter8 Dieser Makrobefehl beginnt eine Makrodefinition. Der Name dieser Makro ist Makroname. Die erlaubten Zeichen in Makroname sind dieselben wie für Marken im CALM-Assembler. Zur Zeit werden 32 Zeichen im Makronamen berücksichtigt. Ein weitere Makro kann nicht innerhalb einer Makrodefinition definiert werden. Erweiterung ist jede beliebige Zeichenfolge, abgeschlossen durch Komma, die die Datenangabe definiert. Erweiterung kann im Makrohauptteil mit dem reservierten Symbol %0 aufgerufen werden. Erweiterung ist der Vorgabewert. Dieser wird für %0 eingesetzt, falls keine Erweiterung in einem entsprechenden Makroaufruf definiert wurde. Der Punkt ist in %0 nicht eingeschlossen. Erlaubte Zeichen: alle ausser Kommas, Leerzeichen, Tabulatoren, Strichpunkte und Zeilenende. CALM-Makros Seite: 2 Parameter1 bis Parameter8 sind die Vorgabeparameter für diese Makro und werden im Makrohauptteil mit %1 bis %8 aufgerufen. Sie werden für die %1 bis %8 ersetzt, wenn keine Parameter bei einem entsprechenden Makroaufruf definiert wurden. Leerzeichen und Tabulatoren vor und nach einem Parameter werden ignoriert. Aber Leerzeichen und Tabulatoren innerhalb eines Parameters sind erlaubt. Beispiel: .MACRO TEST," ",D0 Wenn ein Parameter Kommas enthält, so muss der Parameter innerhalb Winkelklammern gesetzt werden. Beispiel: .MACRO TEST,<{R0}+ABSTAND,R1>, Um die linke Winkelklammer als erstes Zeichen zu übergeben, muss man < verwenden. Um die rechte Winkelklammer in einem solchen Parameter zu übergeben, muss man sie zweimal wiederholen (>folge>). Die Länge eines Parameters ist nur durch die Eingangszeilenlänge beschränkt. 3.2 .LOCALMACRO .LOCALMACRO Marke1,...,Marke8 Dieser Pseudobefehl definiert bis zu 8 Marken, die im Makrohauptteil verwendet werden können. Sie werden in lokale Marken (M_0$..M_999$) umgewandelt, wenn diese Makro aufgerufen (expandiert) wird. Dies vermeidet mehrfach definierte Marken, wenn die Makro mehr als einmal aufgerufen wird. Die erlaubte Syntax für die Marken ist dieselbe wie für Marken im CALM-Assembler. Ein Komma trennt die Marken. Leerzeichen und Tabulatoren vor und nach den Marken werden ignoriert. Falls dieser Pseudobefehl verwendet wird, muss er direkt auf .MACRO folgen. ASCALM berücksichtigt 32 Zeichen im Markennamen. 3.3 .ENDMACRO .ENDMACRO Dieser Pseudobefehl beendet eine Makrodefinition. 3.4 .LAYOUTMACRO .LAYOUTMACRO COMMENT,COMPRESS,ERROR,LIST,REPLACE TRUE Dieser Pseudobefehl ist überall im Programm gültig. Parameter: COMMENT speichert den ganzen Makrohauptteil (Kommentare, leere Zeilen, usw.). Diese Informationen erscheinen dann auch in den Makroexpansionen. Vorgabe: kein Kommentar: leere Zeilen und Kommentare werden ignoriert. COMPRESS der Eingangstext wird komprimiert, um die Grösse der Ausgangsdatei .ASM zu minimisieren. Alle Kommentare, leeren Zeilen und Leerzeichen zu Zeilenbeginn werden eliminiert. Aufeinanderfolgende Leerzeichen werden auf ein einziges reduziert. Dabei geht keine Assemblerinformation verloren. Nur die Lesbarkeit der Ausgangsdatei wird beeinträchtigt. Vorgabe: Eingangstext wird nicht komprimiert. ERROR kopiert die Fehler ebenfalls in die Ausgangsdatei. Vorgabe: Fehler werden nicht in die Ausgangsdatei kopiert. LIST kopiert den Makronamen und die Parameter bei einem Makroaufruf in die Ausgangsdatei. Beispiel: ; MACRO TEST {A0}+10,{A0+} ... hier folgt der expandierte Makrohauptteil Vorgabe: der eigentliche Makroaufruf wird nicht kopiert. REPLACE ein Makroaufruf, der sich selber aufruft (direkt oder über andere Makros), ist rekursiv und führt zu einem Fehler. Mit dem Befehl "REPLACE TRUE" wird die erneut aufgerufene Makro nicht expandiert, sondern einfach durch den Makroaufruf selber ersetzt (Eingangszeile bleibt unverändert). Ergänzende Informationen finden Sie im Kapitel "Assemblertextübersetzungen mit Makros". Vorgabe: REPLACE FALSE: führt bei einem rekursiven Aufruf zu einem Fehler. CALM-Makros Seite: 3 3.5 .EXITMACRO .EXITMACRO Dieser Pseudobefehl beendet die Makroexpansion. .EXITMACRO hat die gleiche Wirkung wie .ENDMACRO. .IF/.ELSE/.ENDIF- Pseudobefehlsstrukturen werden korrekt abgeschlossen. 3.6 Makrohauptteil Der Makrohauptteil enthält alle Befehle, die bei einem Makroaufruf zu expandieren sind. Kommentare und leere Zeilen werden normalerweise nicht gespeichert (siehe .LAYOUTMACRO). Beispiel: .MACRO LDIR.8,D0,D0,#FEHLER# .LOCALMACRO SCHLAUFE SCHLAUFE: MOVE.%0 %1,%2 DJ.16,NMO %3,SCHLAUFE .ENDMACRO Der Makroaufruf: LDIR.16 {A0+},{A1+},D0 generiert: M_0$: MOVE.16 {A0+},{A1+} DJ.16,NMO D0,M_0$ Auf die Datenangabe (Erweiterung) wird mit %0 und auf die Parameter mit %1 bis %8 zugegriffen. Wenn sich %0 bis %8 zwischen Anführungsstrichen befinden, so beziehen sie sich auf die Parameterwerte beim Makroaufruf. D.h. die Vorgabeparameter sind hierbei nicht eingeschlossen. %0 wird durch die Datenangabe ersetzt; die Datenangabe wird beim Makroaufruf, oder falls nicht angegeben, durch die Vorgabeerweiterung (falls vorhanden) definiert. "%0" ersetzt durch die beim Makroaufruf angegebene Datenangabe. %1..%8 wird durch den nten Parameter ersetzt; ein Parameter wird beim Makroaufruf, oder falls nicht angegeben, durch den Vorgabeparameter (falls vorhanden) definiert. "%1".."%8" wird durch den beim Makroaufruf angegebenen nten Parameter ersetzt. %MC ist der Makrozähler und wird bei einer Makroexpansion durch eine Zahl ersetzt, die die Anzahl der Makroaufrufe dieser Marke darstellt (1..999). %ML ist die aktuelle Verschachtelungstiefe, in der sich die aufgerufene Makro befindet. Diese Zahl kann mit einem .IF- Pseudobefehl verwendet werden, um beispielsweise zu testen, ob diese Makro in der Verschachtelungstiefe eins aufgerufen worden ist (nützlich bei Assemblertextübersetzungen). 3.7 Makroaufruf Ein Makroaufruf erfolgt, wie bereits in den vorherigen Beispielen gezeigt, durch drei Felder: den Makronamen, die Erweiterung und die Parameter. Jedem Parameter entspricht exakt dem im Makrohauptteil verwendeten Parameternamen: %1..%8. Ein Parameter kann bei einem Makroaufruf als leer deklariert werden. Ein Parameter innerhalb einer Makro ist leer, wenn kein Parameter beim Makroaufruf angegeben und kein Vorgabewert definiert wurde. Für einen leeren Parameter wird kein Zeichen in der expandierten Makro eingesetzt. Eine Makro kann eine andere Makro, aber nicht sich selbst aufrufen (Ausnahme: siehe .LAYOUTMACRO). Bis zu 10 geschachtelte Makroaufrufe sind möglich. Eine Definition muss sich immer vor einem Aufruf zu dieser Makro befinden. CALM-Makros Seite: 4 4 Makroerweiterungen Die definierten Makromöglichkeiten entsprechen den üblichen Makroleistungen. Aber es gibt zusätzliche Makrofunktionen. Unter anderem können die übergebenen Parameter analysiert und eine bedingte Assemblierung innerhalb Makros eingesetzt werden. 4.1 Parameteranalyse Die folgenden Funktionen werden nur innerhalb des Makrohauptteils erkannt. Sie werden bei einem Makroaufruf (Makroexpansion) berechnet. Verwendete Abkürzungen: %Vj globale Variablen, gesetzt mit .VARMACRO 0..9{,Text} par %i oder "%i" oder %Vj 0 <= i <= 8, 0 <= j <= 9 exp Zahlen oder LENGTH() Operatoren: + und -. parcopy par oder COPY() parpos parcopy oder Symbolname Funktionen: LENGTH(par) gibt die Länge von par zurück. COPY(par,exp1,exp2) erzeugt von par einen neuen Parameter, der bei der Position exp1 beginnt und Länge exp2 hat. DIGIT(parcopy) ergibt TRUE, falls alle Zeichen in parcopy Ziffern ["0".."9"] sind, ansonsten FALSE. LETTER(parcopy) ergibt TRUE, falls alle Zeichen in parcopy Buchstaben ["A".."Z","a".."z"] sind. HEX(parcopy) ergibt TRUE, falls alle Zeichen in parcopy Hex-Zahlen ["0".."9","A".."F","a".."f"] sind. EMPTY(parcopy) ergibt TRUE, falls die Länge von parcopy null beträgt. Somit kann man die Präsenz eines Parameters bei einem Makroaufruf prüfen. UPCASE(parcopy) wandelt parcopy in Grossbuchstaben um. POS(parpos1,parpos2) gibt Position von parpos1 in parpos2 (0..). 4.2 Bedingte Assemblierung in Makros Die zusätzlichen Funktionen werden noch leistungsfähiger, wenn man sie mit der bedingten Assemblierung kombiniert. Ausserdem können zwei Zeichenketten verglichen werden, indem man beim .IF-Peudobefehl zwischen diese ein Gleichheitszeichen (=) setzt. Beispiele: Prüft, ob ein Parameter beim Makroaufruf angegeben wurde: .MACRO LDIR .LOCALMACRO SCHLAUFE SCHLAUFE: MOVE.%0 %1,%2 .IF EMPTY("%3") *** Fehler: Kein Zähler! .ELSE DJ.16,NMO %3,SCHLAUFE ; 68000 .ENDIF .ENDMACRO Allgemeine Makro, die prüft, ob ein Wert Null ist (68000): .MACRO ZERO .IF LENGTH("%1")=2 .IF COPY("%1",1,1)DIGIT(COPY("%1",2,1))=ATRUE COMP.%0 #0,%1 ; Adressregister .ELSE TEST.%0 %1 .ENDIF .ELSE TEST.%0 %1 .ENDIF .ENDMACRO CALM-Makros Seite: 5 5 Assemblerpseudobefehle, die interpretiert werden Der CALM-Assembler interpretiert alle Pseudobefehle. Mit den Optionen /C/R/V kann eine Ausgangsdatei erzeugt werden, die keine Makropseudobefehle und keine .IF/.ELSE/.ENDIF-Pseudobefehle mehr enthält. 6 Makrobeispiele Der Einsatz von Makros wird in den folgenden Beispielen gezeigt. a) Zweck: ein Unterprogramm soll nur dann in das Programm eingefügt werden, wenn das Unterprogramm auch aufgerufen wird. Definition: .MACRO UP_NAME .IF %MC=1 JUMP UPNAMEE UPNAME: ... hier befindet sich das übliche Unterprogramm RET UPNAMEE: .ENDIF CALL UPNAME .ENDMACRO Erster Makroaufruf: UP_NAME generiert: JUMP UPNAMEE UPNAME: ... hier befindet sich das übliche Unterprogramm RET UPNAMEE: CALL UPNAME Weitere Makroaufrufe generieren: CALL UPNAME b) Zweck: allgemeiner Blockverschiebebefehl, der die Zählerlänge berücksichtigt (68000). Ist der Zähler ein Datenregister und die Länge .16, dann wird automatisch optimisiert (DJ). Ebenso soll ein Vorgabeblockbefehl definiert werden (wie LDIR bei Z80). Definition: .MACRO MOVESTRING.8,{A0+},{A1+},D0.32 .LOCALMACRO SCHLAUFE .IF COPY(%3,LENGTH(%3)-1,2)=16 .IF DIGIT(COPY(%3,2,1))COPY(%3,1,1)LENGTH(%3)=TRUED5 DEC.16 COPY(%3,1,2) SCHLAUFE: MOVE.%0 %1,%2 DJ.16,NMO COPY(%3,1,2),SCHLAUFE .ELSE SCHLAUFE: MOVE.%0 %1,%2 DEC.16 COPY(%3,1,LENGTH(%3)-3) JUMP,NE SCHLAUFE .ENDIF .ELSE .IF COPY(%3,LENGTH(%3)-1,2)=32 CALM-Makros Seite: 6 SCHLAUFE: MOVE.%0 %1,%2 DEC.32 COPY(%3,1,LENGTH(%3)-3) JUMP,NE SCHLAUFE .ELSE .IF COPY(%3,LENGTH(%3),1)=8 SCHLAUFE: MOVE.%0 %1,%2 DEC.8 COPY(%3,1,LENGTH(%3)-2) JUMP,NE SCHLAUFE .ENDIF .ENDIF .ENDIF .ENDMACRO Der Makroaufruf: MOVESTRING generiert: M_0$: MOVE.8 {A0+},{A1+} DEC.32 D0 JUMP,NE M_0$ Der Makroaufruf: MOVESTRING.16 {A4+},ADWINCH,{A6}+LEN.8 generiert: M_1$: MOVE.16 {A4+},ADWINCH DEC.8 {A6}+LEN JUMP,NE M_1$ Der Makroaufruf: MOVESTRING.32 #0,{A3+},D2.16 generiert: DEC.16 D2 M_2$: MOVE.32 #0,{A3+} DJ.16,NMO D2,M_2$ 7 Assemblertextübersetzungen mit Makros Oft möchte der Benutzer den Befehlssatz erweitern, indem einige Befehle mit zusätzlichen Operandenmöglichkeiten hinzugefügt werden sollen. D.h. der Operationscode ändert sich nicht. Um rekursive Makroaufrufe zu vermeiden, wird der Pseudobefehl .LAYOUTMACRO mit dem Operanden REPLACE eingesetzt. Beispiel: Folgende Befehle sollen zum Befehlsatz des Z80 hinzugefügt werden: MOVE DE,HL MOVE BC,HL CALM-Makros Seite: 7 Makrodefinition: .LAYOUTMACRO REPLACE TRUE ; ersetzt den .MACRO MOVE ; rekursiven Makroaufruf .IF %1%2=DEHL MOVE D,H MOVE E,L .ELSE .IF %1%2=BCHL MOVE B,H MOVE C,L .ELSE MOVE %1,%2 .ENDIF .ENDIF .ENDMACRO .LAYOUTMACRO REPLACE FALSE Makroaufruf: MOVE {HL},A generiert: MOVE {HL},A Makroaufruf: MOVE DE,HL generiert: MOVE D,H MOVE E,L Der Pseudobefehl .LAYOUTMACRO mit dem Parameter REPLACE TRUE verhindert, dass ein rekursiver Makroaufruf (somit ein Fehler) erzeugt wird, wenn erneut der Operationscode MOVE gefunden wird. Eine andere Anwendung ist die Übersetzung von der Herstellerschreibweise in die CALM-Schreibweise. Dies ist möglich, wenn der allgemeine Aufbau (Marken, Befehle, Kommentare, usw.) dem von CALM ähnelt.