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.