This lecture will focus on some
of the advanced features of the
macro language as implemented by the IBM/System 360 assembler.

We shall focus on our stack
handling macros.

Some of the features to be
covered by this lecture include.

1.The
use of concatenation to generate type–specific instructions.

2.Some
standard system variable symbols.

3.The
use of one system variable symbol to solve the branch problem.

4.Conditional
assembly.

5.The
use of conditional assembly as a help in writing STKPOP.

7.The ABEND macro and its
use in signaling run–time errors.

8.A
completed version of our stack macros.

Concatenation:
Building Operations

In
a model statement, it is possible to concatenate two strings of characters.

Consider
the macro prototype to load a register from one of several sources.
Note the use of the string “&NAME” to allow this to be a branch target.

MACRO

&NAMELOAD &REG,&TYPE,&ARG

&NAMEL&TYPE &REG,&ARG

MEND

Consider
a number of invocations.

LOAD R7,R,R6becomesLR R7,R6

LOAD R7,H,HWbecomesLH R7,HW

LOAD R7,,FWbecomesL R7,FW

Note
here: the second argument is empty.The
empty string is concatenated to “F”.

We shall now extend the stack
operations to push and pop contents of
half–words and full–words, as well as registers.

Pushing from Various Sources

We
look first at the handling of our STKPUSH.The only
restriction on the
stack is that every value pushed be treated as a 32–bit fullword.

As
a result, a 16–bit halfword will be sign–extended to a 32–bit fullword
before being pushed onto the stack.This
is similar to the function of the LH
instruction, which loads a register from a halfword.

The
key instruction in the original STKPUSH macro is the following.

ST&R,0(3,2)STORE THE ITEM INTO THE STACK

In
this case, the item to be placed on the stack is found in the register
indicated by the symbolic parameter &R.

The
way to extend this instruction to all data types is as follows.

1.Select
a register to be a fixed source for the word on the stack, and

2.Construct
instructions to load that fixed register from the source.

What Shall Be Stored on the Stack?

At
this point, we have a decision to make.What data types to store?

The
size restriction on the stack limits the simple choices to addresses and the
contents of registers, halfwords, and fullwords.

We
must select a working register for the new macro.I select R4.
The “key code” becomes as follows.

Stacking
an addressLA R4,&ARGLoad address into R4.ST R4,&R,0(3,2)

Stacking
a halfwordLH R4,&ARGLoad halfword into R4.ST R4,&R,0(3,2)

Stacking
a fullwordL R4,&ARGLoad fullword into R4.ST R4,&R,0(3,2)

Stacking a registerLR R4,&ARGLoad
value from sourceregister into R4.ST R4,&R,0(3,2)

Passing the Type in a Macro Invocation

The
solution adopted to the problem above is to pass the type in the
macro call and use concatenation to build the load operator.

Here is
some code taken from a macro definition that has been run and tested.
First, we show the macro prototype.

&L2STKPUSH &ARG,&TYP

Next we
show the “key instruction” in the macro body.

L&TYP R4,&ARG

Here are
four typical invocations of the macro.

STKPUSH R7,RPUSH VALUE IN REGISTER.

STKPUSH HHW,HPUSH A HALFWORD VALUE.

STKPUSH FFW,APUSH AN ADDRESS.

STKPUSH FFWPUSH A FULLWORD.

Note that the last invocation lacks a second
argument.In the expansion, this
causes &TYP to be set to ‘ ’, a blank; “L&TYP” becomes “L ”.

The Macro Definition

Here is
the definition for the macro at this stage of its development.

MACRO

&L2STKPUSH &ARG,&TYP

&L2LHR3,STKCOUNT

SLAR3,2

LAR2,THESTACK

L&TYP R4,&ARG

STR4,0(3,2)

LHR3,STKCOUNT

AHR3,=H'1'

STH3,STKCOUNT

MEND

Again,
the “&L2”
allows the macro invocation to be a branch target.

Some Invocations of this Macro

91STKPUSH R7,R

92+LHR3,STKCOUNT

93+SLAR3,2

94+LAR2,THESTACK

95+LRR4,R7

96+STR4,0(3,2)

97+LHR3,STKCOUNT

98+AHR3,=H'1'

99+STH3,STKCOUNT

100STKPUSH HHW,H

101+LHR3,STKCOUNT

102+SLAR3,2

103+LAR2,THESTACK

104+LHR4,HHW

105+STR4,0(3,2)

106+LHR3,STKCOUNT

107+AHR3,=H'1'

108+STH3,STKCOUNT

More Invocations of this Macro

109STKPUSH FFW

110+LHR3,STKCOUNT

111+SLAR3,2

112+LAR2,THESTACK

