Unit 10.2 -- Demonstrate Macro With Move Byte Macro
SEE ALR &SYSNDX discussion pages 187-189
SCHAUM Section 14.4
Program
Move bytes from location A to location B
Move bytes from location C to location D
PED
to illustrate the use of &SYSNDX for generated lables
Concept
For generated labels for branch points or local data
use
string&SYSNDX
where string is three or less characters
SF
&SYSNDX is assigned a consecutive number for each macro call
within a macro calling another macro, &SYSNDX is restored after
the calling macro is completed
36.ASS
36.LIS
Unit 10.2
Demonstrate Macro with Move Byte Macro
Very often, we need to include labels in a macro. For example,
we might wish a macro to create a loop or an if-statement. Both
of these create labels to branch to.
Or, in a macro that creates data, we need various labels to refer
to the items created. In such a macro, we might need to compute
lengths.
The macro assembler provides an interesting variable, &SYSNDX,
for these purposes.
In each macro call, this macro-time variable is assigned a
number. That number is constant within the macro. It is
different for each macro-call.
(There's a special case of this. Macro1 might call macro2. In
this case, let's say that the value for &SYSNDX in macro1 is nnn.
And let's say the value for &SYSNDX in macro2 is mmm. When we
return from macro2, &SYSNDX will be restored to nnn.)
In our example, we write code to Move a sequence of bytes from
one location to another. This is a generalized memory-move
utility that can be used whenever we have two fields and we know
how long each one is in bytes.
Note that this routine will automatically ensure that we do not
move so many bytes from the source to the target that we overflow
the target. As you will recall, many nasty bugs including a
security breach called the INTERNET worm occurred when nobody
bothered to check that there was enough room in the target for
the source. Thus, the routine will take the two lengths and only
move as many bytes as the minimum of these two lengths.
The macro appears is defined in lines 2 to 23. The macro takes
four arguments. The first two are the address of the source and
target. That is, the first argument is the location of the first
byte to be moved. The second argument is the location of the
place to receive the first byte. The next two arguments are the
length of the first item and the length of the second argument.
On Page 258 is the pseudocode for the code that the macro
generates.
The initial "if" to set register 0 to the right value is in lines
5 to 9. Lines 13 to 21 implement the do loop. Note the presence
of IF&SYSNDX which is the label for the "FI" generated.
L1&SYSNDX generates a unique label for the start of the loop.
And L2&SYSNDX generates the label for the end of the loop.
The main program tests this code out by first copying field A to
field B. Then it copies field C to field D.
Note that the length of field A is 3 as indicated by "ALENGTH"
The length of fieldB is 10. Thus, the actual number of bytes
moved is three, the minimum of 3 and 10.
Meanwhile, the length of C is 10 while there are only three bytes
in D. Thus, only three bytes are moved in the second macro call.
Note that the first macro call takes two A-type constants:
=A(ALENGTH) and =A(BLENGTH). The second macro takes =A(CLENGTH)
and DLENGTH. Any valid memory location can be put in the macro
call, even an "explicit" reference such as 8(0,1). Thus, the
macro could easily be used inside a subroutine where the length
was in the control block passed to it. The macro simply
textually substitutes whatever is given to it. If something
invalid was passed to the macro, for example XXX=+@, then the
error message would come from the generated code. I.E., there
would be an error message that would appear in your listing after
the line with a "+" that contained "XXX=+@" The part of the
ASSEMBLER that does macro expansion wouldn't know.
The first call appears in line 30 of the LISTING file. It
generates code in lines 31 to 48. In this call, &SYSNDX is 1.
Thus, in line 34, we see IF0001 which is the result of replacing
&SYSNDX with one in the IF&SYSNDX that appeared in the macro
definition. In line 39, we see L10001 which is the result of
replacing the &SYSNDX with one in the L1&SYSNDX appearing in the
macro definition. And finally, line 48 is L20001 which is the
result of replacing the &SYSNDX with 1 in L2&SYSNDX.
In the second call, which appears in line 48 of the listing, we
have:
&SYSNDX is 0002
IF&SYSNDX goes to IF0002 in line 54.
L1&SYSNDX going to L10002in line 58
L2&SYSNDX going to L20002 in line 67
Pseudocode for the Macro
Register 0 = length of first argument
If Register 0 >= length of second argument
Register 0 = length of second argument
//Register 0 now contains the number of bytes to be
moved which is the minimum of (length of first argument
and second argument)
Register 1 = position in first string
Register 2 = position in second string
Register 3 (count) = 0
while count (register 3) < number of bytes to be moved (register 0)
move one character from first string to second string
increment position in first string
increment position in second string
increment count