This is a very simple dataset copy utility.
MINICOPY CSECT
USING *,12
SAVE (14,12),,*
LR 12,15
LA 15,SAVEAREA
ST 15,8(,13)
ST 13,4(,15)
LR 13,15
OPEN (INDCB,INPUT,
OUTDCB,OUTPUT)
LOOP GET INDCB
LR 0,1
PUT OUTDCB,(0)
B LOOP
EOF CLOSE (INDCB,,OUTDCB)
L 13,4(,13)
RETURN (14,12),T,RC=0
SAVEAREA DC 18F'0'
INDCB DCB DSORG=PS,MACRF=GL,
DDNAME=INPUT,
EODAD=EOF
OUTDCB DCB DSORG=PS,MACRF=PM,
DDNAME=OUTPUT
END MINICOPY
I can't show continuation flags on the OPEN and DCB statements because the code block is too narrow.
The CSECT statement defines a CSECT; which is just a block of storage; it has the external name MINICOPY.
The USING statement tells the Assembler that register 12 has the address of the current location. Most, not all, z/OS instructions form an address by adding the contents of a register specified in the instruction to a displacement specified in the instruction. The USING statement tells the Assembler to use register 12 as the register, and for it to compute a displacement as required and to store the displacement as required.
The SAVE statement is a macro call. The System/360 Assemblers have a
very powerful macro language, and they are accompanied by an extensive library of macros that greatly simplify programming for Assembler programmers. The SAVE macro stores the contents of registers 14 through 12, in the order 14, 15, 0, 1,...,12 into a save area provided by the caller with an address provided in register 13.
LR 12,15 copies the contents of register 15 to register 12. Another convention is that register 15 contains the address of the program, and register 14 contains a return address. Programs are expected to restore the contents of registers 2 through 14 before they exit to the address in reg 14. The SAVE macro does not use base/displacement instructions that use the addressing defined by the USING statement.
LA 15,SAVEAREA The very first thing a program must do is prepare a new save area if it calls another program. Though it's not obvious, the GET and PUT macros later in this program do just that. The LA instruction uses base register / displacement arithmetic to store the address of a new save area into register 15.
ST 15,8(,13) These instructions add the new save area to a potential chain of save
ST 13,4(,15) area. Notice we establish a forward pointer with the first ST instruction
LR 13,15 and a back pointer with the second ST instruction. The LR instruction actually completes the process. The 8(,13) string defines displacement 8 from register 13 with implied index register 0 (no index register, since register 0 cannot be used as a base register or an index register).
OPEN (INDCB,INPUT,OUTDCB,OUTPUT) OPEN is another macro; it completes preparation of data areas established by the DCB macro so they can be used for I/O.
LOOP GET INDCB This statement provides an instruction label LOOP and a call to the GET macro to retrieve the address of a record from the dataset specified through the INDCB DCB macro. The address is returned in register 1.
LR 0,1 This is pretty obvious: copy the contents of register 1 to register 0. The reason is much less obvious: the PUT macro will ultimately store a record address in register 0, but it will load the DCB address into register 1. If you specify PUT OUTDCB,(1), which seems to be legal, what will happen is PUT will load the DCB address into register 1, then copy that address to register 0. Oops.
PUT OUTDCB,(0) PUT is a macro, and it writes the record that has an address in register 0 to the dataset established by the DCB with label OUTDCB.
B LOOP More accurately, BC 15,LOOP. This branch instruction forms the I/O loop. Many instructions set a 2 bit condition code. The BC instruction provides a 4 bit mask, one bit for each possible condition code setting, according to these rules
BC Mask Condition code
8 00
4 01
2 10
1 11
When the mask bit for a specific condition code is on, the instruction branches, so a mask of 15 (all the bits are on) causes the instruction to branch if the condition code has any value. As a convenience for programmers the Assembler provides a number of "extended branch" operation codes. BE ..., for example, generates BC 8,... because instructions that perform a comparison set condition code 00 if the comparison is equal.
EOF CLOSE ... The I/O macros break the I/O loop and branch here when all the records in the input dataset have been processed. The CLOSE macro terminates I/O processing for the DCBs.
L 13,4(,13) This instruction loads the address of the previous save area, as set by the ST 13,4(,15) instruction near the start of the program.
RETURN (14,12),T,RC=0 RETURN is yet another macro. This one restores the registers saved by the SAVE macro from the save area register 13 points to. T directs the macro to set a flag that indicates the save area is no longer in use, and RC=0 directs the macro to store 0 in register 15 as a program return code.
SAVEAREA DC 18F'0' This instruction defines a 72 byte register save area used when this program calls another program.
INDCB DCB ... Another macro. The actual macro is
very large, and it generates a very large (almost 100 bytes) table. DSORG=PS tells the macro to generate a DCB for a sequential dataset. MACRF=GL tells the macro that GET macros will be used with this DCB, and that the GET macros expect to return a record address rather than move the data record to a storage area specified by the GET macro. DDNAME=INPUT specifies the DD name assigned to the DD statement that defines the actual input dataset. EODAD=EOF provides the address where a GET macro will branch to after all input records have been read.
OUTDCB DCB ... DSORG=PS tells the macro to generate a DCB for a sequential dataset. MACRF=PM tells the macro that PUT macros will be used, and that the PUT macros will provide the address of a storage area where the record is located; the PUT macro will move the contents of this storage area to the dataset. DDNAME=OUTPUT specifies the DD name assigned to the DD statement that defines the actual output dataset. This DD statement must specify the RECFM, LRECL, and BLKSIZE of the dataset.