113+LR4,FFW

114+STR4,0(3,2)

115+LHR3,STKCOUNT

116+AHR3,=H'1'

117+STH3,STKCOUNT

118STKPUSH FFW,A

119+LHR3,STKCOUNT

120+SLAR3,2

121+LAR2,THESTACK

122+LAR4,FFW

123+STR4,0(3,2)

124+LHR3,STKCOUNT

125+AHR3,=H'1'

126+STH3,STKCOUNT

NOTE:
The originals of the program listing are found at the end of the slides.

Saving the Work Registers

As
written, this macro has the side effect of changing the values of three
registers: R2, R3, & R4.The value
of R4 is preserved only if it is being pushed.

We
should write macros so that they operate without side effects.The only
way to do this is to save and restore the values of the work registers.

There
are many ways to do this.The simplest
is to alter the stack data structure.
Here is the new version.

STKCOUNT DC H‘0’NUMBER OF ITEMS STORED ON STACK

STKSIZEDC H‘64’MAXIMUM STACK CAPACITY

STKSAV2DC F‘0’SAVES CONTENTS OF R2

STKSAV3DC
F‘0’SAVES CONTENTS OF R3

STKSAV4DC F‘0’SAVES CONTENTS OF R4

THESTACK DC 64F‘0’THE STACK HOLDS 64 FULLWORDS

This new
definition does not alter the STKINIT macro.It does
affect the
other two macros: STKPOP and STKPUSH.We illustrate
the latter.

The First Revision of STKPUSH

Here is
the revision that allows the work registers to be saved.

MACRO

&L2STKPUSH &ARG,&TYP

&L2STR2,STKSAV2THE ORDER OF SAVING

STR3,STKSAV3IS NOT IMPORTANT.

STR4,STKSAV4

LHR3,STKCOUNT

SLAR3,2

LAR2,THESTACK

L&TYP R4,&ARG

STR4,0(3,2)

LHR3,STKCOUNT

AHR3,=H'1'

STHR3,STKCOUNT

LR4,STKSAV4THE ORDER OF
RESTORATION

LR3,STKSAV3IS NOT IMPORTANT
EITHER.

LR2,STKSAV2

MEND

The Status of the Macros at This Point

There
are a few issues to be addressed at this point.

The only
macro that will not change is the initialization macro, STKINIT.

1.We
have not yet dealt with generalizing the STKPOP macro.

2.We
have not yet dealt with either the stack empty problem or that of the stack being
full.Each has to be addressed.

Each of
these issues demands the use of techniques we have not yet discussed.

Consider
the first problem.We shall want to pop
the following from the stack:
register values, halfwords, and fullwords.The type for the argument refers to
the destination; an address can be popped into either a register or fullword.

In order
to see the problem for STKPOP, consider the “key instruction”.

Halfword:STH R4,&ARG

Fullword:ST R4,&ARG

Register:LR &ARG,R4No STR for store register.

We could
write a STR
macro, but I want to use another solution.

Some System Variable Symbols

There
are a number of system variable symbols.I mention three.

&SYSDATEThe
system date, in the 8 character form “MM/DD/YY”.Use in the form
of a declaration of initialized storage, as inTODAYDC C‘&SYSDATE’

&SYSTIMEThe
system time of day, in the five character form “HH.MM”.Also used in
the form of a declaration, as inNOWDC C‘&SYSTIME’

The &SYSNDX system
variable symbol can prevent a macro from generating
duplicate labels.The system symbol is
concatenated to a leading character,
which begins the label and must be unique within the macro definition.

More on the Macro Expansion Index

First
consider the following string, used as a label in a macro definition.

L&SYSNDX L R4,STKSAV4

Note
that the string “L&SYSNDX”, as written, contains eight characters:
the initial character “L” followed by the 7 character sequence “&SYSNDX”.

On
expansion, this will be converted to labels such as “L0001”, “L0002”, etc.

In the
macro definition, this takes the maximum eight characters allowed for
a properly formatted listing.For this
reason, I suggest that the better form for
the label in the macro definition is Single_Letter&SYSNDX.

In actual
fact, the requirement for the leading characters, to which the &SYSNDX
is to be appended can be any sequence of one to four characters, provided only
that the first character is a letter.Thus the following are valid.

A12&SYSNDX ...This label might become A120003.

WXYZ&SYSNDX ...This might become WXYZ0117.

I
suggest use of a single leading letter, this allows 26 labels per macro.

A Simple Example of Label Generation

Consider
the simple macro used for packed division in the previous lecture.
We adapt it to prevent division by zero.

MACRO

&LABELDIVID &QUOT,&DIVIDEND,&DIVISOR

