The IBM
System/360 and those that have followed in the family have evolved an elaborate
I/O system in an attempt to maintain efficiency in processing extremely large
data sets.Even the early System/360
designs had several levels in the I/O architecture: logical IOCS (Input/Output
Control System), Physical IOCS, and the Channel subsystem.While such a multi–level organization can be
very efficient, it is somewhat hard to program.

From an
Assembler Language level, the proper control and use of I/O operations requires
several sequences of instructions.Many
times, these sequences appear as a fixed set of instructions in a fixed order,
with optional parameters.Such sequences
immediately suggest the use of macros with keyword parameters.Indeed, this is the common practice.

To review
from the previous chapter, the use of a macro is based on a macro definition
that is then invoked by what is called the “macro invocation”.As a standard example, we recall the decimal
divide macro.This first definition is
that of a positional macro.

Again, we
note an obvious fact.Teaching examples
tend to be short and explicit.This
sample macro is so simple that few programmers would actually use it.However, the I/O macros that are the subject
of this chapter are complex; nobody writes the equivalent code.

A MACRO begins with the key word
MACRO, includes a prototype and a macro body, and ends with the trailer keyword
MEND.Parameters to a MACRO are
prefixed by the ampersand “&”.Here
is the example definition.

HeaderMACRO

PrototypeDIVID&QUOT,&DIVIDEND,&DIVISOR

Model StatementsZAP&QOUT,&DIVIDENDDP&QUOT,&DIVISOR

TrailerMEND

The macros
used in the I/O system seem all to be keyword
macros.The definition of a keyword
macro differs from that of a positional macro only in the form of the
prototype.Each symbolic parameter must
be of the form &PARAM=[DEFAULT].What this says is that the symbolic parameter is followed immediately by
an “=”,
and is optionally followed by a default value.As a keyword macro, the above example can be written as:

HeaderMACRO

PrototypeDIVID2&QUOT=,&DIVIDEND=,&DIVISOR=

Model StatementsZAP&QOUT,&DIVIDENDDP&QUOT,&DIVISOR

TrailerMEND

Here are a number of equivalent
invocations of this macro, written in the keyword style.Note that this definition has not listed any
default values.

DIVID2&QUOT=MPG,&DIVIDEND=MILES,&DIVISOR=GALS

DIVID2&DIVIDEND=MILES,&DIVISOR=GALS,&QUOT=MPG

DIVID2&QUOT=MPG,&DIVISOR=GALS,&DIVIDEND=MILES

It is possible to use labels
defined in the body of the program as default values.

MACRO

DIVID2&QUOT=MPG,&DIVIDEND=,&DIVISOR=

ZAP&QOUT,&DIVIDENDDP&QUOT,&DIVISOR

MEND

With this definition, the two
invocations are exactly equivalent.

DIVIDMPG,MILES,GALSDIVID2&DIVIDEND=MILES,&DIVISOR=GALS

The invocation of the macro
DIVID2 will expand as follows:

ZAPMPG,MILESDPMPG,GALS

Having
reviewed the syntax of keyword macros, we now turn to the main topic of this
chapter: a brief discussion of the Input/Output Control System and associated
macros.Following the lead of Peter Abel
[R_02], the focus will be on the following:

DCBData
Control Block, used to define files.

OPENThis
makes a file available to a program, for either input or output.

CLOSEThis
terminates access to a file in an orderly way.For a buffered outputapproach, this
ensures that all data have been output properly.

GETThis
makes a record available for processing.

PUTThis
writes a record to an output file.In a
buffered output, this maywrite only to an
output buffer for later writing to the file.

Register Usage

Each I/O
macro that we shall discuss expands into a sequence of calls to operating
system routines, most probably in the LIOCS (Logical I/O Control System)
level.For this reason, we should review
the general–purpose registers used by the operating system.

0 and 1Logical
IOCS macros, supervisor macros, and other IBM macros use
these registers to pass addresses.

13Used
by logical IOCS and other supervisory routines to hold the address of a
save area.This area holds the contents
of the user program’s
general purpose registers and restores them on return.

14 and 15Logical
IOCS uses these registers for linkage.A
GET or PUTwill load
the address of the following instruction into register 14 and will
load the address of the actual I/O routine into register 15.

This use of
registers 13, 14, and 15 follows the IBM standard for subroutine
linkage, which will be discussed in a later chapter.

One “take
away” from this discussion is the fact that user programs should reference and
use only registers 3 through 12 of the general–purpose register set.Some general–purpose registers are less
“general purpose” than others.

Record Blocking

