Now we need to write our executable program.  For now we will focus on our program and not worry about how to get it punched into 80-byte cards.

First we need to establish a base register.  This code is written to be relocatable so it should run from anywhere we place it in memory.  We can move it to somewhere else other than location 1024 by modifying the PSW and the three CCWs used to read in the program.

BEGIN    DS    0D
         BALR  R10,0                * Establish a Base Address
         USING *,R10                * Tell the assembler
*

Next we need to get the device address for the card reader  used for the IPL process.  This is where we will expect to find our data cards.  When the CPU completes the IPL process and loads our initial PSW but before execution begins, the address of the IPL device is saved.  Since we are loading a BC PSW the IPL device address is saved in locations 2 and 3.

         SLR   R3,R3                * Clear Register 3
         ICM   R3,B'0011',2         * Load IPL Device Address
         LA    R4,X'E'              * Assume Printer at 00E
*

We will assume the printer is at device address X’00E’ which is usually a standard place to define a printer.  The standard location for the card reader is X’00C’ and that for the card punch is X’00D’.

Now we can handle some housekeeping to make our program relocatable.  If we were running with the help of an operating system we would probably have a relocating loader.  This means we could use an address constant (ADCON) in our CCW to point to the buffer.  When the loader read our program into memory the value in the ADCON would be relocated or updated to reflect our actual location in memory.

Since we are Bare Metal programming we don’t have an operating system or relocating loader.  In fact our loader is just some CCWs that are executed by the channel at IPL.  We will use a LA and STCM to get the actual address of the buffer at run time and store it into our CCWs.

         LA    R1,RDBUF          * Get the address of the I/O Buf
         STCM  R1,B'0111',RDCCW+1  Place address into Read CCW
         STCM  R1,B'0111',PRCCW+1  Place address into Print CCW

Now we are ready to enter the main loop for our 80-80 List program.  The first thing we want to do is attempt to read a card from the same card reader that was used as the IPL device.  Before issuing the Start I/O we need to place the address of our read CCW into the CAW.

         LA    R1,RDCCW          * Get address of Read CCW
         ST    R1,72             * Place into CAW (location 72)

Our Read CCW should look very familiar since it is almost exactly like the CCWs used in our IPL process.  We will not set any flags in the CCW this time.  Since we are not command chaining our CCW program will consist of a single CCW.  We are using command code X’02’ to read, the address is filled in at run time, and we are expecting 80 bytes of data.  This time we will leave the SLI bit off and if the card reader attempts to transfer more or less than 80 bytes an exceptional condition will occur.

RDCCW    DC    X'02',AL3(0),X'0000',AL2(80)

Now we can issue the Start I/O instruction to cause the channel to execute our channel program.  We have saved the address of the card reader in register three.  We then check the condition code to see if the channel is processing our request.  If not we load a Wait PSW and halt execution.

         SIO   0(R3)             * Issure Start I/O to Channel
         BNZ   ERR1              * If Chan not processing - error

Now we have to wait for the I/O to complete.  Since we have masked all I/O interrupts the CPU will not generate an interrupt when the I/O is complete.  Instead we will use the Test I/O instruction to check on the progress of the channel program.  If the I/O is complete we will branch out of our wait loop.  If the return code indicates the channel or device is not operational we will load a Wait PSW.  If the channel is still busy we will loop back and issue the Test I/O again.

RDTIO    DS    0H
         TIO   0(R3)             * Test for I/O Completion
         BZ    PRT               * Branch if I/O Complete
         BC    1,ERR2            * Branch if not operational
         B     RDTIO             * Loop back and wait for I/O

Now we need to check for successful completion of our channel program.  We know that it completed and the completion status was stored into the CSW as a result of our issuing a Test I/O against the device.  We will test the status bits and we only expect to find Channel End and Device End set.  If we find anything else some type of exceptional condition has occurred.  We use a CLC to compare the two bytes of status bits in the CSW (located at fixed location 68) to a constant with just the Channel End and Device End bits set X’0C00′

PRT      DS    0H
         CLC   CEDE,68           * Compare status bits
         BNE   ERR0              * Branch if not CE+DE
          .
          .
CEDE     DC    X'0C00'           * CE+DE

If we get anything else other than CE+DE we will save the status bits of the CCW into the address portion of a Wait PSW and then load that PSW to halt execution.  The reason we store the status bits in the CSW is so they become the wait code (the address portion of the wait PSW) and are visible on the operator console.

ERR0     MVC   PSWERR0+6(2),68   * Move CSW status bits to PSW
         LPSW  PSWERR0           * Load Wait PSW
          .
          .
PSWERR0  DC    X'00',X'02',X'0000',x'00',x'000000'

If there is no error then we issue a Start and I/O to the printer to print out the contents of the card we just read.  Just as with reading a card we store the address of the CCW into the CAW and then issue the Start I/O against the device.  We check the condition code from the Start I/O to verify the channel program is active.

         LA    R1,PRCCW          * Point to Print CCW
         ST    R1,72             * Store into CAW
         SIO   0(R4)             * Start I/O on Printer
         BNZ   ERR3              * Branch if Error

The CCW to print is similar to the CCW to read a card from the card reader.  Each device has its own set of command codes.  Printers have a number of command codes they respond to. Below is a quick summary of a few command codes for a printer.

01 - Write and Do Not Space
09 - Write and Space 1 Line
11 - Write and Space 2 Lines
19 - Write and Space 3 Lines
0B - Space 1 Line Immediate
13 - Space 2 Lines Immediate
1B - Space 3 Lines Immediate

We will use command code X’09’ to write a line and then space down to the next line.

PRCCW    DC    X'09',AL3(0),X'0000',AL2(80)

As with the read CCW, the data address is filled in at run time.  We will print 80 bytes of data and no flags are set.  Our channel program will consist of a single CCW.

Next we enter a Test I/O loop to wait for completion of the I/O.  For now when the I/O is complete we assume it was successful.  We could check the CSW status bits for any exceptional conditions but we don’t for now to make our program smaller and simpler.

PRTTIO   DS    0H
         TIO   0(R4)             * Wait for I/O to Complete
         BZ    RDLP              * Done - Go read next card
         BC    1,ERR4            * Branch if error
         B     PRTTIO            * Loop back and test again

[Next - Creating The IPL Deck]