Unit 10.3 -- Using Macros to Call Subroutines

PROG

The Copy-Array Subroutine with two calls
  Calls done with macros

PED

To learn another application of macros

A macro makes it much easier to call subroutines with parameters

Given a subroutine with n arguments

Macro to generate call is

     MACRO
     name &arg1,&arg2,...,&argn
     L    regA,&arg1     if first argument value argument
         or
     LA   regA,&arg1     if it's "by var" argument
     ST   regA,cbname&sysndx
     L    rega,&arg2     if second argument value argument
        or
     LA   regA,&arg2     if it's "by var" argument
     ST   regA,cbname&sysndx+4
         .
              .
              .
     L    regA,argn if nth argument value argument
        or
     LA   regA,argn if it's "by var" argument
          ST   regA,cbname&SYSNDX+(n-1)*4
     BAL  regB,name
     B    cbnameA&sysndx
     DS   0f
cbname&sysndx EQU *
     DS   nF
cbnameA&SYSNDX EQU *
     MEND

regA - register subroutines expects used to pass control block,
also used for temp storage
regB - register subroutine expects return address
cbname - name for control block <= 3 letters long

SF

     None

73.ASS

73.LIS

            Unit 10.3 -- Macros to call subroutines

When  we  learned about calling subroutines with parameters,  you
must  have  noticed that it was quite tedious to  write  the  two
lines  for  each parameter.  One did the load of  each  value  or
address  and  the  other  did the corresponding  store  into  the
appropriate place for each control block.  Should there  be  many
parameters,  it  would  be easy to forget  one  parameter  or  to
otherwise "screw up."

Macros are an obvious solution.  It should be fairly obvious what
to  do,  but  we  will go through it anyway.  The stores  can  be
easily put in, but what about the control block.  One solution is
to  have  the user type a control block of a given name, one  for
each different subroutine called.  But that's a pain.

The  other  solution  is to have the macro somehow  generate  the
control  block.   In  the first example,  each  macro  call  will
generate a control block.  We can use the &SYSNDX capability that
we learned about in the previous unit to accomplish this.

The  macro  name  is given a &SYSNDX suffix.  That  way,  we  can
insure  that  each  invocation of the macro generates  a  control
block  with  the unique label.  But where do we put  the  control
block.   If  we just deposit it in the code, when the instruction
before  it  is  finished  executing...  Yes,  the  computer  will
attempt  to  execute the control block as if it were program  and
not  finding  a  proper  op-code  there,  it  would  generate  an
"operation exception."

The  solution  is  simple--we generate a branch instruction  that
branches around the generated control block.

Our  example  shows the use of such a macro with our  copy  array
subroutine.   Recall  that  the copy-array  routine  takes  three
parameters,  the address of the first array, the address  of  the
second  array, and lastly the number of items in the first  array
to  be  copied.   The  first  two are  passed  as  addresses--var
parameters and the last one is a value parameter.  In  this  kind
of  application, the first array is referred to as  "the  source"
and the second array is referred to as the "target."

Thus  our COPY MACRO has three arguments as well.  The first  two
are  the  addresses of the two arrays and the last is the  count.
This  macro appears on lines 2 to 17.  &ARRAY1 receives the first
argument,  the  address  of  the array  to  be  copied.   &ARRAY2
receives the second argument, the address of the place to put the
result.  &LENGTH gets the location in memory where the number  of
bytes to move is stored.

Lines 4 to 5 put the address of the source into the first element
of  the Copy Control Block.  Lines 6 to 7 put the address of  the
target into the second element of the Copy Control Block.   Lines
8 to 9 put the length into the copy control block.

Line  10 gets the address of the copy control block into register
one--where the COPY subroutine expects to find it.  And  line  11
does  the  actual  branch.  Line 12 will branch around  the  Copy
Control  Block.  Line 13 makes sure that its alligned  correctly.
Line  14 and Line 15 define the copy control block itself.   Line
16 is the endpoint for the branch around the control block.

We  have  a single call to test this, on line 23.  Note  that  we
specify  simply A and B as the arguments to COPY.  These are  put
into  "LA" instructions by the macro.  The "=A(ALEN)" is used  as
the  length.  Since, the macro does a Load of the third argument,
we can't write "ALEN," we have to provide a memory location where
the length is.  That is provided by the constant "=A(ALEN)" which
is the name for the constant stored at memory location 00A0.

Observe  in the generated code, that a Copy Control Block  called
CCB0001 is generated in lines 34 and 35 and a branch around it is
done using CCBA0001 as the address in line 32.