In IBM
terminology, a data set is a
collection of data records that can be made available for processing.The term is almost synonymous with the modern
idea of a disk file; for most of
this text the two terms will be viewed as equivalent.One should realize that the idea of a data
set is more general than that of a disk file.Data sets can be found on a DASD (Direct Access Storage Device, either a
magnetic disk or a magnetic drum), on magnetic tape, or on a sequence of paper
punch cards.The term “data set” is a
logical construct.

In order to
understand the standard forms of record organization, one must recall that
magnetic tape was often used to store data.This storage method had been introduced in the 1950’s as a replacement
for large boxes of punched paper cards.The standard magnetic tape was 0.5 inches wide and either 1200 or 2400
feet in length.The tape was wound on a
removable reel that was about 10.5 inches in diameter.The IBM 727 and 729 were two early models.

The IBM 727
was officially announced on September 25, 1963 and marketed until May 12, 1971.The figure at left was taken from the IBM
archives, and is used by permission.

It is
important to remember that the tape drive is an electro–mechanical unit.Specifically, the tape cannot be read unless
it is moving across the read/write heads.This implies a certain amount of inertia; physical movement can be started
and stopped quickly, but not instantaneously.

One
physical manifestation of this problem with inertia is the inter–record gap on
the magnetic tape.If the tape contains
more than one physical record, as do almost all tapes, there must be a physical
gap between the records to allow for starting and stopping the tape.In other words, the data layout on the tape
might resemble the following:

One issue
faced early by the IBM design teams was the percentage of tape length that had
to be devoted to these inter–record gaps.There were several possible solutions, and each one was pursued.Better mechanical control of the tape drive
has always been a good choice.

Another way
to handle this problem would be to write only large physical records.Larger records lead to a smaller percentage
of tape length devoted to the inter–record gaps.The efficiency problem arises with multiple
small records, such as images of 80–column cards.

One way to
improve the efficiency of storage for small records on a magnetic tape is to
group the records into larger physical records and store these on tape.The following example is based on the one
above, except that each physical record now holds four records.Note the reduction of the fraction of tape
length devoted to inter–record gaps.

This
process of making more efficient use of tape storage is called record blocking.The program reads or writes logical records that have meaning
within the context of that program.These logical records are blocked into physical records for efficiency of storage.In a particular data set, all physical
records will contain the same number of logical records; the blocking factor is
a constant.The only exception is the
last physical record, which may be only partially filled.

Consider a
set of 17 logical records written to a tape with a blocking factor of 5.There would be four physical records on the
tape.Physical record 1 would contain
logical records 1 – 5,physical record 2 would contain
logical records 6 – 10,physical record 3 would contain
logical records 11 – 15, andphysical record 4 would contain
logical records 16 and 17.

On a
physical tape, it is likely that the last physical record will be the same size
as all others and be padded out with dummy records.In the above example, physical record 4 might
contain two logical records and three dummy records.This is a likely conjecture.

Magnetic
tape drives are not common in most computer systems these days, but the design
feature persists into the design of the modern data set.

Use of the I/O Facilities

In order to
use the data management facilities offered by the I/O system, a few steps are
necessary.The program must do the
following:

1.Describe
the physical characteristics of the data to be read or written with respect to data set organization, record
sizes, record blocking, and buffering to be used.

2.Logically
connect the data set to the program.

3.Access
the records in the data set using the correct macros.

4.Properly
terminate access to the data set so that buffered data (if any)can be properly handled before
the connection is broken.

While some
of these steps might be handled automatically by the run–time system of a
modern high–level language, each must be executed explicitly in an assembler
program.

Style Conventions for Invoking I/O Macros

Some of the
I/O macros, especially the file definition macro, require a number of
parameters in order to specify the operation.This gives rise to a stylistic convention designed to improve the
readability of the program.The most
common convention used here is to use the keyword facility and list only one
parameter per line.

While one
possibly could use positional parameters in invoking an I/O macro, this would
require any reader to consult a programming reference in order to understand
what is intended.Of course, it is
possible for a programmer to forget the proper argument order.

Here is a
file definition macro invocation written in the standard style.

FILEINDCB DDNAME=FILEIN,X

DSORG=PS,X

DEVD=DA,X

RECFM=FB,X

LRECL=80,X

EODAD=A90END,X

MACRF=(GM)

Note the “X”
in column 72 of each of the lines except the last one.This is the continuation character indicating
that the next physical line is a continuation of the logical line.To reiterate a fact, it is the presence of a
non–blank character in column 72 that makes the next line a continuation.Peter Abel [R_02] places a “+”
in that column; that is good practice.

