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