The structure of a macro definition consists of a name, some optional arguments, the body of the macro and a termination keyword. The syntax you use to define a macro is:
name MACRO arg1, arg2, ... , argn
macro-body
ENDMACRO | ENDM
The name of the macro has the same requirements as a label name (in particular it must start in column one). The arguments are a comma-separated list of identifiers. The body of the macro can have arbitrary assembly language text including other macro definitions and invocations, conditional and file inclusion directives. A macro is instantiated by using its name together with optional actual argument values. A macro instantiation has to occur on its own lineit cannot be used within an expression or as an argument to an assembly code mnemonic or directive. The syntax you use invoke a macro is
name actual1, actual2, ... , actualn // comment
When a macro is instantiated the macro body is inserted into the assembly text with the actual values replacing the arguments that were in the body of the macro definition.
add MACRO N,a,b,c
load a, N
load b, N
addn , N
pop N
store c,N
ENDMACRO
longlong MACRO name, storage
name storage
BYTE[8]
ENDMACRO
longlong A, STATIC
longlong B, STATIC
longlong C, STATIC
.......
add 8, A, B, C // C = A + B
This example shows two macro definitions: add which defines a code sequence that will add two variables and store the result in a third variable; and longlong defines an 8-byte variable.
When labels are used in macros they must be unique for each instantiation to avoid duplicate label definition errors. The assembler provides a label generation mechanism for situations where the label name isnt significant and a mechanism for constructing specific label names.
If a macro definition contains a jump to other instructions in the macro definition it is likely that the actual name of the label isnt important. To facilitate this a label of the form name? can be used.
incifeq
MACRO a, N
pushw N
load a
cmpn ,2
bne NE?
incn a
NE?
ENDMACRO
var1 STATIC WORD = 10
incifeq var1, 10 // var1 is 11
incifeq var1, 10 // var1 is still
11
This example defines a macro incifeq that will increment a variable only if the variable has a specific value. If the label in the macro didnt use a ? then the assembler would have produced an error that the label was defined multiple times.
There are situations when a macro invocation should result in the definition of a label. In the simplest case the label can be passed as an argument to the macro, however there are cases when the label name should be constructed from other tokens. The macro definition facility provides two constructs to enable this:
MELBINARYOP macro opcode
_mel##opcode##$$MELNUM
BLOCK
op1? IN WORD
op2? IN WORD
ccr OUT WORD
loadi op1?, $$MELNUM
loadi op2?, $$MELNUM
opcode ,$$MELNUM
pop $$MELNUM
storei op1?,$$MELNUM 45
prim 0x5
store ccr,1
RETURN
ENDMACRO
MELNUM SET
3
MELBINARYOP
addn
MELNUM SET
MELNUM+1
MELBINARYOP
addn
In this example the macro will define a function whose name is based on a macro
argument and the value of the label MELNUM the macro invocations will
create the functions _meladdn3 and _meladdn4.
If multiple definitions are required a loop structure can be used. This can be achieved either by a recursive macro definitions or by the use of the LOOP directive.
MKMELARITH
macro N
IF N
MKMELARITH (N-1)
MELNUM SET MELNUM+1
MELBINARYOP addn
ENDIF
ENDMACRO
MKMELARITH 10
This example will produce functions _meladdn10 ... _meladdn1.
If the loop counter is a large number then a recursive macro may consume considerable machine resources. To avoid this we recommend using the LOOP directive, which is an iterative rather than recursive solution.
LOOP expression
loop-body
ENDLOOP
The loop control expression must be a compile time constant. The loop body can contain any assembly text (including further loop constructs) except macro definitions (since it would result in multiple definitions of the same macro).
x set 3
LOOP x
pushb (x*y)
x set x-1
ENDLOOP
This will assemble the instructions pushb 3, pushb 2 and pushb 1. Note that the label naming capabilities (? $$ ##) are not available within the body of a loop. If the loop body is to declare labels then a recursive macro definition should be used or a combination of using macro invocation to define the labels and the loops to define the text of the label.