Here is
another style that would probably work.It is based on old FORTRAN usage.

FILEINDCB DDNAME=FILEIN,1

DSORG=PS,2

DEVD=DA,3

RECFM=FB,4

LRECL=80,5

EODAD=A90END,6

MACRF=(GM)

Note that
every line except the last has a comma following the parameter.This is due to the fact that the parameter
string after the DCB should be read as a single line as follows:

The DCB (Data Control Block) is the file definition macro
that is most commonly used in the programs that we shall encounter.As noted above, it is a keyword macro.While the parameters can be passed in any
order, it is good practice to adopt a standard order and use that
exclusively.Some other programmer might
have to read your work.

The example
above shows a DCB invocation that has been shown to work on the particular
mainframe system now being used by Columbus State University.It has the form:

FilenameDCB DDNAME=Symbolic_Name,X

DSORG=Organization,X

DEVD=Device_Type,X

RECFM=Format_Type,X

LRECL=Record_Size,X

EODAD=EOF_Address,X

MACRF=(Input_Operation)

The name
used as the label for the DCB is used by the other macros in order to identify
the file that is being accessed.Consider the following pair of lines.

The example macro has one
problem that might lead to confusion.Consider the line:

FilenameDCB DDNAME=Symbolic_Name,X

The file
name is the same as the symbolic name.This is just a coincidence.In
fact it is the filename, which is the label associated with the DCB, that must
match the other macros.

Here is an
explanation of the above entries in the invocation of the DCB macro.

DDNAME
identifies the file’s symbolic name, such as SYSIN for the
primary system input device and SYSPRINT for the primary listing
device.Here we use a slightly
nonstandard name FILEIN, which is associated with SYSIN by a job
control statement near the end of the program.That line is as follows:

//GO.FILEIN DD *

The “*” in this statement stands for the
standard input device, which is SYSIN.This statement associates the symbolic name FILEIN
with SYSIN.

DSORG
identifies the data set organization.Typical values for this are:PSPhysical
sequential, as in a set of cards with one record per card.

DEVD
defines a particular I/O unit.The only
value we shall use is DA, which indicates a direct
access device, such as a disk.All of
our I/O will be disk oriented; even our print copy will be sent to disk and not
actually placed on paper.

RECFM
specifies the format of the records.The
two common values of the parameter are:FFixed
length and unblockedFBFixed
length and blocked.

LRECL
specified the length (in bytes) of the logical record.A typical value would be
a positive decimal number.Our programs
will all assume the use of 80–column punched cards for input, so that we set LRECL=80.

BLKSIZE
specifies the length (in bytes) of the physical record.Our sample invocation does not use this
parameter, which then assumes its default value. If the record format is FB
(fixed length and blocked), the block size must be an even multiple of the
logical record size.If the record
format is F (fixed length and unblocked), the block size must equal the logical
record size.It is probably a good idea
to accept the default value for this parameter.

EODAD
is a parameter that is specified only for input operations.It specifies the symbolic address of the line
of code to be executed when an end–of–file condition is encountered.

MACRF
specifies the macros to be used to access the records in the data set.In the case of GET and PUT,
it also specifies whether a work area is to be used for processing the
data.The work area is a block of memory
set aside by the user program and used by the program to manipulate the
data.We use MACRF=(GM) to select
the work area option.

The OPEN Macro

This macro
opens the data set and makes its contents available to the program.More than one dataset can be opened with a
single macro invocation.The upper limit
on datasets for a single OPEN statement is 16, but that
number would produce unreadable code.As
a practical matter, your author would prefer an upper limit of two or three
datasets for each invocation of the OPEN macro.

Consider
the following two sequences of macro invocations.Each sequence does the same thing; it opens
two datasets.

Sequence 1 is a single
statement.

OPEN
(FILEIN,(INPUT),PRINTER,(OUTPUT))

Sequence 2 has two statements,
which could appear in either order.

OPEN (FILEIN,(INPUT))OPEN (PRINTER,(OUTPUT))

Each of these statements
assumes that the two Data Control Blocks are defined.

The general format of the OPEN
macro for one file is as follows [R_21, page 67].

