MACRO ASSEMBLY A macro is a named sequence of instructions. It is used in a similar way to a subroutine by the programmer, but is treated quite differently by the assembler. Whereas the assembler generates one instruction on encountering a JSR instruction (a call to the subroutine whose code starts at the label given in the JSR instruction), it generates the sequence of instructions given in the macro's definition on encountering a macro call. A subroutine call is a directive to the processor to change the normal sequential execution of instructions, while a macro call is a directive to the assembler to change the normal sequential translation of instructions. Example: .MACRO SWAP,X,Y MOV X,TEMP ;swap contents of memory locations X & Y MOV Y,X MOV TEMP,Y .ENDM If the following code is being assembled JSR PC,Q1 SWAP R1 R0 JSR PC,Q1 MOV R1,(X)+ the code generated is the same as for JSR PC,Q1 MOV R1,TEMP MOV R0,R1 MOV TEMP,R0 JSR PC,Q1 MOV R1,(X)+ In this example, TEMP must be a predefined memory location. Macros can be used instead of subroutines, but (except for very small macros) more code is generated. However, because no subroutine call or return instructions are generated, the code generated when a macro is used is more efficient than the code generated when a subroutine is used. The percentage improvement in efficiency decreases with increasing size of the macro. It is recommended, therefore, that macros without conditional assembly statements (explained below) be used only if at least one of the following conditions are true: 1) The macro contains no more than about five instructions, and its use improves program readability. 2) The macro contains more than five instructions, but is only used once, and that use improves program readability. 3) The macro is used to replace several similar, but not identical, code sequences. 4) The macro contains stack manipulating instructions, and is used several times. 5) The speed of the program's execution is critical, and the macro's use improves program readability. In all other cases, a subroutine call or in-line code sequence should be used. CONDITIONAL ASSEMBLY It is possible to indicate to the assembler that certain sections of a program are to be compiled only if certain conditions are true. This is useful on a number of instances. For example, it may on occasions be desirable to collect statistics on how frequently certain code paths inside the program are being executed, or to print out trace information. This can be done by inserting conditional assembly statements into the source program. Example: .IF EQ,STATS ;assemble if STATS = 0 MOV R0,TEMP MOV #15.,R0 ASL R0 INC FREQ(R0) ;increment array elem 15 MOV TEMP,R0 .ENDC This code might be used to indicate how frequently a section of code is being executed. When assembled, it saves R0 in a temporary location, and then increments element 15 in an array named FREQ. Other sections of code would increment different array elements. The code is assembled if assembler variable STATS is equal to zero. Near the beginning of the program, STATS would be assigned a value, thus: ON=0 OFF=1 STATS=OFF To collect statistics on code path usage, STATS=OFF would be changed to STATS=ON and the program reassembled. This statistics collection macro could be put inside a macro, thus: .MACRO GETSTA,N .IF EQ,STATS MOV RO,TEMP MOV N,R0 ASL RO INC FREQ(R0) MOV TEMP,R0 .ENDC .ENDM The conditional statement above could then be replaced by GETSTA #15 Other condition types can be used, for example .IF NE,X ;assemble if X <> 0 .IF GT,X ;assemble if X > 0 .IF GE,X ;assemble if X >= 0 .IF LT,X ;assemble if X < 0 .IF LE,X ;assemble if X <= 0 .IF B,X ;assemble if X is blank (missing) .IF NB,X ;assemble if X is non-blank (present) .IF DF,X ;assemble if X is defined .IF NDF,X ;assemble if X is not defined .IF IDN,X,Y ;assemble if X is identical to Y .IF DIF,X,Y ;assemble if X is different from Y Conditional assembly can be used inside macros. For example, it is possible to modify the SWAP macro given above, so that it can be used even when TEMP has not been given a value. .MACRO SWAP,X,Y .IF NDF,TEMP;if TEMP is not defined, then BR .+1 ;insert a branch instr to skip one word TEMP: .WORD 0 ;reserve one word for temp .ENDC MOV X,TEMP ;swap contents of memory locations X & Y MOV Y,X MOV TEMP,Y .ENDM The first time this code is assembled, TEMP is not defined, and so code is generated for the lines within the conditional assembly statement. When it has been assembled on subsequent occasions, TEMP has been defined, and so no code is generated for the lines within the conditional assembly statement. ITERATIVE ASSEMBLY It is possible to assemble code repeatedly. This is useful on a few occasions. Examples: To move three bytes from the memory location whose address is contained in R0 to the memory location whose address is contained in R1, we could write A: MOVB (RO)+,(R1)+ MOVB (R0)+,(R1)+ MOVB (R0)+,(R1)+ We could, alternatively define a macro using the .REPT directive. This takes one parameter which has a numeric value, and repeatedly assembles the code a number of times, depending on the value of the parameter .MACRO MOVE,X,Y,N .REPT N ;assemble N times MOVB (X)+,(Y)+ .ENDR and call this with actual parameters 3, R0 and R1 A: MOVE R0 R1 3 Exactly the same code would be generated as above. It is not necessary that the code generated be identical for each iteration. The following code would produce the ASCII string '0123456789'. DIGIT=48 .REPT 10 .BYTE DIGIT DIGIT=DIGIT+1 .ENDR Another form of iterative assembly uses the .IRP directive. This takes a dummy symbol, followed by a list of symbols enclosed in angle brackets, and, on each iteration, replaces the dummy symbol by the next symbol on the list. The following macros save and restore registers R1 to R6. .MACRO PUSH,X MOV X,-(SP) .ENDM .MACRO POP,X MOV (SP)+,X .ENDM .MACRO SVREGS ;push registers R0 to R6 on to stack .IRP REG, PUSH REG .ENDR .ENDM .MACRO RSREGS ;pop registers R0 to R6 from stack .IRP REG, POP REG .ENDR .ENDM Note that we can use macros from inside macros. It is in fact possible to have recursive macro definitions, i.e., a macro may be used from inside itself. Assembler directives other than macro calls and conditional assembly are not frequently used.