LOCKDS CSECT DEFINE PROGRAM CSECT
USING *,12 ESTABLISH PROGRAM ADDRESSABILITY
SAVE (14,12),,* SAVE REGISTERS
LR 12,15 COPY ENTRY POINT ADDR TO REG 12
LA 15,SAVEAREA LOAD ADDR OF A NEW SAVE AREA
ST 15,8(,13) ADD NEW SAVE AREA
ST 13,4(,15) TO THE SAVE AREA CHAIN
LR 13,15 ESTABLISH NEW SAVE AREA POINTER
LHI 10,50 PRESET DEFAULT COUNT
L 3,0(,1) LOAD ADDR OF PARM
LH 15,0(,3) LOAD LENGTH
LTR 15,15 TEST LENGTH
BNP NOPARM BR IF NO PARM TEXT
CHI 15,4 TEST LENGTH
BH NOPARM BR IF TOO LONG
BCTR 15,0 REDUCE LENGTH BY 1 FOR HARDWARE
EX 15,NUMTRT VERIFY PARM TEXT IS NUMERIC
BNZ NOPARM BR IF NOT
EX 15,NUMPACK CONVERT PARM TEXT TO PACKED DECIMAL
CVB 10,16(,13) CONVERT PACKED DECIMAL TO BINARY
NOPARM DC 0H'0'
...
NUMTRT TRT 2(*-*,3),TESTNUM
NUMPACK PACK 16(8,13),2(*-*,3)
...
SAVEAREA DC 9D'0' 72 BYTE OS/360 SAVE AREA
TESTNUM DC 0XL256'0',(C'0')X'04',10X'00',(256-(*-TESTNUM))X'04'
USING *,12 ESTABLISH PROGRAM ADDRESSABILITY
SAVE (14,12),,* SAVE REGISTERS
LR 12,15 COPY ENTRY POINT ADDR TO REG 12
LA 15,SAVEAREA LOAD ADDR OF A NEW SAVE AREA
ST 15,8(,13) ADD NEW SAVE AREA
ST 13,4(,15) TO THE SAVE AREA CHAIN
LR 13,15 ESTABLISH NEW SAVE AREA POINTER
LHI 10,50 PRESET DEFAULT COUNT
L 3,0(,1) LOAD ADDR OF PARM
LH 15,0(,3) LOAD LENGTH
LTR 15,15 TEST LENGTH
BNP NOPARM BR IF NO PARM TEXT
CHI 15,4 TEST LENGTH
BH NOPARM BR IF TOO LONG
BCTR 15,0 REDUCE LENGTH BY 1 FOR HARDWARE
EX 15,NUMTRT VERIFY PARM TEXT IS NUMERIC
BNZ NOPARM BR IF NOT
EX 15,NUMPACK CONVERT PARM TEXT TO PACKED DECIMAL
CVB 10,16(,13) CONVERT PACKED DECIMAL TO BINARY
NOPARM DC 0H'0'
...
NUMTRT TRT 2(*-*,3),TESTNUM
NUMPACK PACK 16(8,13),2(*-*,3)
...
SAVEAREA DC 9D'0' 72 BYTE OS/360 SAVE AREA
TESTNUM DC 0XL256'0',(C'0')X'04',10X'00',(256-(*-TESTNUM))X'04'
When a program is entered from JCL, register 1 points to a parameter list. The parameter list, in turn, points to the EXEC statement PARM data preceded by a two byte binary length.
L 3,0(,1)
LH 15,0(,3)
The L instruction loads the address of the parameter data from the parameter list, then the LH instruction loads the number of bytes of PARM data.
LTR 15,15
BNP NOPARM
CHI 15,4
BH NOPARM
First, the program tests if there is any parameter data. If the parameter length is 0, there is no data. The program then tests if the length is longer than the program will process. The UNPK instruction can actually handle 16 bytes, but the program imposes an arbitrary max length of 4 bytes.
BCTR 15,0
The BCTR instruction subtracts 1 from the length. Part of the reason the program bypasses this instruction if there is no parameter data is because this instruction will produce -1, or X'FFFFFFFF' in the register if the register contains 0 before the BCTR instruction executes, and that will cause problems later. The program does the subtraction because data length values in instructions like TRT and UNPK is always 1 less than the data length the instruction processes.
With the encoded data length in register 15, the program translates the decimal digits to binary. First, though, we want to verify the data is decimal digits.
EX 15,NUMTRT
BNZ NOPARM
...
NUMTRT TRT 2(*-*,3),TESTNUM
...
TESTNUM DC 0XL256'0',(C'0')X'04',10X'00',(256-(*-TESTNUM))X'04'
The EX instruction is a little complicated. It loads a single instruction from storage, updates the second byte of the instruction by ORing the low order 8 bits of the register specified , and then executes the modified instruction as thoughit were an instruction just fetched from storage.
The TRT instruction is also complicated: working from left to right in the table specified by the first operand - the parameter text - it loads a byte of data from the second table calculated by adding the contents of the byte in the first table to the address of the second table. Let's say the byte contains 5, or X'F5', so it loads the byte at TESTNUM+X'F5'. Each byte in the second table is called a "function byte." If the function byte is X'00', the instruction continues with the next byte in the first table. If the function byte is not X'00', the instruction stops, sets a condition code, and stores the address in the table where it found the byte with a non-zero function byte into register 1, and stores the non-zero function byte into the low order 8 bits of register 2. Our program is only interested in the condition code; it does not care about the registers.
The TESTNUM table is a complicated Assember DC instruction that actually contains 4 data elements, one after the other.
0XL256'0' -- This does not generate any data, but it seems to say that 256 bytes of Assembler type X are present.
(C'0')X'04' -- This generates 240 non-zero function bytes that correspond to non-decimal digit EBCDIC codes. The (C'0') is a count using the value of the EBCDIC 0. Doing it this way means that if the value for C'0' should ever change, all we have to do is assemble the program and the table will be adjusted appropriately.
10X'00' -- This generates 10 function code bytes that correspond to the EBCDIC codes for 0 through 9.
(256-(*-TESTNUM))X'04' -- This fills out the table with 6 more non-zero function bytes. However, if the value for the EBDIC 0 should ever change, the count calculated by (256-(*-TESTNUM)) will effectively change and the table will be built correctly.
If we made it this far, we are certain we have PARM text containing valid decimal digits. All we have to do is translate the digits to a binary value.
EX 15,NUMPACK
CVB 10,16(,13)
The conversion is done in two steps. The EX instruction executes a PACK instruction that converts the decimal digits to their correspond packed decimal data area. Rather than define a separate 8 byte data area the program uses 8 bytes in the new save area that do not presently contain any data. This is safe because once these 8 bytes have been converted to binary there is no further need for the data. The EX instruction works the same as it did for the TRT instruction. If we look at the initial value for NUMPACK, we have
0000D4 F270 D010 3002 00010 00002 638 NUMPACK PACK 16(8,13),2(*-*,3)
CVB 10,16(,13)
The CVB instruction translates the 8 byte packed decimal number to binary.