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   ,

[Next – Macro @DUMP]