[LABEL]OPEN
(ADDRESS[,(OPTIONS)]

Multiple files can be opened at
the same time, by continuing the argument list.

[LABEL]OPEN
(ADDRESS1[,(OPTIONS1),ADDRESS2[,(OPTIONS2)]

Note that
the first argument for opening the dataset is the file name used as the label
for the DCB that defines the dataset.This is the label (address) associated with the DCB, not the symbolic
name of the file (SYSIN, SYSPRINT, etc.).

It is also
possible to pass the address of the DCB in a general–purpose register.When a register is used for this purpose, it
is enclosed in parentheses.Here are two
equivalent code sequences, each of which opens FILEIN for INPUT.

Note the
parentheses around the second argument in each of the two individual
invocations of the OPEN macro.This is a use of the sublist option for macro
parameters [R_17, p. 302].A sublist is
a character string that consists of one or more entries separated by commas and
enclosed in parentheses.What is
happening here is that the macro definition is written for a sublist as a
symbolic parameter, and this is a sublist of exactly one item.

There is
one advantage in creating a separate OPEN statement for each file to be
opened.If the macro fails, the line
number of the failing statement will be returned.With only one file per line, the offending
file is identified immediately.

The Close Macro

This macro
deactivates the connection to a dataset in an orderly fashion.For output datasets, this will flush any data
remaining in the operating system buffers to the dataset, so that nothing is
lost by closing the connection.If
needed, this macro will update any catalog entries for the dataset; in the
Microsoft world this would include the file attributes.

Once a
dataset is closed, it may be accessed again only after it has once again been
opened.

While it may
be possible to execute a program and terminate the execution without issuing a CLOSE
for each open file, this is considered very bad programming practice.

The general format of the CLOSE
macro for one file is as follows [R_21, page 27].

[LABEL]CLOSE (ADDRESS[,(OPTIONS)]

Multiple files can be closed at
the same time, by continuing the argument list.

[LABEL]CLOSE
(ADDRESS1[,(OPTIONS1),ADDRESS2[,(OPTIONS2)]

The code
that has been successfully used in our lab assignments seems not to be of
this form.Here are the lines that we
have used to close the INPUT and PRINTER.

A90ENDCLOSE
FILEIN

CLOSE
PRINTER

The format
above is that preferred for use when running under the DOS operating system,
which is an IBM product not related to the better known Microsoft product.Our programs are run under a variant of the
OS operating system.According to the
standard format for OS, the above statements should have been written as
follows.

A90ENDCLOSE (FILEIN)

CLOSE (PRINTER)

Apparently,
either form of the CLOSE macro for a single file will
work.

When
closing more than one file with a single CLOSE macro, one must allow for
the fact that the options do exist, even if not commonly used.Here is the proper format.

A90ENDCLOSE (FILEIN,,PRINTER)

Notice the
two commas following FILEIN.This indicates that optional
parameter list OPTIONS1
is not used.Were only one comma
present, the assembler would try to interpret the string PRINTER as an option
for closing FILEIN.The
lack of options following the string PRINTERindicates that no options are used for that
close either.

Locate Mode

The next
two system macros to be discussed are GET and PUT.Before discussing either of these, it is
important to note an I/O mode that will not be discussed here.This is called “locate mode”; it allows direct processing of data in the system buffers,
so that the program need not define a work area.As this is a very minor advantage [R_02, page
262], we shall omit this feature and assume that each GET and PUT
references a work area.

The GET Macro

This macro
makes available the next record for processing.The record input overwrites the previous contents of the input
area.There are two general formats as
used with a work area.

[label]GETFilename,Workarea

[label]GET (1),(0)

In each of
these formats, the label
is optional (the reason it is shown in brackets).The filename is that used as the label for the DCB.The system delivers the record to the work area, as
specified in the second argument.

In the
following examples, the file name is FILEIN and the work area is labeled RECDIN.Here are two equivalent code sequences.The first sequence uses the first format.

GETFILEIN,RECDIN

FILEINDCBDefine the input file

RECDINDSCL80This is the input work
area

The second
uses the use of general–purpose registers 0 and 1 in the standard manner to
store the addresses of the file definition area and the work area

LA 1,FILEINAddress of the file definition

LA0,RECDINAddress of the work
area

READIT
GET (1),(0)Read a record into RECDIN.Note thestandard use of the parentheses.

The PUT Macro

This macro
writes a record from the output work area. There are two general formats.

[label]PUTFilename,Workarea

[label]PUT (1),(0)

In each of
these formats, the label
is optional (the reason it is shown in brackets).The filename is that used as the label for the DCB.The system delivers the record to the work area, as
specified in the second argument.

In the
following examples, the file name is PRINTER and the work area is labeled DATOUT.Here are two equivalent code sequences.The first sequence uses the first format.

PUTFILEIN,RECDIN

PRINTERDCBDefine the input file

DATOUT
DSCL133This is the output work
area

The second
uses the use of general–purpose registers 0 and 1 in the standard manner to
store the addresses of the file definition area and the work area