&LABELZAP&QOUT,&DIVIDEND

CP&DIVISOR,=P‘0’IS IT ZERO

BNEA&SYSNDXNO, DIVISION
IS OK

ZAP&QUOT,=P‘0’YES, SET
QUOTIENT TO 0

BB&SYSNDX

A&SYSNDX
DP&QUOT,&DIVISOR

B&SYSNDX NOPRR3DO NOTHING

MEND

Note
that the format of the NOPR instruction requires a register number
(here R3),
even though the instruction does nothing.

Sample Expansion of the Macro

With the
above definition, consider the following expansions.

A10START DIVID X,Y,Z

+A10START ZAPX,Y

+CPZ,=P‘0’IS IT ZERO

+BNEA0001NO,
DIVISION IS OK

+ZAPX,=P‘0’YES, SET QUOTIENT TO 0

+BB0001

+A0001DPX,Z

+B0001 NOPRR3DO NOTHING

A20DOITDIVID A,B,C

+A20DOITZAPA,B

+CPC,=P‘0’IS IT ZERO

+BNEA0002NO, DIVISION IS OK

+ZAPX,=P‘0’YES, SET QUOTIENT TO 0

+BB0002

+A0002DPA,C

+B0002 NOPRR3DO NOTHING

Note
that each invocation has distinct labels.This removes the name clashes.

Another Design Strategy for DIVID

In this
variant, a zero divisor will cause the program to terminate abnormally.

MACRO

&LABELDIVID &QUOT,&DIVIDEND,&DIVISOR

&LABELZAP&QOUT,&DIVIDEND

CP&DIVISOR,=P‘0’IS IT ZERO

BNEA&SYSNDXNO, DIVISION
IS OK

ABENDINVOKE THE MACRO TOTERMINATE
EXECUTION.

A&SYSNDX
DP&QUOT,&DIVISOR

MEND

The First Revision of STKINIT

Here is
a revision of the STKINIT code that allows initialization of its size.

35MACRO

36 &L1STKINIT &SIZE

37 &L1ST
R3,STKSAV3

38SR R3,R3

39STH R3,STKCOUNT

40LR3,STKSAV3

41BL&SYSNDX

42 STKCOUNT DC H'0'

43 STKSIZEDC H'&SIZE'

44 STKSAV2DC F'0'

45 STKSAV3DC F'0'

46 STKSAV4DC F'0'

47 THESTACK DC
&SIZE.F'0'

48 L&SYSNDX SLA R3,0

49MEND

Note the “.” in the definition of THESTACK.This
concatenates the value
of the symbolic parameter with “F‘0’”, as in “128F‘0’”

The Second Revision of STKPUSH

MACRO

&L2STKPUSH &ARG,&TYP

&L2STR3,STKSAV3

LHR3,STKCOUNTGET COUNT OF ITEMS ON
THE STACK

CHR3,STKSIZEIS THE STACK FULL?

BNLZ&SYSNDXYES, DO NOT ADD
ANOTHER.

STR4,STKSAV4NO, WE CAN PUSH
ANOTHER ITEM.

STR2,STKSAV2START BY SAVING THE
OTHER 2 REGISTERS

SLAR3,2MULTIPLY THE INDEX BY 4.

LAR2,THESTACK

L&TYP R4,&ARGFORM THE ADDRESS

STR4,0(3,2)STORE THE ITEM

LHR3,STKCOUNTGET THE OLD COUNT OF
ITEMS

AHR3,=H'1'INCREMENT THE COUNT
BY 1

STHR3,STKCOUNTSTORE THE CURRENT COUNT

LR4,STKSAV4RESTORE THE
REGISTERS.

LR2,STKSAV2

Z&SYSNDX LR3,STKSAV3

MEND

This is
the final version of the STKPUSH macro.

We must
discuss another basic topic before addressing STKPOP.

Conditional Assembly

We have
already seen how concatenation can be used to construct
different instructions in a macro expansion.

We now
investigate conditional assembly, in which the expansion of a macro
can lead to a number of distinct code sequences.

Conditional
assembly permits the testing of attributes such as data format, data
value, or field length, and to use the results of such testing to generate
source
code that is specific to the case in question.

This
lecture will focus on five specific conditional assembly instructions.

AGOan
unconditional branch

AIFa
conditional branch.This means “Ask If”.

ANOPA NOP
that can be the branch target for either AGO or AIF.

MNOTEprint a
programmer defined message at assembly time

MEXITexit
the macro definition.

Attributes for Use by Conditional Assembly

The
assembler can generate code specified by certain attributes of
the arguments to the macro definition at the time it is expanded.

There
are six types of attributes that can be associated with a parameter.
Here are three if the more useful attributes.