The @PRINT macro will allow us to print a single line to a printer. By default the printer is assumed to be a the standard address x’00E’. There are two forms of this macro – GEN=YES and GEN=NO. GEN=NO is the default form and is used to generate a call to our subroutine to print a line. The GEN=YES form is used to generate the code for our print subroutine.
MACRO &NAME @PRINT &DATA,&LEN=132,&DEV=X'00E',&GEN=NO LCLC &NDX LCLA &K &NDX SETC '&SYSNDX' AIF ('&GEN' EQ 'YES').GEN
We being by defining a couple of macro local variables – &NDX and &K. We set &NDX to the value contained in the assembler &SYSNDX which will contain a unique number for each macro invocation. We will use this to generate unique lable values in our macros. Next we test to see if GEN=YES has been specified and if so we branch to generate the subroutine code.
AIF ('&DATA'(1,1) EQ '''').STRING &NAME @RGCK &DATA,REG=R1 @RGCK &LEN,REG=R0 LA R15,@PRINT BALR R14,R15 MEXIT ,
Next we check to see if our &DATA parameter is a string. We check this before using the @RGCK macro because we want to use the length of the string in our macro. If not a string then we load the data target address into R1 and the data length into R0 (using a length of 132 as a default). We then BALR to our print subroutine.
.STRING ANOP , &NAME LA R1,=C&DATA &K SETA K'&DATA &K SETA &K-2 LA R0,&K LA R15,@PRINT BALR R14,R15 MEXIT ,
Here we generate a LA to place the address of a literal string into R1. We set &K to the length of the string operand and subtract two (for the beginning and ending quotes) to get the data length which we place in R0. We then call the print subroutine.
We will use a standard OS save area and linkage. We could use any other approach since we are not interfacing with the operating system – we are the operating system! We will always expect R13 to contain the address of a 18 word save area.
.GEN ANOP , @PRINT STM R14,R12,12(R13) SAVE CALLERS REGISTERS LR R2,R1 POINT TO DATA TO PRINT LR R3,R0 LENGTH OF DATA TO PRINT LA R1,132 MAX LENGTH WE CAN PRINT CR R3,R1 TOO BIG BNH @&NDX.01 NO - BRANCH LR R3,R1 SET TO MAX @&NDX.01 DS 0H
Now we copy the data address into R2 although we could have left it in R1 but out of habit I copied it freeing up R1. We then copy the length from R0 into R3 and compare it to the max length of 132. If the length is larger than the max we set it to the max value.
ST R2,@&NDX.90 SAVE DATA ADDR INTO CCW MVI @&NDX.90,X'09' PRINT: SINGLE SPACE ST R3,@&NDX.90+4 SAVE LENGTH INTO CCW LA R1,@&NDX.90 POINT TO CCW ST R1,72 SAVE INTO CAW LA R2,&DEV GET PRINT DEVICE ADDRESS SIO 0(R2) BNZ @&NDX.81 BRANCH IF ERROR
Next we place the data address into the CCW. We then set our CCW Op Code to X’09’ to print and single space followed by the length of the data. We then get the address of our CCW and store it into the Channel Address Word at fixed location 72. We can then issue a SIO to the printer using the device address from our macro parameter &DEV. We check to verify the SIO was accepted and if not we branch to an error routine to load a wait state PSW.
@&NDX.02 DS 0H TIO 0(R2) WAIT FOR I/O TO COMPLETE BZ @&NDX.03 COMPLETE BC 1,@&NDX.82 BRANCH IF ERROR B @&NDX.02 LOOP BACK AND WAIT * @&NDX.03 DS 0H LM R14,R12,12(R13) RESTORE REGISTERS BR R14
A TIO loop is executed until the I/O is complete and then we can restore the registers and return to the caller.
@&NDX.81 LPSW @ERRPRT1 LOAD WAIT PSW @&NDX.82 LPSW @ERRPRT2 LOAD WAIT PSW DS 0D @&NDX.90 DC X'00',AL3(0),X'00',X'00',AL2(0) CCW MEND ,
Now all we have left to is it define our error routines to load a wait state PSW. Our error PSW definitions are in our @ERR macro. We also need to allocate the space where we will construct our CCW.
Now we can print to the printer using our macro.
@PRINT 'HELLO, WORLD' * Print Hello Message @PRINT ' ' * Print a Blank Line @PRINT MSG,LEN=9 * Print string 8 chars long MSG DC C'HI, WORLD' @PRINT (AMSG) * Print 132 char string AMSG DC A(OURMSG) OURMSG DC CL132'*** THIS IS OUR MESSAGE ***' LA R10,OURMSG * Print 132 char string @PRINT (R10)
Full macro listing is below.
MACRO &NAME @PRINT &DATA,&LEN=132,&DEV=X'00E',&GEN=NO LCLC &NDX LCLA &K &NDX SETC '&SYSNDX' AIF ('&GEN' EQ 'YES').GEN AIF ('&DATA'(1,1) EQ '''').STRING &NAME @RGCK &DATA,REG=R1 @RGCK &LEN,REG=R0 LA R15,@PRINT BALR R14,R15 MEXIT , .* .* .STRING ANOP , &NAME LA R1,=C&DATA &K SETA K'&DATA &K SETA &K-2 LA R0,&K LA R15,@PRINT BALR R14,R15 MEXIT , .* .* .GEN ANOP , @PRINT STM R14,R12,12(R13) SAVE CALLERS REGISTERS LR R2,R1 POINT TO DATA TO PRINT LR R3,R0 LENGTH OF DATA TO PRINT LA R1,132 MAX LENGTH WE CAN PRINT CR R3,R1 TOO BIG BNH @&NDX.01 NO - BRANCH LR R3,R1 SET TO MAX @&NDX.01 DS 0H ST R2,@&NDX.90 SAVE DATA ADDR INTO CCW MVI @&NDX.90,X'09' PRINT: SINGLE SPACE ST R3,@&NDX.90+4 SAVE LENGTH INTO CCW LA R1,@&NDX.90 POINT TO CCW ST R1,72 SAVE INTO CAW LA R2,&DEV GET PRINT DEVICE ADDRESS SIO 0(R2) BNZ @&NDX.81 BRANCH IF ERROR @&NDX.02 DS 0H TIO 0(R2) WAIT FOR I/O TO COMPLETE BZ @&NDX.03 COMPLETE BC 1,@&NDX.82 BRANCH IF ERROR B @&NDX.02 LOOP BACK AND WAIT * @&NDX.03 DS 0H LM R14,R12,12(R13) RESTORE REGISTERS BR R14 * @&NDX.81 LPSW @ERRPRT1 LOAD WAIT PSW @&NDX.82 LPSW @ERRPRT2 LOAD WAIT PSW DS 0D @&NDX.90 DC X'00',AL3(0),X'00',X'00',AL2(0) CCW MEND ,