0% found this document useful (0 votes)
34 views541 pages

Assember Edward

This document serves as a textbook introduction to assembly language, specifically the IBM System/370 Assembler Language, and discusses its historical significance and relevance in modern programming. It outlines the reasons for studying assembly language, including its role in understanding computer architecture, improving proficiency in high-level languages, and the legacy of existing assembly code. Additionally, it presents course objectives and a hierarchy of programming languages, emphasizing the unique characteristics of assembly language in relation to hardware architecture.

Uploaded by

sanjitha96bala
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views541 pages

Assember Edward

This document serves as a textbook introduction to assembly language, specifically the IBM System/370 Assembler Language, and discusses its historical significance and relevance in modern programming. It outlines the reasons for studying assembly language, including its role in understanding computer architecture, improving proficiency in high-level languages, and the legacy of existing assembly code. Additionally, it presents course objectives and a hierarchy of programming languages, emphasizing the unique characteristics of assembly language in relation to hardware architecture.

Uploaded by

sanjitha96bala
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 541

Chapter 1 – Why Study Assembly Language?

This is a textbook for a course in assembly language. More specifically it is a course that covers
an older variant (IBM System/ 370 Assembler Language) of the assembly language of the IBM
mainframe series of computers from the System/360 of the 1960’s to the Z–Series of the present
day. The previous statement immediately suggests two questions: what is assembly language
and why should one study it?
In answering these two questions, we mention explicitly the one assumption about the intended
reader of this book, that he or she has programmed a computer in some higher–level language;
possibly Java, C++, Basic, LISP, Python, or COBOL. Other than the fact that each can be used
in a beginning course on programming, the common feature of these languages is that each
normally considered a higher–level language. The structure of such a language is based on the
class of problems it is intended to solve; the expressions of such a language facilitate formulation
of a solution to the associated problems. Another common feature of such languages is that each
is built around a core component common to all implementations, though often with extensions
that are specific to a given manufacturer and computer model.
An assembly language and its more primitive variant, machine language, has a structure that
reflects the hardware architecture of a specific computer. While an assembly language might
have constructs that facilitate solution of a specific class of problems, this reflects only the fact
that the underlying hardware architecture has been designed with that goal in mind. As an
example, the assembly language of the IBM mainframe computers contains many features to
facilitate solution of business–oriented problems; this is due only to the fact that the designers of
the computer decided to build a hardware architecture to support these features. It is worth
noting that IBM has elected to use the name “Assembler Language” for what most others call
“assembly language”; the two terms should be viewed as synonymous.
Given the fact that almost all computer programming is now done in a higher–level language, it
is unlikely that any student will spend a significant amount of time either writing or modifying
an assembly language program. Given that fact, we repeat the question “Why study assembly?”.
The answer should be developed historically, beginning with an answer that would have been
given in 1950 and evolving into an answer that is valid today.
In the earliest digital computers any question about an assembly language would not have been
reasonable; assembly language had yet to be invented. Indeed the ENIAC, one of the first
general purpose digital computers, was not even a stored program computer; it was programmed
by connecting coaxial cables and setting switches. Lacking a program memory, the ENIAC
lacked any programming language, including an assembly language.
One of the earliest confirmable uses of assembly language was in the EDSAC, designed by
Maurice Wilkes of Cambridge University (Cambridge, England), beginning in late 1946 or 1947.
The EDSAC Assembly Language was described in 1951 in a book by Wilkes, Wheeler, and Gill
[R_01]. At the time, Wilkes used the term “orders” for what we call “instructions”.

Page 1 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

The earliest stored–program computers, the EDVAC and EDSAC, were designed in the late
1940’s. Beginning with these computers, we assume that each computer is programmed in
some sort of language and ask why assembly language might be used. As noted above, the
answer depends on the year in which the question is asked.
Here we must introduce a bit of terminology. Both assembly language programs and high–level
language programs are written first in text that is readable by humans. From this form, it must be
processed into a binary form that can be interpreted and executed by the computer. For assembly
language programs, this process is called assembly and is done by an assembler. High–level
languages are said to be compiled into binary form by a compiler.
In the 1950’s you would study assembly language because high–level languages were yet to be
developed. Other than primitive binary machine language, assembly language was the only way
to program a computer. FORTRAN (Formula Translation), introduced by IBM in 1957, was
one of the first high–level languages that served as an alternative to assembly language.
In the 1960’s and 1970’s, one would study assembly language for two purposes: either to
maintain a base of legacy code written in assembly language or to enhance the performance of
time–critical parts of code generated by a compiler. Most compilers of the time would emit an
equivalent assembly language program prior to conversion to binary machine language. It was
common practice to edit these intermediate assembly code files and then assemble these, while
discarding the original machine language produced by the compiler. In 1972 the author of these
notes used that process to program a PDP–9. The resulting assembly language program executed
at least twice as fast as the equivalent compiled FORTRAN code.
Writing in 1979, Peter Abel [R_02] was still able to state that “programs (or even parts of
programs) written in assembler may be considerably more efficient in storage space and
execution time, a useful consideration if such programs are run frequently”. One might note the
considerable advance in compiler design of the 1980’s and early 1990’s that increased the
efficiency of compiled programs (both time and space) to the level that even the most proficient
programmers have difficulty writing assembly language that is more efficient.
Legacy code continues to be a reason to study assembly language, though increasingly a minor
one. The legacy code problem is a side effect of a design choice best represented by the slang
expression “If it ain’t broke, don’t fix it”. Many companies had a large installed base of
assembly language programs. These programs ran well and produced reliable results. Often
these programs required minor modifications or extensions (such as adding Zip Codes to
addresses). The choice was always either to redesign the code and implement it in a high–level
language, such as COBOL, or modify the assembly language. Since the second option required
much less in the way of programming, it was considered to be the lower risk option.
Prior to the middle 1990’s, there was another very significant reason to study assembly language.
When an executing program encountered an error (such as division by zero, attempting to access
an invalid memory address, or trying to open a non–existent file), it would “abort” and produce a
“core dump”, containing the absolute binary representation of all of the memory address space
allocated to the program. The programmer was required to read this absolute binary, reverse
engineer it to equivalent assembly language code, and determine the offending instruction and
what was to be done to correct the situation. The appearance of modern programming
environments with their sophisticated debugging tools has removed this requirement.

Page 2 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

For today, almost no new code is written in assembly language and legacy code has become a
minor issue. Modern programming environments with their powerful debugging tools have
removed the requirement to read “crash dumps” and convert them to assembly language. Other
than the rather ethically dubious process of reverse engineering commercial code in order to
create unauthorized copies, we must look elsewhere for reasons to study assembly language. For
the students of Computer Science as an academic discipline, there remain a few valid reasons.
1. A knowledge of assembly language can help a programmer become more proficient in
high–level languages. For example, there are many design peculiarities in the COBOL
language that become obvious only when one understands the underlying assembler.
2. An understanding of an assembly language greatly facilitates the study of the architecture
and organization of the computer upon which that assembly language is executed. It is
your author’s opinion that a knowledge of assembly language is absolutely essential to
the understanding of how computers are designed and why certain design choices have
been made. Indeed, one essential part of the study of a computer architecture is a study
of its ISA (Instruction Set Architecture), essentially its assembly language.
3. An ability to program in basic assembly language will help the student to understand and
more fully appreciate the services provided by the run–time systems associated with all
modern high–level programming languages. Examples of these services include: file
handling, management of variable–length strings, allocation of dynamic memory,
management of the stack and recursive procedure calls, the function of a relocating
loader and assignment of absolute addresses in memory, DLL (Dynamic Link Libraries),
and many other common features that are quite useful and often taken for granted.
4. One reason to study IBM System/370 assembler is related to the reason just stated. The
System/370 assembler language is a subset of that used on the more recent and powerful
IBM mainframe computers, variously called either “zSeries” or “Series Z”. The syntax
of the language is rather simple and easy to grasp. The choices made in the design of
this language reflect the choices dictated by the computer architecture of the day, thus
allowing the student to reflect on the interaction of hardware and software design. There
is also the fact that the System/370 assembler language provides very few constructs to
support directly the higher–level constructs commons in a modern run–time systems.
This latter fact allows for programming assignments that use the low–level code to
implement these higher–level functions, possibly leading to a greater understanding.
5. We finally note that there might be some geographic reasons to study System/370
assembler language. From a pure didactic view, this author believes it important for
every student majoring in Computer Science to study and understand some commonly
used assembly language. In the Columbus GA area, there are a few large industries that
continue to use IBM mainframe computers and occasionally legacy code written in
assembler language to be modified and extended. For Columbus State University,
the choice of System/370 assembler language is just a reaction to local demand.
As will become obvious, the focus of this textbook is on writing system code, the interaction of
that code with the ISA of the target machine, and on understanding the functioning of the target
machine at a very deep level. In this, the book differs fundamentally from other excellent texts,
such as the one by Peter Abel [R_02], who appears to expect that his readers will actually use
assembler language to write new financial systems. That is what COBOL is for.

Page 3 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

Course Objectives (Learning Outcomes)


One of the better ways to explain this textbook is to state the learning objectives for the course
for which this text has been written. This course is not a traditional course in assembly language.
While the student is expected to become somewhat proficient in IBM Mainframe Assembler by
the end of the course, the focus will be on the understanding of 1) the ISA (Instruction Set
Architecture) and 2) the services provided by a modern run time system.
At the end of the course the student will be able to describe and explain the following:
1. The binary representations used by IBM for character, integer, and floating–point
data and how these differ from those used in more common computers.
2. How to use zoned decimal and packed decimal data. How these differ from and
extend standard two’s–complement arithmetic and standard floating–point formats.
Conversions from any one of these formats to any of the other formats.
3. The IBM view of data organization into fields, records and files.
The assembler declaratives that support record definition.
4. How to edit and assemble a program using the older–style tools associated
with the IBM Mainframe environment.
5. The basic functions of a two–pass Assembler in producing object code.
6. The basic functions of a Link Editor in producing an executable module.
7. The use of the DS and DC declaratives to define and initialize storage.
Understand the importance of boundary alignment in the use of these declaratives.
8. Addressing modes in the IBM 370, focusing on the use of base registers.
9. How to write simple assembler programs that process character and decimal data.
This will include producing and running a number of small assembler programs.
10. How to link separately assembled programs and pass data among them.
11. The basic design and uses of magnetic tape (obsolete) and disk storage.
12. The basic data architecture of the ISAM and VSAM storage methods.
13. The physical and data architecture of physical I/O and data channels.
The remaining learning goals focus on building a modern run–time system.
14. Several methods to represent and process variable–length strings.
15. How to create and process static arrays with automatic bounds checking.
16. How to create and process a singly linked list.
17. How to create and use a stack to store data, addresses, or both.
18. How to write a simple recursive function by explicit use of a stack.
19, How to write reentrant code, which is required for most systems programs.
20. CPU hardware support for the Operating System.
21. Virtual storage (virtual memory) as implemented on the IBM 370/

Page 4 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

The Hierarchy of Programming Languages


Another way to view assembler language is to place it in a hierarchy of programming languages
from the very high level languages, down to microcode. Many authors of textbooks on computer
architecture and organization use the term “virtual machine” as a method to express this concept,
though the term does have other uses that are quite distinct. One use of the term as we intend it
here is seen in the name “JVM”, for “Java Virtual Machine”. Java is a popular high–level
language developed by Sun Microsystems, Inc. The method for executing a Java program is first
to compile the code into an intermediate language, called “byte code”. This byte code is then
executed by an emulator called the JVM. To the user, the JVM presents itself as a real computer
with real hardware. In fact, it is a program that executes in the native mode of the host machine.
While it would be quite possible to design an architecture for direct execution of Java byte code,
it has been thought unnecessary to do so. This use of a lower–level machine to give the
appearance of direct execution of a higher–level language is the heart of the virtual machine idea.
The top level of this language hierarchy, though seldom recognized, might be called by a name
such as “computer as appliance”; it just does its job. As an example, consider the secretary
who uses the computer for e–mail, word processing, and financial spreadsheets. The mechanism
by which the computer executes each task is almost unimportant; just get it done.
The top level of the traditional language hierarchy comprises problem–oriented languages that
are usually called “high level languages”. Examples of these languages include Java, C++,
Visual Basic, LISP, Snobol, Prolog, FORTRAN, and COBOL. One of the distinguishing
features of such languages is that the syntax and semantics reflect the structure of the problems
most commonly solved by those languages. Though many of these languages, especially
FORTRAN, contained extensions tailored to specific computer architectures, in general the
languages are seen as platform–independent.
The language layer below that of high level languages is that of assembly language. The main
distinguishing feature of an assembly language is its close correspondence to the hardware
architecture of the specific computer. While there is one version of Java that can be executed
equally well on a Sun SPARC, Apple Macintosh, Pentium 4, or IBM zSeries; each of these
platforms has its distinct assembly language. None of these assembly languages is remotely
compatible with an assembly language on the other platform.
Let us consider a simulation problem, such as weather modeling. Suppose the code is to be run
on an IBM System/370. One way to highlight the difference between a high–level language and
the assembler language is to make the following observation. In order to understand the program
in a high–level language, it is necessary to understand the problem being solved. In order to
understand the program as written in System/370 assembler, one must also understand the
architecture and organization of the underlying hardware.
Assembly language is related to a more primitive variant, called “machine language”. Some
experts consider machine language to occupy a lower level than assembly language; others place
it at the same level. The real difference is that assembly language programs are written to be
read by humans, and use mnemonics that are easy to understand. Machine language programs
are written as a sequence of binary numbers, which are made marginally more readable by being
rendered as hexadecimal (base 16) values.

Page 5 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

In order to see the difference between the two (or three) levels of languages, we adopt an
example from the textbook by Patterson and Hennessy [R_04]. We begin with a fragment of
code written in either C or C++ (though some purists claim that neither is high level).
Here is the code fragment, with some reasonable comments added.
swap (int v[], int k)
{ int temp ; // Swap element v[k] with v[k+1]
temp = v[k]; // Save element v[k]
v[k] = v[k+1]; // Move v[k+1] down.
v[k+1] = temp; // Replace the value of v[k+1]
}
Here is the code as written in the assembly language for a computer called MIPS. While most
assembly languages, including both MIPS assembler and System/370 assembler, provide for
comments, this code will not be commented. This translation of the C++ code above is a bit
misleading in that three executable lines are expanded only to seven assembly language lines.
Most expansions are four to eight lines of assembly language for each high–level statement.
swap:
muli $2, $5, 4
add $2, $4, $2
lw $15, 0($2)
lw $16, 4($2)
sw $16, 0($2)
sw $15, 4($2)
jr $31
We now give the translation of this assembly language code into machine language. Each
assembly language instruction directly corresponds to a 32–bit binary machine language
instruction, which we shall represent in hexadecimal form.
00 A1 00 18
00 18 18 21
8C 62 00 00
8C F2 00 04
AC F2 00 00
AC 62 00 04
03 E0 00 08
On all modern stored–program computers, it is a version of the binary machine language that is
executed. The basis of this execution is called either “Fetch/Execute” or some variant of that
name; this is the basic cycle of a modern stored–program computer. Each machine language
instruction is fetched from memory and copied into a special register, called the “Instruction
Register”, where it is decoded and executed. This is the native language of the computer.
As a historical fact, the languages were developed “bottom to top”, with machine language being
the first developed. Almost immediately, assembly language was developed mostly because it
used mnemonics and was much easier for a human to read. High–level languages were a later
development. Recent research and development related to high–level languages has focused on
more sophisticated compilers and support for parallel processing.

Page 6 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

We shall now mention a few of the more obvious differences between high–level languages and
assembly languages. We begin with the definitions of the process that converts the language into
the machine language that is ready to be loaded into memory and executed. By definition, all
high–level language programs are said to be compiled, while assembly language programs are
said to be assembled. While this difference may seem to be just one of semantics, we shall
quickly see that compilers are usually much more sophisticated than assemblers.
We now ask about the output of the compiler. In this context, we have two basic options: either
machine language or assembly language that is then assembled. The option chosen by IBM is
for each compiler to emit assembly language, which is processed by a common assembler.

Some of the other more common differences between compiled and assembled languages are:
1. Assembly language statements almost always map one–to–one into machine language
statements; one assembly language statement generates one machine language word.
High–level language statements usually generate a number of machine language words,
commonly in the range 3 to 8; with more being possible.
2. High–level languages provide for the declaration of variables by types and associate
the proper operations with them. Assembly languages provide only for the allocation
of storage space and rely on the assembly language instruction to be specific about the
data type. In other words, high–level languages select the operation appropriate for the
type of the variable, while the assembly language uses the operation specified.
3. Compilers for high–level languages have become quite sophisticated in the optimal
use of system resources, such as the general purpose registers in the CPU. This usually
leads to executable code that is quite efficient. It is worth noting that many early
compiler writers considered the problem of optimal register allocation to be unsolvable,
until one bright designer recognized it as the equivalent of a well known problem in
mathematical graph theory. Once this was seen, the problem was easily solved.
4. It is said that compilers are yet to become sufficiently sophisticated in allocating
resources for parallel execution on a multi–CPU (or multi–core) computer. While
assembly language programs can allocate the resources explicitly, your author expects
considerable progress to be made in compilation for parallel execution.
5. The code for every operating system does require some basic operations, such as
interrupt management, that are not easily provided in a high level language. For this
reason, one may expect assembly language to play a minor part in all future systems.

Page 7 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

Let us consider the second point by assuming a machine, such as the System/370, that supports
both 32–bit integer arithmetic and 32–bit floating point (real) numbers. Consider the following
fragment, written in a FORTRAN–like high level language.
X = 2
Y = 3
Z = X + Y
The values 2 and 3 are integer constants. The symbols X, Y, and Z represent variables. The
compiler allocated 32–bits (four bytes) for the storage of each, as will the assembler. However,
the compiler will use the variable type declarations (either implicit or explicit, as in Java) to
determine the operations. If all of X, Y, and Z represent integer variables, the first two
assignments are quite simple and it is integer addition that is invoked.
Suppose now that each of X, Y, and Z represent real numbers. The first two assignment
statements involve conversion of the integer values to the equivalent real number values,
2.0 and 3.0. Most modern compilers will do this at compile time, thus avoiding the overhead of
run–time translation. The addition is now the operation appropriate for real numbers.
Note again the fact that it is the type declarations for the variables that determines what type of
assembly language is emitted by the compiler for the three statements being considered.
We close this section by mentioning a newer assembler language developed by IBM and stating
the reasons that it might be preferable to a high–level language. Here, we must note that the
author of this textbook has no experience directly related to these arguments, but finds them
quite plausible. These reasons are taken from a presentation by Kristine H. Neely [R_03]
1. HLASM, the new High Level Assembler, now directly supports all of the
structures required for structured programming. Multiple direct branches are
no longer required.
2. HLASM can create programs that “break” the addressing limits imposed by
some high–level languages. This may be called the “2 GB bar”.
3. HLASM has provisions for explicit control of multiple processors operating in
parallel. At present, the facilities offered by high–level languages lack the
sophistication that can be explicitly achieved by programming in HLASM.
[Your author’s note: This may change soon.]
The introduction of this new high level assembler raises the question about the complexity
desired in a modern assembly language. A number of modern assemblers, such at the IBM
product HLSAM, contain almost enough features to rank them as high–level languages. There
are two variants of this complexity problem, only one of which having an obvious answer.
1. The first variant is similar to that seen in the VAX/11–780 and other members of the
VAX family (often called “Vaxen” by pundits familiar with German). Here, the complex
assembly language is a direct result of the complexity of the underlying machine. One
of the standard results of modern computer design theory is that complex machines are
less desirable than machines more simply designed; simpler means faster.
2. The second variant calls for the complex assembly language to be processed by
sophisticated pre–processor into a simpler standard assembly language. This approach
has no implications for the underlying machine.

Page 8 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Why Study Assembly Language

What Lies Beneath


The student of computer architecture will realize that the hierarchy of languages does not convey
the whole story about hardware and software architecture. We have taken this hierarchy down
only to the machine language level. Below that level, lie a number of very important levels.
The microarchitecture level deals with the control structures that cause the computer to execute
the instructions found in the sequence of machine language words.
The device level deals with the construction of the circuits used by the microarchitecture in order
to execute the machine language. These are built from basic devices, often called “logic gates”.
The electrical engineering layer deals with how to fabricate the basic devices (or gates) from
the basic circuit elements: transistors, resistors, capacitors, inductors, and conducting traces.
The solid state layer deals with how to fabricate basic circuit elements with new desirable
qualities. Normally the requirement is either that they be faster or dissipate less heat.
A course in Computer Architecture and Design (such as CPSC 5155 taught at Columbus State
University in Columbus GA) will address issues in the microarchitecture level and device level.
Any course in assembly language must stop at the machine language level.

Page 9 Chapter 1 Last Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 2 – Structure of an IBM Mainframe Assembler Language Program
One of the main issues in learning Assembler Language for the IBM Mainframe Series, such as
the IBM/370 and following models, is the environment in which the programming is done. This
is a set of notes on accessing the IBM Mainframe and creating an assembler language program to
run on that system. Much of what is said here can be applied to running other programs, such as
COBOL, on the Mainframe. This chapter was revised in January 2009 to reflect the new IBM
Mainframe to which Columbus State University was recently granted access.
The chapter begins with a description of how to log on to our mainframe, presents some cautions
in use of the emulator, discusses the structure of an Assembler program that will run on the CSU
mainframe, and closes with a discussion of the use of the editor and other system utilities.
The reader should note that almost all of the illustrations in this chapter are screen shots taken
from the standard CSU terminal emulator, using the standard screen style. Other styles can be
used; the more common option being one with the background display set to black. While this
option displays well, it does not print well. For this reason, I have chosen the style used.
Use of the Terminal Emulator
Before starting our discussion on accessing an IBM Mainframe, it is important to discuss some
cautions in use of the terminal emulator. There are significant differences between the use of the
keyboard for this tool and for the normal programming as done in class.
Maintaining the Terminal Session
As noted below, the first thing to do when running a program on the Mainframe is to launch the
terminal emulator on your PC and log onto the Mainframe. This establishes a session on the
Mainframe and allows you to edit and run programs.
It is very important that you log off the Mainframe in an orderly manner. It is almost always not
acceptable just to close the Terminal Emulator as one would close any MS–Windows program
before logging off the Mainframe. If you do that, the Mainframe will maintain your session for a
time (possibly 15 minutes to an hour) and not allow you to log back on.
This caution also applies if the session is dropped due to any other errors; e.g. bad transmission.
Keyboard Lock
Another event that frequently happens is that the emulator will stop responding to key strokes.
At this point, you might see “XMIT Lock” in the display bar at the bottom of the emulator
window. To clear this, hit the ESC (Escape) key a number of times. If that does not work, then
alternatively hit Ctrl–Q and Ctrl–S. You cannot proceed until the keyboard is unlocked.

Beware of the Overwrite Mode


The normal (and preferred) mode for running the emulator is called Overwrite, as opposed to
Insert. Most word processors can be operated in either mode, but commonly work in Insert.
While operating the terminal emulator in Insert Mode can yield complex and perplexing results,
we note here that misuse of the Overwrite mode can lead to predictable, but wrong, results.
Consider the problem of altering the string “AAABBBCCC” to read “AAADDDCCC”. In Insert
mode, one might place the cursor after the “BBB”, backspace 3 times, and then insert the “DDD”.

Page 10 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Consider what happens in Overwrite Mode. First position the cursor after the BBB to get
AAABBB|CCC

Then backspace three times to get the string


AAA|CCC

Then enter the string “DDD”. The result is logical, but surprising. The new string is
AAADDD|

What has happened is that the “CCC” in the string “AAACCC” has been overwritten to produce
the result “AAADDD”. The “CCC” was not “moved over” so that the string “DDD” could be
placed in front of it; the string “CCC” just replaced the next three characters in the old string.

Be Cautious About “Non Standard” Keys


Here I have a very precise definition for the non–standard term “Non Standard Key”. It is a key
that does not immediately correspond to a key on the IBM 029 card punch. Within this arbitrary
definition, let us stipulate that lower case letters correspond to upper case letters, all of which are
present on the IBM 029.
With a few exceptions, the “standard keys” are those that produce printable characters. One way
to refer to this set of keys is to call them the “Character Keys”, though this is not a standard
usage. On the standard keyboard, these include the alphabetical keys, the digit keys directly
above them, the space bar (it produces the “ ” character), the shift key (which produces no
character), and the characters generated by pressing the shift key and one of the other mentioned
keys. This set of keys specifically DOES NOT INCLUDE the keys in the Numeric Keypad to
the right of a standard keyboard.

Page 11 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

We now note that most terminal emulators are not guaranteed to handle all of the standard keys
correctly. Let us ignore the Multimedia Keys and Internet Controls (which nobody would expect
to work) and discuss the other keys.
The Numeric Keypad keys emit scan codes that may differ from those emitted by the digit keys
that are at the top of the alphabetical set. These might be converted into different EBCDID
codes by the terminal emulator, and thus be misinterpreted by the Mainframe.
The Toggle Keys emit codes that generally have no meaning to most terminal emulators.
The Cursor Control Keys can be used in certain contexts, such as moving over text. They
should not be viewed as introducing a space character, though they may seem to do so.
The Function Keys are correctly interpreted by the emulator and passed to the Mainframe.
The following keys can be used with the standard terminal emulator packages: the character
keys, the Function Keys, and (occasionally) the Cursor Control Keys. In general, the Control
Key, Alt Key, Windows Key, keys in the Numeric Keypad, and the Toggle Keys should be
avoided. While these often work, they occasionally will cause the keyboard to freeze.
Logging onto the Mainframe
The first step is to run a terminal emulator. What we have on the computers
at CSU is called “zScope Classic”, currently version 5.1. I double click the icon.
The program starts. In the status line at the bottom of the screen and below what will become the
display, one sees two words: “OFF LINE” and “Overwrite”. The standard for the mainframe is
editing in the overwrite mode, in which the characters typed will replace the existing characters.
The “OFF LINE” is an indication that one needs to connect to the mainframe before proceeding.
Go to the File menu at the top and click on Connect (Alt C). Another option is to click on the
“lightning bolt” icon just below the File menu. You will be connected to the mainframe. At this
point, you should see a splash screen with “ENTER L FOLLOWED BY THE APPLID YOU
WISH TO LOGON TO”. Immediately we see that we have landed in UPPERCASE LAND, the
standard style for the classis mainframe application. You might as well set the “CAPS LOCK”
on your keyboard.
L TSO
Enter the above line, followed by a carriage return (the Enter key). You will be prompted for a
user ID. I entered my seven–character ID. You should use the user ID assigned to you by the
instructor. You are taken to another screen, with the cursor positioned at the place for entry of
your seven–character password.
If this is your first use of the mainframe, your password will be set to your user ID. You will be
required to change the password before proceeding. Enter the password followed by a CR (hit
the enter key). DO NOT USE MORE THAN SEVEN CHARACTERS FOR THE PASSWORD,
as this can lead to effects that will appear to be random, though they are predictable.
At this point, you will see several screens of announcements, the last one ending with “LAST
MESSAGE FROM VENDOR.CLIST”. Hit the Enter Key at the end of each of these displays.
On hitting the Enter Key after the last key, you will be presented with the ISPF Primary Options
Menu (shown below, using my display option).

Page 12 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

If you use another screen style, your display will appear different, but have this content.

Editing a File
There are two tasks here: find the file that you want to edit and actually editing it.
I chose menu option 2. This takes me to a menu with a lot on it, including:
ISPF Library
Project _________
Group _________
Type _________
Member _________
For the project enter your user ID. This is an assembly language course, so the group is ASM.
We edit source code, so the Type is SRC. Since I have logged on before, the system remembers
what I last looked at and displays as follows.
ISPF Library
Project CSU0003__
Group ASM______
Type SRC_____
Member _________
This is what I want, so I hit the enter key.

Page 13 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The EDIT Screen


What now displays is titled “EDIT CSU0003.CS3121.ASSY”. I would call it a “File Listing”,
though I am confident that this is not IBM terminology. I now must select a file to edit.
My listing shows five lines, appearing approximately as follows.
JCLPOST
LAB1
LAB1EBGO
POSTJCL
POST1JCL
It is time to select a line and thereby select a file to be edited. It is here that we first encounter
what I call “dual mode” editing. At times certain keys act as commands to the system, moving
the cursor and so forth. At other times, the keys act as text to be input into a file.
Here use the TAB key as a command key to move the cursor to the dot in front of the name
of the file that you want to edit. I have chosen LAB1EBGO. Input the single character “S”,
followed by the ENTER key to edit the file. You are in Command Mode.
You should now see a screen that resembles the following. We shall discuss this later.

Page 14 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

A Sample Program
Here is the complete text of the sample program, listed with the line numbers removed.
There are two reasons for this: 1. The student will not type in any line number, and
2, With line numbers, I could not fit this on the page.
This listing is “as is”; later we shall comments on the program section by section.
//CSU0003A JOB (ASSY),'ED BOZ',CLASS=A,MSGCLASS=A,
// NOTIFY=&SYSUID,MSGLEVEL=(0,0)
//ASM EXEC PROC=HLASMCLG
//SYSIN DD *
TITLE 'ED B - FROM SKELETON ASSEMBLER PROGRAM'
PRINT ON,NODATA,NOGEN
******************************************************************
* *
* PROGRAMMER: EDWARD BOSWORTH, COLUMBUS STATE UNIVERSITY *
* ASSIGNMENT: FIRST LAB ASSIGNMENT FOR CPSC 3121 *
* DATE : JANUARY 21, 2009 *
* COMMENTS : THIS ALLOWS THE STUDENT TO LEAN HOW TO ENTER *
* : A PROGRAM ON THE MAINFRAME AND EXECUTE IT. *
* *
******************************************************************
* *
* REGISTER EQUATES *
* *
******************************************************************
R0 EQU 0
R1 EQU 1
R2 EQU 2
R3 EQU 3
R4 EQU 4
R5 EQU 5
R6 EQU 6
R7 EQU 7
R8 EQU 8
R9 EQU 9
R10 EQU 10
R11 EQU 11
R12 EQU 12
R13 EQU 13
R14 EQU 14
R15 EQU 15
******************************************************************
LAB1 CSECT
SAVE (14,12) SAVE THE CALLER'S REGISTERS
BALR R12,0 ESTABLISH
USING *,R12 ADDRESSABILITY
LA R2,SAVEAREA ADDRESS OF MY SAVE AREA
ST R2,8(,R13) FORWARD CHAIN MINE
ST R13,SAVEAREA+4 BACKWARD CHAIN CALLER'S
LR R13,R2 SET 13 FROM MY SUB CALLS

Page 15 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

***************************************************
* BEGIN THE PROGRAM LOGIC. FIRST OPEN THE INPUT AND OUTPUT
*
OPEN (PRINTER,(OUTPUT))
OPEN (FILEIN,(INPUT))
PUT PRINTER,PRHEAD PRINT THE HEADER
GET FILEIN,RECORDIN GET THE FIRST RECORD, IF THERE
*
* READ AND PRINT LOOP
*
A10LOOP MVC DATAPR,RECORDIN MOVE INPUT RECORD
PUT PRINTER,PRINT PRINT THE RECORD
GET FILEIN,RECORDIN GET THE NEXT RECORD
B A10LOOP GO BACK AND PROCESS
*
* END OF INPUT PROCESSING
*
A90END CLOSE (FILEIN) CLOSE THE FILES...
CLOSE (PRINTER)
L R13,SAVEAREA+4 POINT AT OLD SAVE AREA
LM R14,R12,12(R13) RESTORE THE REGISTERS
LA R15,0 RETURN CODE = 0
BR R14 RETURN TO OPERATING SYSTEM
******************************************************************
* *
* OUTPUT FILE - DATA CONTROL BLOCK *
* *
******************************************************************
PRINTER DCB DSORG=PS, X
MACRF=(PM), X
DEVD=DA, X
DDNAME=PRINTER, X
RECFM=FM, X
LRECL=133
******************************************************************
* *
* INPUT FILE - DATA CONTROL BLOCK *
* *
******************************************************************
FILEIN DCB DSORG=PS, X
MACRF=(GM), X
DEVD=DA, X
DDNAME=FILEIN, X
EODAD=A90END, X
RECFM=FB, X
LRECL=80

Page 16 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

******************************************************************
*
* INPUT RECORD AREA
*
******************************************************************
RECORDIN DS CL80
******************************************************************
*
* OUTPUT RECORD AREA
*
******************************************************************
*
* HERE IS THE HEADER FOR SPRING 2009
*
PRHEAD DS 0CL133
PRC1 DC C' ' PRINT CONTROL - PRINT ON NEXT LINE
DC CL10' '
DC CL122'***COLUMBUS STATE UNIVERSITY SPRING 2009***'
*
PRINT DS 0CL133 PRINT AREA
PRC2 DC C' ' PRINT CONTROL CHARACTER
DC CL10' '
DATAPR DC CL80' '
DC CL42' '
******************************************************************
*
* REGISTER SAVE AREA
*
******************************************************************
SAVEAREA DS 18F
******************************************************************
*
* LITERAL POOL - THIS PROGRAM DOES NOT USE LITERALS.
*
******************************************************************
* LTORG *
END LAB1
/*
//G.PRINTER DD SYSOUT=*
//G.FILEIN DD *
LINE 1 SPRING 2009
LINE 2 SPRING 2009
LINE 3 SPRING 2009
LINE 4 SPRING 2009
/*
//

Page 17 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Column Conventions in the Assembler Program


The column conventions are as follows:
Columns 1 – 8 The name or label of the statement or declarative
Column 9 This must be blank
Columns 10 – 14 The operation: instruction, declarative, or macro
Column 15 This must be blank
Columns 16 – 71 The operands for the operation.
Any continuation line must begin in column 16.
Column 72 If nonblank, the next line is a continuation of this one.

Consider the following example, taken from the sample program.


PRINTER DCB DDNAME=PRINTER, X
DSORG=PS, X
DEVD=DA, X
MACRF=(PM), X
LRECL=133, X
RECFM=FM
The label PRINTER is placed in columns 1 – 7
The DCB macro is placed in columns 10 – 12
The arguments are placed in columns 16 – 71, the continuation mark is in column 72.

More on Column Conventions


Were we to use the COLS command in the editor, we would see the following
for the first line of the statement above.
PRINTER DCB DDNAME=PRINTER, X
000000000111111111122222222223333333333444444444455555555556666666666777
123456789012345678901234567890123456789012345678901234567890123456789012

Coding forms
It used to be common practice to have coding forms with the columns clearly indicated.
On such a form, the DCB statement might appear as follows, except that the form would have
been used by a human; thus the text would have been hand written.

We shall discuss the meaning (semantics) of this statement in a later slide.


At the moment, the only point is to emphasize the importance of proper column alignment.

Page 18 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The Sample Program with Comments


These notes will focus on a sample program that was assigned for all students to execute on the
mainframe. This lecture contains both code fragments and annotations on those code fragments.
Code fragments will be presented in the font Courier New (bold), as follows.
SAVE (14,12)
All other material will be in the standard font Times New Roman, as is this sentence.
The student will recall that the input to the assembler is not free–form; column placement is
extremely important. Your instructor discovered this fact when an otherwise correct program
would not assembly correctly.

We first list the entire program, as it would appear in the IBM editor before being submitted for
execution. We then present a series of comments on the sample program.

Job Control Statements


In order to understand the structure of the sample program, one must imagine a “batch job”,
which is a sequence of cards submitted to the computer.

Your input file comprises a sequence of lines of text. Each line of text should be
viewed as a “card image”, basically eighty characters with some of them blanks.

Here is the job control language from my submission of the program.

//CSU0003A JOB (ASSY),'ED BOZ',CLASS=A,MSGCLASS=A,


// NOTIFY=&SYSUID,MSGLEVEL=(0,0)
//ASM EXEC PROC=HLASMCLG
//SYSIN DD *
Each student should employ a unique job name based on the user ID (mine is obviously
CSU0003), with a single letter appended. The notify line should contains the string
“&SYSUID”, indicating that the user should receive all notifications.

The next line seems to indicate to execute HLASM, the high level assembler, with the option to
compile, load, and go – assemble the program and execute it.
The next line indicates that the input will be from the lines of text following the JCL.
The next line invokes the TITLE macro to place the title at the top of each printed page.
TITLE 'ED B - FROM SKELETON ASSEMBLER PROGRAM'
PRINT ON,NODATA,NOGEN
The assembler directive PRINT ON,NODATA,NOGEN deserves a comment. This is a directive
to the assembler on formatting the listing, but not to expand the macros (defined later).
The course will include an assignment in which you will write your own macros. When you do
that, change the above print directive to
PRINT ON,NODATA,GEN so that you can see your macro expansions.

Page 19 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The next section of the code shows some comments. Within the context of the assembler
program, any line of text that begins with an asterisk (“*”), is taken as a comment.
****************************************************************
*
* PROGRAMMER: EDWARD BOSWORTH, COLUMBUS STATE UNIVERSITY
* ASSIGNMENT: FIRST LAB ASSIGNMENT FOR CPSC 3121
* DATE : JANUARY 21, 2009
* COMMENTS : THIS ALLOWS THE STUDENT TO LEAN HOW TO ENTER
* : A PROGRAM ON THE MAINFRAME AND EXECUTE IT.
*
****************************************************************

The Register Equates


The next section of the code contains a number of EQU statements. This is essentially a set of
substitution statements allowing use of labels for the numeric register designators. Without
these, one would have to write code such as BALR 12,0 rather than BALR R12,0.
****************************************************************
* REGISTER EQUATES
****************************************************************
R0 EQU 0
R1 EQU 1
R2 EQU 2
R3 EQU 3
R4 EQU 4
R5 EQU 5
R6 EQU 6
R7 EQU 7
R8 EQU 8
R9 EQU 9
R10 EQU 10
R11 EQU 11
R12 EQU 12
R13 EQU 13
R14 EQU 14
R15 EQU 15
**************************************************************

The next section of code should be viewed as the start of the executable part of the program. The
structure of this part reflects the reality that a user program is handled by the Mainframe
Operating System as a subroutine or function. What this section of code does is to set up the
standard linkage from a subprogram to the program that called it. This is useful for processing
error output, and allows operations such as tracing the call stack, etc.

Page 20 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Here is the code section.


**************************************************************
LAB1 CSECT
SAVE (14,12) SAVE THE CALLER'S REGISTERS
BALR R12,0 ESTABLISH
USING *,R12 ADDRESSABILITY
LA R2,SAVEAREA ADDRESS OF MY SAVE AREA
ST R2,8(,R13) FORWARD CHAIN MINE
ST R13,SAVEAREA+4 BACKWARD CHAIN CALLER'S
LR R13,R2 SET 13 FROM MY SUB CALLS
**************************************************************
This code should be viewed as “boilerplate”, which is code that should be the start of any
program written. All assembler language programs should start this way, changing only the label
before the “CSECT”, which should be viewed as the name of the program.
The first line LAB1 CSECT is a declaration of a Control Section, named “LAB1”.
By definition, a control section is “a block of coding that can be relocated (independent of other
coding) without altering the operating logic of the program”. Practically, a control section is just
one block of assembly code that can be assembled and executed independently.

Opening the Input and Output


As indicated, the next section of code opens the input and output and prints a header line to the
output. Unlike the book’s example, this does not skip to a new page.
* SET UP THE INPUT AND OUTPUT AND PRINT HEADERS
*
OPEN (PRINTER,(OUTPUT)) OPEN THE STANDARD OUTPUT
OPEN (FILEIN,(INPUT)) OPEN THE STANDARD INPUT
PUT PRINTER,PRHEAD PRINT HEADER
GET FILEIN,RECORDIN GET THE FIRST RECORD, IF THERE
*
This example uses the macros associated with the IBM OS operating system. Note that the input
and output can be opened in any order, provided that each is opened before its first use.
Note that the open of the input and the output can be combined into a single statement.
OPEN (FILEIN,(INPUT), PRINTER,(OUTPUT))
Your instructor prefers to use separate statements, one for each I/O file.
This should be viewed as a personal preference only.

When the input FILEIN is defined, the declaration includes a specification of the line of code to
be executed when an End–of–File exception is raised. We shall say more on this later. At
present, the program prints a header and attempts to get a line of input.

Page 21 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The Print Loop


Here is the “main body” of the assembly code.
GET FILEIN,RECORDIN GET THE FIRST RECORD
* IF IT IS THERE
* READ AND PRINT LOOP
*
A10LOOP MVC DATAPR,RECORDIN MOVE INPUT RECORD
PUT PRINTER,PRINT PRINT THE RECORD
GET FILEIN,RECORDIN GET THE NEXT RECORD
B A10LOOP GO BACK AND PROCESS
*
Note that the code at label A10LOOP is executed the first time only if the top line
of code has actually returned a record (“card image” or 80 characters of text).
On execution of this code at label A10LOOP, we are guaranteed that there is a record in the data
storage area associated with the identifier RECORDIN.
These eighty characters of text (trailing blanks are included) are copied into the data storage area
associated with the identifier DATAPR, and then sent to the output.
This code then tries to get another line (card image) of input. If there is more input, the code
executes an unconditional branch to the statement A10LOOP, thus continuing the loop.
Note that the B A10LOOP statement is an example of the notorious GO TO statement, which is
avoided in higher level language programming. With this early assembler, it is not possible to
avoid such statements. The more modern assembler, HLASM, allows one to do without it.

The Print Loop (Java Style)


The best way to view this print loop is to add a construct that is used in both Java and C/C++.
GET FILEIN,RECORDIN GET THE FIRST RECORD
*
A10LOOP MVC DATAPR,RECORDIN MOVE INPUT RECORD
PUT PRINTER,PRINT PRINT THE RECORD
GET FILEIN,RECORDIN GET THE NEXT RECORD
If End_of_File Then Break
B A10LOOP GO BACK AND PROCESS
*
The loop is never entered if the first GET statement does not return a record.
The loop is exited when the contained GET statement encounters an End of File.
Otherwise, the processing continues.

Page 22 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Closing the Input and Output


When there is no more input to process, the code calls a section to close the I/O
and terminate the processing.
A90END CLOSE FILEIN
CLOSE PRINTER
Note the statement with label A90END. This will be seen to be the statement associated with the
end of file on the input.
Traditionally, a program will have some “close up” processing to do at this time, such as printing
totals and summaries. Here the code just closes the Input and Output.
This is the end of the custom code. The rest of the code is “boilerplate”.

The Standard Closing Code


Here is the standard “postfix code”. It must be the last section of code executed in any program
to be run on our mainframe, which is running the IBM OS operating system.

A90END CLOSE (FILEIN) CLOSE THE FILES...


CLOSE (PRINTER)
L R13,SAVEAREA+4 POINT AT OLD SAVE AREA
LM R14,R12,12(R13) RESTORE THE REGISTERS
LA R15,0 RETURN CODE = 0
BR R14 RETURN TO OPERATING SYSTEM
**************************************************************
When your program terminates, it must execute a return to the operating system. This is the
return code required by the operating system.

Defining the Output


The output file is defined using a standard DCB (Data Control Block)
PRINTER DCB DSORG=PS, X
MACRF=(PM), X
DEVD=DA, X
DDNAME=PRINTER, X
RECFM=FM, X
LRECL=133
DDNAME identifies the file’s symbolic name, which is further elaborated later in the “job”.
DSORG indicates that the data set is “physical sequential”, organized as
a sequence of output records and not indexed in any way.
DEVD defines a particular I/O unit. This data set is Direct Access.
RECFM specifies the operation to move data from the work area.
LRECL specifies the length of a logical record, set to 133 for a standard line printer. Each line
printer will print 132 characters. The first character in the 133 is a printer control character.
Note that this statement covers six lines of text; the first 5 ending with a termination character.

Page 23 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Defining the Input


The input file is defined using a standard DCB (Data Control Block).
FILEIN DCB DSORG=PS, X
MACRF=(GM) X
DEVD=DA, X
DDNAME=FILEIN, X
EODAD=A90END, X
RECFM=FB, X
LRECL=80,
DDNAME identifies the file’s symbolic name, which is further elaborated later in the “job”.
DSORG indicates that the data set is “physical sequential”, organized as
a sequence of input records and not indexed in any way.
DEVD defines a particular I/O unit. This data set is Direct Access.
RECFM specifies the operation to move data from the work area.
LRECL specifies that the length of the input record is 80 characters.
EODAD provides the end–of–file address for the input file that is read sequentially.
MACRF defines the type of input operation, here “get and move to work area”,
so that it can be accessed by the GET macro.
This and the previous macro invocations are examples of the use of call by keywords, rather than
call by position. In other words, the arguments of the form XX = YY could have been written in
any order, provided only that XX is a valid parameter name and YY is an acceptable value for the
parameter XX. This style of writing macro invocations is usually preferred; it is easier to read.

The Input Record Area


The data area labeled RECORDIN reserves eighty bytes of memory storage for use
in the input of an eighty–character card image. All of our programs will be written using the
(now archaic and artificial) assumption that all input is from lines of exactly 80 characters each.
This assumption fits terminal input very well.

*************************************************************
* INPUT RECORD AREA
*************************************************************
RECORDIN DS CL80
*************************************************************
Future programs will follow a convention that should be familiar to COBOL programmers.
We shall still assume 80–column input, but divide it into fields.
RECORDIN DS 0CL80 THE CARD HAS 80 COLUMNS
FIRSTNME DS CL8 THE FIRST 8 COLUMNS HOLD THE FIRST NAME
LASTNME DS CL10 THE NEXT 10 COLUMNS HOLD THE LAST NAME
ACCOUNT DS CL12 THE NEXT 12 COLUMNS HOLD THE ACCOUNT NUM
FILLER DS CL60 THE OTHER 60 COLUMNS ARE PROBABLY BLANK.

Page 24 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The Output Record Area


The output data area includes both constant outputs, such as the print headers used for the printer
output, and data areas into which variable character data is to be placed for printing.
Note that all non–character data (Packed Decimal, Two’s–Complement Integer, etc.) must be
converted to EBCDIC print format before being moved into the output area.
Each possible definition of the print output area conventionally holds 133 bytes, organized as a
print control character (also called “carriage control”) followed by 132 data characters.
***************************************************************
*
* HERE IS THE HEADER FOR SPRING 2009
*
PRHEAD DS 0CL133
PRC1 DC C' ' PRINT CONTROL:PRINT ON NEXT LINE
DC CL10' '
DC CL122'***COLUMBUS STATE UNIVERSITY SPRING 2009***'
*
* THIS DEFINES THE PRINT OUTPUT AREA.
* IT BEGINS WITH A BLANK PRINT CONTROL CHARACTER
* IT THEN HAS 80 CHARACTERS TO HOLD THE INPUT CARD IMAGE
* IT THEN HAS 42 CHARACTERS OF FILLER.
*
PRINT DS 0CL133 PRINT AREA
PRC2 DC C' ' PRINT CONTROL CHARACTER
DC CL10' '
DATAPR DC CL80' '
DC CL42' '
***************************************************************
A blank in the first column will cause the normal spacing in the output text. The program will
function by moving the card image to the data area DATAPR, and PRINT is then printed. What
will be printed is 10 leading spaces, followed by the line of input text.
As an aside, we should mention that the print area should probably be cleared out after each
line is printed. What we need is something like the following constant definition.
*************************************************************
* A BLANK LINE TO CLEAR THE PRINTER DATA AREA
*************************************************************
RECORDIN DS CL80
BLANK133 DC CL133’ ’
*************************************************************
The appropriate print code would then be the following.
PUT PRINTER,PRINT PRINT THE RECORD
MVC PRINT,BLANK133 CLEAR THE OUTPUT AREA

Page 25 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The Register Save Area


The program must have local storage sufficient to hold the registers that the Operating System
will save when the program is called. The size of the area is exactly 18 full–words.

****************************************************************
*
* REGISTER SAVE AREA
*
****************************************************************
SAVEAREA DS 18F
****************************************************************

The Literal Pool


The literal pool provides for a style of programming, in which the argument for the instruction is
contained within the instruction. We shall study this at some length later. When this style is
used, the assembler will create data constants and place them in a designated area of memory.
The LTORG macro denotes the address to be used for the start of the literal pool.
****************************************************************
*
* LITERAL POOL - THIS PROGRAM DOES NOT USE LITERALS.
*
****************************************************************
* LTORG *

The END
This and the following line denote the end of the assembler input. Note the name of the CSECT
in the END statement. This tells the assembler where to find the first executable statement.
END LAB1
/*

More Job Control Cards


The next two lines are directives to the operating system to define the real I/O devices. The first
line indicates where to put the print output, presumably on the print queue. The second line
specifies that the input is to be taken from the “card images” or lines that immediately follow.
//G.PRINTER DD SYSOUT=*
//G.FILEIN DD *

The Input Data.


The next set of cards form the input data, followed by lines indicating End of Job.
LINE 1 SPRING 2009
LINE 2 SPRING 2009
LINE 3 SPRING 2009
LINE 4 SPRING 2009
/*
//

Page 26 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Submitting and Executing the Program


The program may be submitted and executed from within the editor. Log onto the computer, and
enter the edit program, following the instructions on pages 10 – 12 of this chapter. While it is
not necessary to run the program from the editor, it is probably the easiest way to do so.
The mechanics of running the “Dual Mode Editor” will be discussed in the section below.
To submit the job, enter the six–character command “SUBMIT” on the command line.
Do not type the quotes. If you have changed the program, it is probably a good thing to hit the
F3 to exit and save and then reenter the editor.
When I submitted my job, I saw the following announcement at the screen bottom:
IKJ56250I JOB CSU0003A(JOB02189) SUBMITTED
***
I hit Enter twice to return to the editor, and then F3 a number of times in order to return to the
ISPF Primary Option Menu. It is now time to see the results of the run.

Displaying the Results of the Program


Enter the two–character command “SD” (that is, no quotes), followed by the ENTER key, to
access the SDSF system. Then enter the command “O” followed by the ENTER key to view the
Output Queue. The first time you do this you must set the filter.
Use the TAB key to access the Filter command box at the top of the form. Hit ENTER, enter a 1
into the box, and then hit ENTER again. One should then see the following screen.

Use the TAB to move to the first value box and enter your User ID. For me, the line becomes
“OWNER EQ CSU0003” (without the quotes). Then hit ENTER to set the filter.

Page 27 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The screen below shows the Output Queue.

Select the job that you want to examine in a way similar to that in which you selected a file to
edit. Tab down to the job that you are interested in examining and select it. There are a number
of ways to select the job. The easiest way is to place a “?” (question mark) in the box (as shown
above), and then hitting the ENTER key.
This leads to a display titled “SDSF JOB DATA SET DISPLAY”. Tab down to the line that is
called PRINTER, enter an “S” in the box to select it and then hit the ENTER key. You should
then see the output of your program.
If you do not see an entry called PRINTER, then your program had an error. In that case, you
must hit F3 to return to the SDSF STATUS DISPLAY menu, select the job using the “S”
command, and then examine the entire output. Note that this option shows quite a lot, including
much that I cannot understand.
Find the text of your assembler program by hitting F8 a few times, and then look for error
messages. While these may be hard to read, they do indicate the lines with problems.

Page 28 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Purging Jobs from the Hold Queue


From the ISPF Primary Option Menu, enter the two–character command “SD” (that is, no
quotes) to access the SDSF system. As always, follow the command by hitting the Enter key.
You may now examine the results.
Enter the command “O”, followed by the Enter key. Tab down to the job that you are interested
in examining and select it in the same way you selected a file to edit.
Hit “P” and then the Enter key. If a selection box pops up, select option 3 and hit enter. This
will purge the entry from the output queue.
NOTE: The display does not automatically update. Hit enter again to refresh the display.
Deleting Files
From main menu, go to option 3 (Utilities), then option 1 (Libraries). You will see a screen
labeled Library Utility. Note the grouping in the middle of the screen, titled ISPF Library. It
specifies Project, Group, and Type. On my screen, the values are what I want.

Hit enter. You will see a list of your files. Tab to the file, place a D in the line, hit enter and
then confirm. Here I have chosen to delete the file LAB01.

Leaving the System.


Hit F3 repeatedly to get back to the main menu from either the Editor or the SDSF.
Enter the one–character command “X” to exit. You may be prompted by a menu
“Specify Disposition of Log Data Set”. I always choose option 3
“Keep Data Set – Same”.
Then you will see a blank screen, similar to the one that you saw after typing “L TSO” at the
start of the session. Enter the string “LOGOFF”, assuming that you want to log off.
Disconnect from the mainframe by selecting the File menu and then Disconnect.
Close the Windows application that serves as the terminal emulator.

Page 29 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

Creating and Editing a Program


We now discuss the process of entering a program into the editor. One way, discussed below, is
to use the Insert mode and enter all of the text manually. The option that we shall elect involves
fall less manual work. There are two procedures discussed next.
1. How to get a copy of the first program.
2. How to use that copy to create editable copies for your future programs.
Getting a Copy of the First Program
The text of the first program is stored in a public library. In order to get the copy, you must start
from the ISPF PRIMARY OPTIONS MENU. Select Option 3 for the Utilities Menu and then
select Option 3 again, to get to the Copy/Move menu. The option is “C” for COPY.
Enter the “C” in the options line, but do not hit the ENTER key. Use the TAB key to move to
the box labeled “Name” in the section labeled “From Other Partitioned or Sequential Data Set”.
Enter ‘CSU.PUBLIC.DATA’
along with the single quotes. Hit the ENTER key after you do this.

Page 30 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

After this, you will be presented with a similar screen for the “To Data Set”

This is what I want; it lists my project, group, and type correctly. I just hit ENTER.
This brings me to the file COPY menu.

Here I have used the F8 key to move to the display containing the file I wanted and the TAB key
to move to the actual file. It is LAB01. In the Prompt box, I enter a name to use if I do not want
to call it “LAB01” and then hit enter.

Page 31 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

After this, the file should be in your area and available for editing. Again, go back to the ISPF
PRIMARY MENU, and select Option 2 for editing. You will see the Edit Entry Panel.

You may enter your file name in the Member Box or just hit enter to get.

To edit LAB01A, I just TAB to the box on the left of the name and hit ENTER.

Page 32 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

You should not add any text directly to LAB01. It is the “boilerplate” for all the labs that follow.
You should assemble and run it to show that it works. It is a basis for future labs.

Generating New Files from LAB01


As an example, suppose I want to generate a file called LAB02, which will be based on the
existing file LAB01. It will use all of the standard “boilerplate” code from LAB01.
Go to the Edit Entry Panel, and select a new file name.
ISPF Library
Project CSU0003__
Group ASM______
Type SRC_____
Member LAB02_____
Hit ENTER to get the editor with a new blank file.

In the command line enter COPY followed by the name of the file you want to copy. My file
was named “LAB01A’, so I enter “COPY LAB01A”, without the quotes. I then hit ENTER.
At this point, it is important to change call occurrences of the CSECT name to whatever you
want to use. The computer will not care if you name everything “LAB01”, but I shall.
IMPORTANT AND URGENT
I am showing you an example of a fully functional program with my User ID.
You MUST change the User ID in the first line to your own, or you will run in my account.
If I find any of your programs in my Project, I shall delete them without reading them.

Page 33 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

The Dual–Mode Editor


This editor is a classic “dual mode” editor, with an Insert mode and a Command mode.
The Insert Mode is used to enter lines of text into your program.
When you start the editor, it is in the Command mode. Here is my display when I select LAB1
and start the editor. There are several things to note before we start the edit.
1. Note the CSU0003A. This is my USER ID with an arbitrary letter appended.
You MUST use your own User ID.
2. The two lines beginning with “—MSG>” can be ignored.

In command mode, one repeatedly uses the TAB key to move up and down lines. In the way I
have the editor set up; a number of TABs will get me to the “000100” used as a line number.
The next TAB gets me, the next TAB gets me to the command line itself (the part beginning with
“//CSU0003A”. The next TAB will move me to the line number “000200”.
Note that shift–TAB (holding the Shift Key while striking the TAB) moves the cursor
backwards.
As an exercise, try to use the TAB key to shift to the line below that at the bottom of the screen.
In this mode the tab moves to the top of the screen. Use the function keys to change screens.

Page 34 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

In more modern terminology we have the following identifications for the function keys
at the top of the modern keyboard.
F3 Exit the application, while saving the changes.
F7 Page up
F8 Page down.

Changing the Scroll Mode


There are two scroll modes “PAGE” and “CSR” (cursor). I prefer the cursor mode. To change
from PAGE to CSR, tab over to the box following “Scroll ===>” and replace “PAGE” with the
four–character string “CSR ”, including the trailing space to overwrite the final letter.
In cursor (CSR) mode, the F7 and F8 keys display the following behavior:
F7 moves the line selected by the TAB to the bottom of the screen
F8 moves the line selected by the TAB to the top of the screen.

Inserting Text
To insert one or more lines of text, use the TAB or Shift–TAB to move the cursor to the line
number of the line after which you want to insert text. Type “I” and then hit the enter key. I
edited the image below, changing the color of the “I” to emphasize it.

You should now be in Insert Mode. Enter each line of text followed by a CR as needed.

Page 35 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

To exit Insert Mode, enter a blank line by just hitting the CR with no text on the line.
This should return you to Command Mode.
The only way to insert blanks is to use the space bar. Do not use the “” arrow key, as that will
just move the cursor without inserting anything. The line will appear to have spaces inserted, but
in reality it will not. This can be verified by saving the file, closing the editor, and reopening it.

Deleting a Line
To delete a line, use the TAB or Shift–TAB to move the cursor to the line number preceding the
line to delete, hit the “D” key, and then hit the enter key. The line should be deleted. Once
again, I have edited the image and changed the color of the “D” to highlight it.

Rare Editor Commands


In certain instances of the assembly process, it is important to place text in the correct column.
In that case, one might want a guide to the columns. This is not like the old days of punch cards
when one could examine the card and read the column number.
To view the columns, type COLS on the line that one wants to inspect and hit Enter.
Don’t forget to delete the COLS line when done.

This figure shows that the “X” continuation character has been correctly placed in column 72.

Page 36 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Structure of a Program

HEX ON, HEX OFF These two commands enter HEX mode in the editor and exit it.
These two commands are typed on the command line of the editor. In the HEX mode, the
editor will show the hexadecimal value of every character in the line, in two rows below.
To view the hexadecimal equivalents (EBCDIC code) for the text characters, enter the
command “HEX ON” in the command line, as shown below.

The output from the HEX ON will be verbose. In its typical use, this mode is used to search for
undesired non–printable characters. In the three lines below, we see that the only non–printable
character is the space, which has EBCDIC code 0x40.

Running with Output to Disk


To output to file SP2008.LAB1OUT in your user area, replace the GO.PRINTER line with
//GO PRINTER DD DSN=KCNNNNN.SP2008.LAB10UT,SPACE=(TRK,(1,1),RLSE),
// DISP=(NEW,CATLG,DELETE)
Neither the name “SP2008” nor the name “LAB1OUT” can exceed eight characters in length.

Viewing the Output Disk File


From the main menu, enter the four character string “=3.4” and hit ENTER twice.
Find the output file by using the F7 and F8 keys as well as the TAB key.
There are two ways to examine this file.
S Place S by the file name and hit ENTER. This will show the file attributes.
E Place E by the file name and hit ENTER twice. The text of the file should display.

Page 37 Chapter 2 Revised on February 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Chapter 3 – The Heritage of the IBM System/360


The IBM System/360 was announced on April 7, 1964. It is considered to be either an early
third–generation computer or a hybrid of the second generation and third generation. The
goals of this chapter include the following:
1. To understand the events that lead to the development of the System/360 family
of computers and the context into which this family must fit.
2. To understand the motivation for IBM’s creation of a family of computers, with
identical architecture, spanning a wide range of performance capabilities.
3. To define the standard five generations of computing technology, relating each
generation to the underlying circuitry and giving examples of each.
We begin this chapter by addressing the last goal. In order to place the System/360 family
correctly, we must study the technologies leading up to it.
The standard division lists five generations, numbered 1 through 5. Here is one such list,
taken from the book Computer Structures: Principles and Examples [R04].
1. The first generation (1945 – 1958) is that of vacuum tubes.
2. The second generation (1958 – 1966) is that of discrete transistors.
3. The third generation (1966 – 1972) is that of small-scale and medium-scale
integrated circuits.
4. The fourth generation (1972 – 1978) is that of large-scale integrated circuits..
5. The fifth generation (1978 onward) is that of very-large-scale integrated circuits.
This classification scheme is well established and quite useful, but does have its drawbacks.
Two that are worth mention are the following.
1. The term “fifth generation” has yet to be defined in a uniformly accepted way.
For many, we continue to live with fourth–generation computers and are even now
looking forward to the next great development that will usher in the fifth generation.
2. This scheme ignores all work before the introduction of the ENIAC in 1945. To quote
an early architecture book, much is ignored by this ‘first generation’ label.
“It is a measure of American industry’s generally ahistorical view of things that the
title of ‘first generation’ has been allowed to be attached to a collection of machines
that were some generations removed from the beginning by any reasonable
accounting. Mechanical and electromechanical computers existed prior to electronic
ones. Furthermore, they were the functional equivalents of electronic computers and
were realized to be such.” [R04, page 35]
The IBM System/360, which is the topic of this textbook, was produced by the International
Business Machines Corporation. By 1952, when IBM introduced its first electronic computer,
it had accumulated over 50 years experience with tabulating machines and electromechanical
computers. In your author’s opinion, this early experience greatly affected the development
of all IBM computers; for this reason it is studied.

Page 38 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

A Revised Listing of the Generations


We now present the classification scheme to be used in this textbook. In order to fit the
standard numbering scheme, we follow established practice and begin with “Generation 0”.
Generation 0 (1642 through 1945)
This is the era of purely mechanical calculators and electromechanical calculators. At this
time the term “computer” was a job title, indicating a human who used a calculating machine.
Generation 1 (1945 through 1958)
This is the era of computers (now defined as machines) based on vacuum tube technology.
All subsequent generations of computers are based on the transistor, which was developed by
Bell Labs in late 1947 and early 1948. It can be claimed that each of the generations that
follow represent only a different way to package transistors. Of course, one can also claim
that a modern F–18 is just another 1910’s era fighter. Much has changed.
Generation 2 (1958 through 1966)
Bell Labs licensed the technology for transistor fabrication in late 1951 and presented the
Transistor Technology Symposium in April 1952. The TX–0, an early experimental
computer based on transistors, it became operational in 1956. IBM’s first transistor–based
computer, the 7070, was announced in September 1958.
Generation 3 (1966 through 1972)
This is the era of SSI (Small Scale Integrated) and MSI (Medium Scale Integrated) circuits.
Each of these technologies allowed the placement of a number of transistors on a single chip
fabricated from silicon, with the wiring between the transistors being achieved by lines of
aluminum actually etched on the chip. There were no large wires on the chip.
SSI corresponded to 100 or fewer electronic components on a chip.
MSI corresponded to between 100 and 3,000 electronic components on a chip.
Generation 4 (1972 – 1978)
This is the era of LSI (Large Scale Integrated) chips, with up to 100,000 components on the
chip. Many of the early Intel processors fall into this generation.
Generation 4 B (1978 and later)
This is the era of VLSI (Very Large Scale Integrated) chips, having more than 100,000
components on the chip. The Intel Pentium series belongs here.
This textbook will not refer to any computing technology as “fifth generation”; the term is just
too vague and has too many disparate meanings. As a matter of fact, it will not make many
references to the fourth generation, as the IBM System/360 family is definitely third
generation or earlier.
A Study of Switches
All stored program computers are based on the binary number system, implemented using
some sort of switch that turns voltages on and off. The history of the computer generations is
precisely a history of the devices used as voltage switches. It begins with electromechanical
relays and continues through vacuum tubes and transistors. Each of the latter two has many
uses in analog electronics; the digital use is a rather specialized modification of the operating
regime that causes each to operate as a switch.

Page 39 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Electronic Relays
Electronic relays are devices that use (often small) voltages to switch other voltages. One
example of such a power relay is the horn relay found in all modern automobiles. A small
voltage line connects the horn switch on the steering wheel to the relay under the hood. That
relay switches a high–current line that activates the horn.

The following figure illustrates the operation of an electromechanical relay. The iron core
acts as an electromagnet. When the core is activated, the pivoted iron armature is drawn
towards the magnet, raising the lower contact in the relay until it touches the upper contact,
thereby completing a circuit. Thus electromechanical relays are switches.

Figure: An Electromechanical Relay

In general, an electromechanical relay is a device that uses an electronic voltage to activate an


electromagnet that will pull an electronic switch from one position to another, thus affecting
the flow of another voltage; thereby turning the device “off” or “on”. Relays display the
essential characteristic of a binary device – two distinct states. Below we see pictures of two
recent-vintage electromechanical relays.

Figure: Two Relays (Source http://en.wikipedia.org/wiki/Relay)

Page 40 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The primary difference between the two types of relays shown above is the amount of power
being switched. The relays for use in general electronics tend to be smaller and encased in
plastic housing for protection from the environment, as they do not have to dissipate a large
amount of heat. Again, think of an electromechanical relay as an electronically operated
switch, with two possible states: ON or OFF.

Power relays, such as the horn relay, function mainly to isolate the high currents associated
with the switched apparatus from the device or human initiating the action. One common use
is seen in electronic process control, in which the relays isolate the electronics that compute
the action from the voltage swings found in the large machines being controlled.

In use for computers, relays are just switches that can be operated electronically. To
understand their operation, the student should consider the following simple circuits.

Figure: Relay Is Closed: Light Is Illuminated

Figure: Relay Is Opened: Light Is Dark.


We may use these simple components to generate the basic Boolean functions, and from these
the more complex functions used in a digital computer. The following relay circuit
implements the Boolean AND function, which is TRUE if and only if both inputs are TRUE.
Here, the light is illuminated if and only if both relays are closed.

Figure: One Closed and One Open


Computers based on electromagnetic relays played an important part in the early development
of computers, but became quickly obsolete when designs using vacuum tubes (considered as
purely electronic relays) were introduced in the late 1940’s. These electronic tubes also had
two states, but could be switched more quickly as there were no mechanical components to be
moved.

Page 41 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Vacuum Tubes
The next step in digital logic was the use of a vacuum tube as a digital switch. As this device
was purely electrical, it was much faster than the electromechanical relays that had been used
in digital computing machines prior to about 1945. The figure below shows four vacuum
tubes from this author’s personal collection. Note that the big one is about 5 inches tall.

Figure: Four Vacuum Tubes Mounted in Styrofoam


The big vacuum tube to the right is a diode, which is an element with 3 major components: a
filament, a cathode and a grid. This would have been used as a rectifier as a part of a circuit
to convert AC (Alternating Current) into DC (Direct Current).
The cathode is the element that is the source of electrons in the tube. When it is heated either
directly (as a filament in a light bulb) or indirectly by a separate filament, it will emit
electrons, which either are reabsorbed by the cathode or travel to the anode. When the anode
is held at a voltage more positive than the cathode, the electrons tend to flow from cathode to
anode (and the current is said to flow from anode to cathode – a definition made in the early
19th century before electrons were understood). The anode is the silver “cap” at the top.
One of the smaller tubes is a triode, which has four major components: the above three as well
as a controlling grid placed between the cathode and the anode. This serves as a current
switch, basically an all–electronic relay. The grid serves as an adjustable barrier to the
electrons. When the grid is more positive, more electrons tend to leave the cathode and fly to
the anode. When the grid is more negative, the electrons tend to stay at the cathode. By this
mechanism, a small voltage change applied to the grid can cause a larger voltage change in
the output of the triode; hence it is an amplifier. As a digital device, the grid in the tube either
allows a large current flow or almost completely blocks it – “on” or “off”.
Here we should add a note related to analog audio devices, such as high–fidelity and stereo
radios and record players. Note the reference to a small voltage change in the input of a tube
causing a larger voltage change in the output; this is amplification, and tubes were once used
in amplifiers for audio devices. The use of tubes as digital devices is just a special case,
making use of the extremes of the range and avoiding the “linear range” of amplification.

Page 42 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

We close this section with a picture taken from the IBM 701 computer, a computer from 1952
developed by the IBM Poughkeepsie Laboratory. This was the first IBM computer that relied
on vacuum tubes as the basic technology.

Figure: A Block of Tubes from the IBM 701


Source: [R23]

The reader will note that, though there is no scale on this drawing, the tubes appear rather
small, and are probably about one inch in height. The components that resemble small
cylinders are resistors; those that resemble pancakes are capacitors.
Another feature of the figure above that is worth note is the fact that the vacuum tubes are
grouped together in a single component. The use of such components probably simplified
maintenance of the computer; just pull the component, replace it with a functioning copy, and
repair the original at leisure.
There are two major difficulties with computers fabricated from vacuum tubes, each of which
arises from the difficulty of working with so many vacuum tubes. Suppose a computer that
uses 20,000 vacuum tubes; this being only slightly larger than the actual ENIAC.
A vacuum tube requires a hot filament in order to function. In this it is similar to a modern
light bulb that emits light due to a heated filament. Suppose that each of our tubes requires
only five watts of electricity to keep its filament hot and the tube functioning. The total
power requirement for the computer is then 100,000 watts or 100 kilowatts.
We also realize the problem of reliability of such a large collection of tubes. Suppose that
each of the tubes has a probability of 99.999% of operating one hour. This can be written as a
decimal number as 0.99999 = 1.0 – 10-5. The probability that all 20,000 tubes will be
operational for more than an hour can be computed as (1.0 – 10-5)20000, which can be
approximated as 1.0 – 2000010-5 = 1.0 – 0.2 = 0.8. There is an 80% chance the computer
will function for one hour and 64% chance for two hours of operation. This is not good.

Page 43 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Discrete Transistors
Discrete transistors can be thought of as small triodes with the additional advantages of
consuming less power and being less likely to wear out. The reader should note the transistor
second from the left in the figure below. It at about one centimeter in size would have been
an early replacement for the vacuum tube of about 5 inches (13 centimeters) in size shown on
the previous page. One reason for the reduced power consumption is that there is no need for
a heated filament to cause the emission of electrons.

When first introduced, the transistor immediately presented an enormous (or should we say
small – think size issues) advantage over the vacuum tube. However, there were cost
disadvantages, as is noted in this history of the TX–0, a test computer designed around 1951.
“Like the MTC [Memory Test Computer], the TX–0 was designed as a test device.
It was designed to test transistor circuitry, to verify that a 256 X 256 (64–K word)
core memory could be built … and to serve as a prelude to the construction of a
large-scale 36–bit computer. The transistor circuitry being tested featured the new
Philco SBT100 surface barrier transistor, costing $80, which greatly simplified
transistor circuit design.” [R01, page 127]
That is a cost of $288,000 just for the transistors. Imagine the cost of a 256 MB memory,
since each byte of memory would require at least eight, and probably 16, transistors.
Packaging Discrete Transistors
In order to avoid the overwhelming complexity associated with individual wires, components
at this time were placed onto discrete cards, with a backplane to connect the cards.

Figure: A Rack of Circuit Cards from the Z–23 Computer (1961)

Page 44 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The interesting features of these cards are illustrated in the figure below, which is a module
called a “Flip Chip”. It was used on a PDP–8 marketed by the Digital Equipment Corporation
in the late 1960’s. Note the edge connectors that would plug into a wired backplane. Also
note the “silver” traces on the back of the card. These traces served as wires to connect the
components that were on the chip. An identical technology, on a very much smaller scale, has
been employed by each of the generations of integrated chips.

Figure: Front and Back of an R205b Flip-Chip (Dual Flip-Flop) [R42]

In the above figure, one can easily spot many of the discrete components. The orange
pancake-like items are capacitors, the cylindrical devices with colorful stripes are resistors
with the color coding indicating their rating and tolerances, the black “hats” in the column
second from the left are transistors, and the other items must be something useful. The size of
this module is indicated by the orange plastic handle, which is fitted to a human hand.
It was soon realized that assembly of a large computer from discrete components would be
almost impossible, as fabricating such a large assembly of components without a single faulty
connection or component would be extremely costly. This problem became known as the
“tyranny of numbers”. Two teams independently sought solutions to this problem. One team
at Texas Instruments was headed by Jack Kilby, an engineer with a background in ceramic-
based silk screen circuit boards and transistor-based hearing aids. The other team was headed
by research engineer Robert Noyce, a co-founder of Fairchild Semiconductor Corporation. In
1959, each team applied for a patent on essentially the same circuitry, Texas Instruments
receiving U.S. patent #3,138,743 for miniaturized electronic circuits, and Fairchild receiving
U.S. patent #2,981,877 for a silicon-based integrated circuit. After several years of legal
battles, the two companies agreed to cross-license their technologies, and the rest is history
(and a lot of profit).
Page 45 Chapter 3 Last Revised on November 5, 2008
Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Integrated Circuits
Integrated circuits are nothing more or less than a very efficient packaging of transistors and
other circuit elements. The term “discrete transistors” implied that the circuit was built from
transistors connected by wires, all of which could be easily seen and handled by humans.
As noted above, the integrated circuit was independently developed by two teams of
engineers in 1959. The advantages of such circuits quickly became obvious and applications
in the computer world soon appeared. We list a few of the more obvious advantages.
1. The integrate circuit solved the “tyranny of numbers” problem mentioned above.
More of the wiring connections were placed on the chip of the integrated circuit,
which could be automatically fabricated. This automation of production lead to
decreased costs and increased reliability.
2. The length of wires interconnecting the integrated circuits was decreased, allowing
for much faster circuitry. In the Cray–1, a supercomputer build with generation 2
technologies, the longest wire was 4 feet. Electricity travels on wires at about two
feet per nanosecond; the Cray–1 had to allow for 4 nanosecond round trip times.
This limited the maximum clock frequency to about 200 MHz.
The first integrated circuits were classified as SSI (Small-Scale Integration) in that they
contained only a few tens of transistors. The first commercial uses of these circuits were in
the Minuteman missile project and the Apollo program. It is generally conceded that the
Apollo program motivated the technology, while the Minuteman program forced it into mass
production, reducing the costs from about $1,000 per circuit in 1960 to $25 per circuit in
1963. Were such components fabricated today, they would cost less than a penny.
Large Scale and Very Large Scale Integrated Circuits (from 1972 onward)
As we shall se, the use of SSI (Small Scale Integration) in the early System/360 models
yielded an impressive jump in circuit density. We now have a choice: stop here because we
have developed the technology to explain the System/360 and System /370, or trace the later
evolution of the S/360 family through the S/370 (announced in 1970), the 370/XA (1983), the
ESA/370 (1988), the ESA/390 (1990), and the z/Series (announced in 2000).
The major factor driving the development of smaller and more powerful computers was and
continues to be the method for manufacture of the chips. This is called “photolithography”,
which uses light to transmit a pattern from a photomask to a light–sensitive chemical called
“photoresist” that is covering the surface of the chip. This process, along with chemical
treatment of the chip surface, results in the deposition of the desired circuits on the chip.
In a very real sense, the development of what might be called “Post Generation 3” circuitry
really depended on the development of the automated machinery used to produce those
circuits. These machines, together with the special buildings required to house them, are
called “Fabs”, or chip fabrication centers. These fabs are also extraordinarily expensive,
costing on the order of $ 1 billion dollars. All of this development is in the future for the
computers in which we are interested for this course.
We shall limit our thoughts to the first three generations of computer technologies.

Page 46 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

It seems that pictures are the best way to illustrate the evolution of the first three generations
of computer components. Below, we see a picture of an IBM engineer (they all wore coats
and ties at that time) with three generations of components. He is seen sitting in front of the
control panel for one of the System/360 models.
The first generation unit (vacuum tubes) is a pluggable module from the IBM 650. Recall that
the idea of pluggable modules dates to the ENIAC; the design facilitates maintenance.
The second generation unit (discrete transistors) is a module from the IBM 7090.
The third generation unit is the ACPX module used on the IBM 360/91 (1964). Each chip was
created by stacking layers of silicon on a ceramic substrate; it accommodated over twenty
transistors. The chips could be packaged together onto a circuit board. Note the pencil
pointing to one of the chips on the board. It is likely that this chip has functionality equivalent
to the transistorized board on the right or the vacuum tube pluggable unit on the left.

Figure: IBM Engineer with Three Generations of Components

Page 47 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Magnetic Core Memory


The reader will note that most discussions of the “computer generations” focus on the
technology used to implement the CPU (Central Processing Unit). Here, we shall depart from
this “CPU–centric view” and discuss early developments in memory technology. We shall
begin this section by presenting a number of the early technologies and end it with what your
author considers to be the last significant contribution of the first generation – the magnetic
core memory. This technology was introduced with the Whirlwind computer, designed and
built at MIT in the late 1940’s and early 1950’s.
The reader will recall that the ENIAC did not have any memory, but just used twenty
10–digit accumulators. For this reason, it was not a stored program computer, as it had no
memory in which to store the program. A moderately sized memory (say 4 kilobytes) would
probably have required 32,768 dual–triode vacuum tubes to implement. This was not feasible
at the time; it would have cost too much and been far too unreliable.
The EDSAC
Maurice Wilkes of Cambridge University in England was the first to develop a working
memory for a digital computer. By early 1947 he had designed and built a working memory
based on mercury delay lines (see the picture below). Each of the 16 tubes could store 32
words of 17 bits each (16 bits and a sign) for a total of 512 words or 1024 bytes.
It should be noted that Dr. Wilkes was primarily interested in creating a machine that he could
use to test software development. As a result, the EDSAC was a very conservative design.

Figure: Maurice Wilkes and a Set of 16 mercury delay lines for the EDSAC [R 38]

Page 48 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The Manchester Mark I


The next step in the development of memory technology was taken at the University of
Manchester in England, with the development of the Mark I computer and its predecessor, the
“Manchester Baby”. These computers were designed by researchers at the University; the
manufacture of the Mark I was contracted out to the Ferranti corporation.
Each of the Manchester Baby and the Manchester/Ferranti Mark I computers used a new
technology, called the “Williams–Kilburn tube”, as an electrostatic main memory. This
device was developed in 1946 by Frederic C. Williams and Tom Kilburn [R43]. The first
design could store either 32 or 64 words (the sources disagree on this) of 32 bits each.
The tube was a cathode ray tube in which the binary bits stored would appear as dots on the
screen. The next figure shows the tube, along with a typical display; this has 32 words of 40
bits each. The bright dots store a 1 and the dimmer dots store a 0.

Figure: An Early Williams–Kilburn tube and its display


Note the extra line of 20 bits at the top.
While the Williams–Kilburn tube sufficed for the storage of the prototype Manchester Baby,
it was not large enough for the contemplated Mark I. The design team decided to build a
hierarchical memory, using double–density Williams–Kilburn tubes (each storing two pages
of thirty–two 40–bit words), backed by a magnetic drum holding 16,384 40–bit words.
The magnetic drum can be seen to hold 512 pages of thirty–two 40–bit words each. The data
were transferred between the drum memory and the electrostatic display tube one page at a
time, with the revolution speed of the drum set to match the display refresh speed. The team
used the experience gained with this early block transfer to design and implement the first
virtual memory system on the Atlas computer in the late 1950’s.

Figure: The IBM 650 Drum Memory

Page 49 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The MIT Whirlwind and Magnetic Core Memory


The MIT Whirlwind was designed as a bit-parallel machine with a 5 MHz clock. The
following quote describes the effect of changing the design from one using current technology
memory modules with the new core memory modules.
“Initially it [the Whirlwind] was designed using a rank of sixteen Williams tubes,
making for a 16-bit parallel memory. However, the Williams tubes were a limitation
in terms of operating speed, reliability, and cost.”
“To solve this problem, Jay W. Forrester and others developed magnetic core
memories. When the electrostatic memory was replaced with a primitive core
memory, the operating speed of the Whirlwind doubled, and the maintenance time
on the machine fell from four hours per day to two hours per week, and the mean
time between memory failures rose from two hours to two weeks! Core memory
technology was crucial in enabling Whirlwind to perform 50,000 operations per
second in 1952 and to operate reliably for relative long periods of time” [R11]

The reader should consider the previous paragraph carefully and ask how useful computers
would be if we had to spend about half of each working day in maintaining them.
Basically core memory consists of magnetic cores, which are small doughnut-shaped pieces
of magnetic material. These can be magnetized in one of two directions: clockwise or
counter-clockwise; one orientation corresponding to a logic 0 and the other to a logic 1.
Associated with the cores are current carrying conductors used to read and write the memory.
The individual cores were strung by hand on the fine insulated wires to form an array. It is a
fact that no practical automated core-stringing machine was ever developed; thus core
memory was always a bit more costly due to the labor intensity of its construction.
To more clearly illustrate core memory, we include picture from the Sun Microsystems web
site. Note the cores of magnetic material with the copper wires interlaced.

Figure: Close–Up of a Magnetic Core Memory [R40]

At this point, we leave our discussion of the development of memory technology. While it is
true that memory technology advanced considerably in the years following 1960, we have
taken our narrative far enough to get us to the IBM System/360 family.

Page 50 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Interlude: Data Storage Technologies In the 1950’s

We have yet to address methods commonly used by early computers for storage of off–line
data; that is data that were not actually in the main memory of the computer. One may validly
ask “Why worry about obsolete data storage technologies; we all use disks.” The answer is
quite simple, it is the format of these data cards that drove the design of the interactive IBM
systems we use even today. We enter code and data as lines on a terminal using a text editor;
we should pretend that we are punching cards.
There were two methods in common use at the time. One of the methods employed punched
paper tape, with the tape being punched in rows of either five or seven holes. Here are two
views of typical punched paper tapes from approximately the 1950’s.

Figure: Punched Paper Tape – Fanfold and Rolled

While punched paper tape was commonly used for storage on the smaller computers, such as
the IBM 1620, punched cards were the preferred medium for the larger computers of the early
1950’s. Even after the wide availability of magnetic disks and magnetic tape drives, the paper
card remained a preferred medium for many data applications until quite late. The most
common card was the 80–column punch cards, such as seen in the figure below.

Figure: 80–Column Punch Card (Approximately 75% of Full Size)

These cards would store at most eighty characters, so that the maximum data capacity was
exactly eighty bytes. The card has twelve rows with the bottom ten being numbered 0
through 9. There are two additional rows (unmarked in this card) on the top.

Page 51 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The data (80 characters maximum) were encoded on the card by punching holds in each
column. Most printing punches would print the text corresponding to each column on the top
of the card above that column. Anything printed or written on the card (such as the college
logo above) would have been ignored; only the holes in the cards were significant.
There are two common coding schemes used by IBM for their punched cards; these are
usually identified by the name of the card punch producing them. The IBM 026 card punch,
introduced in July 1949, produced cards encoded with BCDIC (Binary Coded Decimal
Interchange Code), an extension of Baudot code. The figure below shows the twelve rows (or
punching positions) with the codes for each digit, upper case letter, or special character.

There are many features of the IBM 026 that persist into the later IBM 029 and other card
punches (if there are any left at the moment). For this reason, we discuss the features here.
Note that the digits 0 through 9 are each encoded with a single punch and that punched hole is
placed in the row with the appropriate value. Only the digits have a single punch code; all the
other characters have at least two holes punched in their column.
As noted above, there are twelve rows or “punching positions” on this card. The bottom ten
rows, labeled rows 0 through 9, are easily seen on the card. The two rows, or punching
positions, above these ten rows are called rows 12 and 11; with row 12 nearer the top.
Printing card punches would place a line of text at the top of the card, just above punching
position 12; as noted above, the card readers would ignore that text.
The easiest way to describe the codes for the upper case letters is by the punching positions
used to encode them. Here are a few codes, read from the image above.
A 12 – 1 J 11 – 1
B 12 – 2 K 11 – 2 S 0–2
I 12 – 9 R 11 – 9 Z 0–9
BCDIC is a 46–character code that includes the 26 uppercase Roman letters, the 10 digits 0-9,
and 11 special characters: Ampersand (&), Period (.), Lozenge (◊), Minus sign (-), Dollar
sign ($), Asterisk (*), Slash (/), Comma (,), Percent sign (%), Number sign (#), and
Commercial At Sign (@).

Page 52 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The reader will note that this code omits all lower case letters and a great number of useful
characters. The obvious conclusion is that it predates any high–level programming language,
as it lacks coding for the plus sign,”+”, as well as parentheses.
The figure below shows an IBM 026 printing card punch from about the year 1949. The term
“printing punch” means that it will write the character above each column encoding that
character. Blank cards are fed from the card hopper, one at a time into the punching station.
In common usage, after being punched, the cards would move automatically through the
reading station (which did nothing) and into the card stacker.
Some of the features shown below, such as the program unit and column indicator, allowed
automation of various data entry functions, such as moving to tabbed columns. Programmers
rarely used these features, though they could be useful.

Figure: An IBM 026 Printing Card Punch, Circa 1949

The IBM 026 remained in common use until 1964, when the IBM System/360 was
introduced. This machine required a new code for its much enlarged character set, EBCDIC
(Extended Binary Coded Decimal Interchange Code), and hence a new card punch. EBCDIC
was designed as a compatible extension of the older BCDIC; cards produced by the older
IBM 026 punches could be interpreted as EBCDIC.

Page 53 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The IBM 029 Printing Card Punch was used to encode characters in EDCDIC on a standard
eighty–column punch card. The format of the card was retained while the code changed.
Here is an illustration of the punch code produced by the IBM 029; the card displays each of
the 64 characters available for this format. Note again that lower case letters are missing.

Note that the encodings for the ten digits and twenty–six upper case letters are retained from
the BCDIC codes of the IBM 026. This example shows the print representation of each
character above the column that encodes it. The IBM 026 also had the ability to print in this
area; it is just that the example we noted did not have that printing. Comparison of the picture
of the IBM 029 (below) and the IBM 026 (above) show only cosmetic change.

Figure: The IBM 029 Printing Card Punch (1964)

Page 54 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

It is worth noting that IBM seriously considered adoption of ASCII as its method for internal
storage of character data for the System/360. The American Standard Code for Information
Interchange was approved in 1963 and supported by IBM. However the ASCII code set was
not compatible with the BCDIC used on a very large installed base of support equipment,
such as the IBM 026. Transition to an incompatible character set would have required any
adopter of the new IBM System/360 to also purchase or lease an entirely new set of peripheral
equipment; this would have been a deterrence to early adoption.
It is a little known fact that the CPU (Central Processing Unit) on an early System/360
implementation included an “ASCII bit” in the PSW (Program Status Word). When set, the
S/360 would process characters encoded in ASCII; when cleared the EBCDIC code was used.
It is an interesting study to remark on the design of the EBCDIC scheme and how it was
related to the punch card codes used by the IBM 029 card punch. One should be very careful
and precise at this moment; the punch card codes were not EBCDIC.
The structure of the EBCDIC, used for internal character storage on the System/360 and later
computers, was determined by the requirement for easy translation from punch card codes.
The table below gives a comparison of the two coding schemes.
Character Punch Code EBCDIC Remember that the punch card codes
‘0’ 0 F0 represent the card rows punched. Each
‘1’ 1 F1 digit was represented by a punch in a
‘9’ 9 F9 single row; the row number was identical
‘A’ 12 – 1 C1 to the value of the digit being encoded.
‘B’ 12 – 2 C2 The EBCDIC codes are eight–bit binary
‘I’ 12 – 9 C9 numbers, almost always represented as
‘J’ 11 – 1 D1 two hexadecimal digits. Some IBM
‘K’ 11 – 2 D2 documentation refers to these digits as:
‘R’ 11 – 9 D9 The first digit is the zone potion,
‘S’ 0–2 E2 The second digit is the numeric.
‘T’ 0–8 E3
‘Z’ 0–9 E9

A comparison of the older card punch codes with the EBCDIC shows that its design was
intended to facilitate the translation. For digits, the numeric punch row became the numeric
part of the EBCDIC representation, and the zone part was set to hexadecimal F. For the
alphabetical characters, the second numeric row would become the numeric part and the first
punch row would determine the zone portion of the EBCDIC.
This matching with punched card codes explains the “gaps” found in the EBCDIC set.
Remember that these codes are given as hexadecimal numbers, so that the code immediately
following C9 would be CA (as hexadecimal A is decimal 10). But the code for ‘J’ is not
hexadecimal CA, but hexadecimal D1. Also, note that the EBCDIC representation for the
letter ‘S’ is not E1 but E2. This is a direct consequence of the design of the punch cards.

Page 55 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Line Printers: The Output Machines


There were two common methods for output of data from early IBM machines: the card
punch and the line printer. The card punch was just a computer controlled version of the
manual card punches, though with distinctively different configurations. All card punches,
manual or automatic, produced cards to be read by the computer’s card reader.
The standard printer of the time was a line printer, meaning that it printed output one line at a
time. These devices were just extremely fast and sophisticated typewriters, using an inked
ribbon to provide the ink for the printed characters. The ink–jet printer and the laser printer
each is a device of a later decade. One should note that only the “high end” laser printers, of
the type found in print shops today, are capable of matching the output of a line printer.
The standard printer formats called for output of data into fixed width columns; the maximum
width being either 80 columns per line or 132 columns per line. The first picture shows an
IBM 716 printer from about 1952. The second show an IBM 1403 printer introduced in 1959.
Each appears to be using 132–column width paper.

Figure: The IBM 716 Printer

Figure: The IBM 1403 Printer

Page 56 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

IBM: Generation 0
We now examine the state of affairs for IBM at the end of the 1940’s. This for IBM was the
end of “Generation 0”; that is the time during which electromechanical calculators were
phased out and vacuum tube computers were introduced.
The author of this textbook wishes to state that the source for almost all of the material in this
section is the IBM history web site (http://www-03.ibm.com/ibm/history/exhibits/).
IBM was incorporated in the state of New York on June 16, 1911 as the C –T–R Company
(Computing–Tabulating–Recording Company), and renamed as the International Business
Machines Corporation on February 14, 1924. Many of its more important products have roots
in the companies of the late 19th century that were merged to form the C–T–R Company.
One can argue that the lineage of most of IBM’s product line in the late 1940’s can be traced
back to the work of Dr. Herman Hollerith, who first demonstrated his tabulating systems in
1889. This system used punched cards to record the data, and a electromechanical calculator
to extract information from the cards.

Herman Hollerith's Tabulating System, shown in the figure


to the left, was used in the U.S. Census of 1890. It reduced
a nearly 10–year long process to two and a half years and
saved $5 million. The Hollerith, Punch Card Tabulating
Machine used an electric current to sense holes in punched
cards and keep a running total of data. Capitalizing on his
success, Hollerith formed the Tabulating Machine
Company in 1896. This was one of the companies that was
merged into the C–T–R Company in 1911.
We mention the Hollerith Tabulator of 1890 for two reasons. The first is that it represented a
significant innovation for the time, one that the descendant company, IBM, could be proud of.
The second reason is that it illustrates the design of many of the IBM products of the first half
of the twentieth century: accept cards as input, process the data on the cards, and produce
information for use by the managers of the businesses using those calculators.
As noted indirectly above, IBM’s predecessor company, the C–T–R Company, was formed in
1911 by the merger of three companies: Hollerith’s Tabulating Machine Company, the
Computing Scale Company of America, and the International Time Recording Company. In
1914, Thomas J. Watson, Sr. was persuaded to join the company as general manager. Mr.
Watson was a formidable figure, playing a large role at
IBM until the early 1950’s.
We now jump ahead to 1933, at which time IBM
introduced the Type 285 Numeric Printing Tabulator. The
goal of this device, as well as its predecessors in the
1920’s, was to reduce the error caused by the hand copying
of numbers from the mechanical counters used in previous
tabulators. By this time, the data cards had been expanded
to 80 columns. These cards were fed from a tray at the
right of the machine, and passed over the tabulating units.

Page 57 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Early tabulating machines were essentially single–function calculators. Starting in 1906,


tabulators were made more flexible by addition of a wiring panel to let users control their
actions to some degree, thus allowing the same machine to be sold into different markets
(government, railroad, etc) and used for different purposes. But this also meant that if one
machine were to be used for different jobs, it would have to be rewired between each job,
often a lengthy process that kept the machine offline for extended periods. In 1928, IBM
began to manufacture machines with removable wiring panels, or "plugboards", so programs
could be prewired and swapped in and out instantly to change jobs.
One example of this is the IBM 402 Accounting Machine, introduced in 1948. It was one of
the “400 series”, each of which could read standard 80 column cards, accumulate sums,
subtotals, and balances, and print reports, all under the control of instructions wired into its
control panel. In the figure below, the Type 402 (on the left) is shown attached to a Type 519
Summary Punch (on the right), allowing totals accumulated by the accounting machine to be
punched to cards for later use.

Figure: IBM 402 Attached to an IBM 519

The 402 series, like the 405 before it, used a typebar print mechanism, in which each column
(up to 88, depending on model and options) has its own type bar. Long type bars (on the left
in the photo below) contain letters and digits; short ones contain only digits (each kind of type
bar also includes one or two symbols such as ampersand or asterisk). Type bars shoot up and
down independently, positioning the desired character for impact printing.

Figure: IBM 402 Tabular Typebar

Page 58 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

Here are two views of a plugboard, as used on the IBM Type 402 Accounting Machine.

Figure: The Plugboard Receptacle

Figure: A Wired Plugboard

Page 59 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

As suggested by the above discussions, most financial computing in the 1930’s and 1940’s
revolved around the use of punched cards to store data. The figure below shows a “card
shop” from 1950. These 11 men and women are operating an IBM electric accounting
machine installation. Seen here (at left) is an IBM 523 gang summary punch, which could
process 100 cards a minute and (in the middle) an IBM 82 high-speed sorter, which could
process 650 punched cards a minute. This may be seen as an essential part of an IBM shop in
the late 1940’s: process financial data and produce results for managers.

Figure: People with Card Equipment


We close this section of our discussion with a picture of the largest electromechanical
calculator ever built, the Harvard Mark I, also known as the IBM Automatic Sequence
Controlled Calculator. It was 51 feet long, 8 feet high, and weighed five tons. It was the first
fully automatic computer to be completed; once it started it needed no human intervention. It
is best seen as an ancestor of the ENIAC and early IBM digital computers.

Figure: The Harvard Mark–I (1944)

Page 60 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The Evolution of the IBM–360


We now return to a discussion of “Big Iron”, a name given informally to the larger IBM
mainframe computers of the time. Much of this discussion is taken from an article in the IBM
Journal of Research and Development [R46], supplemented by articles from [R1]. We trace
the evolution of IBM computers from the first scientific computer ( the IBM 701, announced
in May 1952) through the early stages of the S/360 (announced in March 1964).
We begin this discussion by considering the situation as of January 1, 1954. At the time, IBM
has three models announced and shipping. Two of these were the IBM 701 for scientific
computations and the IBM 702 for financial calculations (announced in September 1953),.
Each of the designs used Williams–Kilburn tubes for primary memory, and each was
implemented using vacuum tubes in the CPU. Neither computer supported both floating–
point (scientific) and packed decimal (financial) arithmetic, as the cost to support both would
have been excessive. As a result, there were two “lines”: scientific and commercial.
The third model was the IBM 650. It was designed as “a much smaller computer that would
be suitable for volume production. From the outset, the emphasis was on reliability and
moderate cost”. The IBM 650 was a serial, decimal, stored–program computer with fixed
length words each holding ten decimal digits and a sign. Later models could be equipped
with the IBM 305 RAMAC (the disk memory discussed and pictured above). When equipped
with terminals, the IBM 650 started the shift towards transaction–oriented processing.
The figure below can be considered as giving the “family tree” of the IBM System/360.
Note that there are four “lines”: the IBM 650 line, the IBM 701 line, IBM 702 line, and the
IBM 7030 (Stretch). The System/360 (so named because it handled “all 360 degrees of
computing”) was an attempt to consolidate these lines and reduce the multiplicity of distinct
systems, each with its distinct maintenance problems and costs.

Figure: The IBM System/360 “Family Tree”

Page 61 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

As mentioned above, in the 1950’s IBM supported two product lines: scientific computers
(beginning with the IBM 701) and commercial computes (beginning with the IBM 702).
Each of these lines was redesigned and considerably improved in 1954.
Generation 1 of the Scientific Line
In the IBM 704 (announced in May 1954), the Williams–Kilburn tube memory was replaced
by magnetic–core memory with up to 32768 36–bit words. This eliminated the most difficult
maintenance problem and allowed users to run larger programs. At the time, theorists had
estimated that a large computer would require only a few thousand words of memory. Even
at this time, the practical programmers wanted more than could be provided.
The IBM 704 also introduced hardware support for floating–point arithmetic, which was
omitted from the IBM 701 in an attempt to keep the design “simple and spartan” [R46]. It
also added three index registers, which could be used for loops and address modification. As
many scientific programs make heavy use of loops over arrays, this was a welcome addition.
The IBM 709 (announced in January 1957) was basically an upgraded IBM 704. The most
important new function was then called a “data–synchronizer unit”; it is now called an “I/O
Channel”. Each channel was an individual I/O processor that could address and access main
memory to store and retrieve data independently of the CPU. The CPU would interact with
the I/O Channels by use of special instructions that later were called channel commands.
It was this flexibility, as much as any other factor, that lead to the development of a simple
supervisory program called the IOCS (I/O Control System). This attempt to provide support
for the task of managing I/O channels and synchronizing their operation with the CPU
represents an early step in the evolution of the operating system.
Generation 1 of the Commercial Line
The IBM 702 series differed from the IBM 701 series in many ways, the most important of
which was the provision for variable–length digital arithmetic. In contrast to the 36–bit word
orientation of the IBM 701 series, this series was oriented towards alphanumeric arithmetic,
with each character being encoded as 6 bits with an appended parity check bit. Numbers
could have any length from 1 to 511 digits, and were terminated by a “data mark”.
The IBM 705 (announced in October 1954) represented a considerable upgrade to the 702.
The most significant change was the provision of magnetic–core memory, removing a
considerable nuisance for the maintenance engineers. The size of the memory was at first
doubled and then doubled again to 40,000 characters. Later models could be provided with
one or more “data–synchronizer units”, allowing buffered I/O independent of the CPU.
Generation 2 of the Product Lines
As noted above, the big change associated with the transition to the second generation is the
use of transistors in the place of vacuum tubes. Compared to an equivalent vacuum tube, a
transistor offers a number of significant advantages: decreased power usage, decreased cost,
smaller size, and significantly increased reliability. These advantages facilitated the design of
increasingly complex circuits of the type required by the then new second generation.
The IBM 7070 (announced in September 1958 as an upgrade to the IBM 650) was the first
transistor based computer marketed by IBM. This introduced the use of interrupt–driven I/O
as well as the SPOOL (Simultaneous Peripheral Operation On Line) process for managing
shared Input/Output devices.

Page 62 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The IBM 7090 (announced in December 1958) was a transistorized version of the IBM 709
with some additional facilities. The IBM 7080 (announced in January 1960) likewise was a
transistorized version of the IBM 705. Each model was less costly to maintain and more
reliable than its tube–based predecessor, to the extent that it was judged to be a “qualitatively
different kind of machine” [R46].
The IBM 7090 (and later IBM 7094) were modified by researchers at M.I.T. in order to make
possible the CTSS (Compatible Time–Sharing System), the first major time–sharing system.
Memory was augmented by a second 32768–word memory bank. User programs occupied
one bank while the operating system resided in the other. User memory was divided into 128
memory–protected blocks of 256 words, and access was limited by boundary registers.
The IBM 7094 was announced on January 15, 1962. The CTSS effort was begun in 1961,
with a version being demonstrated on an IBM 709 in November 1961. CTSS was formally
presented in a paper at the Joint Computer Conference in May, 1962. Its design affected later
operating systems, including MULTICS and its derivatives, UNIX and MS–DOS.
As a last comment here, the true IBM geek will note the omission of any discussion of the
IBM 1401 line. These machines were often used in conjunction with the 7090 or 7094,
handling the printing, punching, and card reading chores for the latter. It is just not possible
to cover every significant machine.
The IBM 7030 (Stretch)
In late 1954, IBM decided to undertake a very ambitious research project, with the goal of
benefiting from the experience gained in the previous three project lines. In 1955, it was
decided that the new machine should be at least 100 times as fast as either the IBM 704 or the
IBM 705; hence the informal name “Stretch” as it “stretched the technology”.
In order to achieve these goals, the design of the IBM 7030 required a considerable number of
innovations in technology and computer organization; a few are listed here.
1. A new type of germanium transistor, called “drift transistor” was developed. These
faster transistors allowed the circuitry in the Stretch to run ten times faster.
2. A new type of core memory was developed; it was 6 times faster than the older core.
3. Memory was organized into multiple 128K–byte units accessed by low–order
interleaving, so that successive words were stored in different banks. As a result,
new data could be retrieved at a rate of one word every 200 nanoseconds, even
though the memory cycle time was 2.1 microseconds (2,100 nanoseconds).
4. Instruction lookahead (now called “pipelining”) was introduced. At any point in
time, six instructions were in some phase of execution in the CPU.
5. New disk drives, with multiple read/write arms, were developed. The capacity and
transfer rate of these devices lead to the abandonment of magnetic drums.
6. A pair of boundary registers were added so as to provide the storage protection
required in a multiprogramming environment.

Page 63 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

It is generally admitted that the Stretch did not meet its design goal of a 100 times increase in
the performance of the earlier IBM models. Here is the judgment by IBM from 1981 [R46].
“For a typical 704 program, Stretch fell short of is performance target of one hundred times
the 704, perhaps by a factor of two. In applications requiring the larger storage capacity and
word length of Stretch, the performance factor probably exceeded one hundred, but
comparisons are difficult because such problems were not often tackled on the 704.” [R46]
It seems that production of the IBM 7030 (Stretch) was limited to nine machines, one for Los
Alamos National Labs, one (called “Harvest”) for the National Security Agency, and 7 more.
Smaller Integrated Circuits (Generation 3 – from 1966 to 1972)
In one sense, the evolution of computer components can be said to have stopped in 1958 with
the introduction of the transistor; all future developments merely represent the refinement of
the transistor design. This statement stretches the truth so far that it hardly even makes this
author’s point, which is that packaging technology is extremely important.
What we see in the generations following the introduction of the transistor is an aggressive
miniaturization of both the transistors and the traces (wires) used to connect the circuit
elements. This allowed the creation of circuit modules with component densities that could
hardly have been imagined a decade earlier. Such circuit modules used less power and were
much faster than those of the second generation; in electronics smaller is faster. They also
lent themselves to automated manufacture, thus increasing component reliability.
The Control Unit and Emulation
In order to better explain one of the distinctive features of the IBM System/360 family, it is
necessary to take a detour and discuss the function of the control unit in a stored program
computer. Basically, the control unit tells the computer what to do.
All modern stored program computers execute programs that are a sequence of binary
machine–language instructions. This sequence of instructions corresponds either to an
assembly language program or a program in a higher–level language, such as C++ or Java.
The basic operation of a stored program computer is called “fetch–execute”, with many
variants on this name. Each instruction to be executed is fetched from memory and deposited
in the Instruction Register, which is a part of the control unit. The control unit interprets this
machine instruction and issues the signals that cause the computer to execute it.

Figure: Schematic of the Control Unit

Page 64 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

There are two ways in which a control unit may be organized. The most efficient way is to
build the unit entirely from basic logic gates. For a moderately–sized instruction set with the
standard features expected, this leads to a very complex circuit that is difficult to test.
In 1951, Maurice V. Wilkes (designer of the EDSAC, see above) suggested an organization
for the control unit that was simpler, more flexible, and much easier to test and validate. This
was called a “microprogrammed control unit”. The basic idea was that control signals can
be generated by reading words from a micromemory and placing each in an output buffer.
In this design, the control unit interprets the machine language instruction and branches to a
section of the micromemory that contains the microcode needed to emit the proper control
signals. The entire contents of the micromemory, representing the sequence of control signals
for all of the machine language instructions is called the microprogram. All we need to
know is that the microprogram is stored in a ROM (Read Only Memory) unit.
While microprogramming was sporadically investigated in the 1950’s, it was not until about
1960 that memory technology had matured sufficiently to allow commercial fabrication of a
micromemory with sufficient speed and reliability to be competitive. When IBM selected the
technology for the control units of some of the System/360 line, its primary goal was the
creation of a unit that was easily tested. Then they got a bonus; they realized that adding the
appropriate blocks of microcode could make a S/360 computer execute machine code for
either the IBM 1401 or IBM 7094 with no modification. This greatly facilitated upgrading
from those machines and significantly contributed to the popularity of the S/360 family.
The IBM System/360
As noted above, the IBM chose to replace a number of very successful, but incompatible,
computer lines with a single computer family, the System/360. The goal, according to an
IBM history web site [R48] was to “provide an expandable system that would serve every
data processing need”. The initial announcement on April 7, 1964 included Models 30, 40,
50, 60, 62, and 70 [R49]. The first three began shipping in mid–1965, and the last three were
replaced by the Model 65 (shipped in November 1965) and Model 75 (January 1966).
The introduction of the System/360 is also the introduction of the term “architecture”
as applied to computers. The following quotes are taken from one of the first papers
describing the System/360 architecture [R46].
“The term architecture is used here to describe the attributes of a system as seen by
the programmer,, i.e., the conceptual structure and functional behavior, as distinct
from the organization of the data flow and controls, the logical design,
and the physical implementation.”
“In the last few years, many computer architects have realized, usually implicitly,
that logical structure (as seen by the programmer) and physical structure (as seen
by the engineer) are quite different. Thus, each may see registers, counters, etc.,
that to the other are not at all real entities. This was not so in the computers of the
1950’s. The explicit recognition of the duality of the structure opened the way
for the compatibility within System/360.”

Page 65 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

To see the difference, consider the sixteen general–purpose registers (R0 – R15) in the
System/360 architecture. All models implement these registers and use them in exactly the
same way; this is a requirement of the architecture. As a matter of implementation, a few
of the lower end S/360 family actually used dedicated core memory for the registers, while
the higher end models used solid state circuitry on the CPU board.
The difference between organization and implementation is seen by considering the two
computer pairs: the 709 and 7090, and the 705 and 7080. The IBM 7090 had the same
organization (hence the same architecture) as the IBM 709; the implementation was different.
The IBM 709 used vacuum tubes; the IBM 7090 replaced these with transistors.
The requirement for the System/360 design is that all models in that series would be
“strictly program compatible, upward and downward, at the program bit level”. [R46]
“Here it [strictly program compatible] means that a valid program, whose logic will
not depend implicitly upon time of execution and which runs upon configuration A,
will also run on configuration B if the latter includes as least the required storage, at
least the required I/O devices, and at least the required optional features.”
“Compatibility would ensure that the user’s expanding needs be easily accommodated
by any model. Compatibility would also ensure maximum utility of programming
support prepared by the manufacturer, maximum sharing of programs generated by the
user, ability to use small systems to back up large ones, and exceptional freedom in
configuring systems for particular applications.”
Additional design goals for the System/360 include the following.
1. The System/360 was intended to replace two mutually incompatible product
lines in existence at the time.
a) The scientific series (701, 704, 7090, and 7094) that supported floating
point arithmetic, but not decimal arithmetic.
b) The commercial series (702, 705, and 7080) that supported decimal
arithmetic, but not floating point arithmetic.
2. The System/360 should have a “compatibility mode” that would allow it
to run unmodified machine code from the IBM 1401 – at the time a very
popular business machine with a large installed base.
This was possible due to the use of a microprogrammed control unit. If you
want to run native S/360 code, access that part of the microprogram. If you
want to run IBM 1401 code, just switch to the microprogram for that machine.
3. The Input/Output Control Program should be designed to allow execution by
the CPU itself (on smaller machines) or execution by separate I/O Channels
on the larger machines.
4. The system must allow for autonomous operation with very little intervention by
a human operator. Ideally this would be limited to mounting and dismounting
magnetic tapes, feeding punch cards into the reader, and delivering output.
5. The system must support some sort of extended precision floating point
arithmetic, with more precision than the 36–bit system then in use.

Page 66 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Heritage of the S/360

The design goal for the series is illustrated by the following scenario. It should be noted that
this goal of upward compatibility has persisted to the present day, in which there seem to be at
least fifty models of the z/10, all compatible with each other and differing only in
performance (number of transactions per second) and cost. Here is the scenario.
1. You have a small company. It needs only a small computer to handle its
computing needs. You lease an IBM System 360/30. You use it in emulation
mode to run your IBM 1401 programs unmodified.
2. Your company grows. You need a bigger computer. Lease a 360/50.
3. You hit the “big time”. Turn in the 360/50 and lease a 360/91.
You never need to rewrite or recompile your existing programs.
You can still run your IBM 1401 programs without modification.

The System/360 Evolves into the System 370


In June 1970, IBM announced the S/370 as a successor to the System/360. This introduced
another design feature of the evolving series; each model would be backwardly compatible
with the previous models in that it would run code assembled on the earlier models. Thus, the
S/370 would run S/360 code unaltered, and later models would run both S/360 and S/370
code unaltered. It is this fact that we rely on when we are running S/370 assembler code on a
modern z/10 Enterprise Server, which was introduced in 2008.
The S/370 underwent a major upgrade to the S/370–XA (S/370 extended architecture) in early
1983. At this time the address space was extended from 24 bits to 31 bits, allowing the CPU
to address two gigabytes of memory (1 GB = 230 bytes) rather than just 16 MB (224 bytes).
While the IBM mainframe architecture has evolved further since the introduction of the
S/370, it is here that we stop our overview. The primary reason for this is that this course has
been designed to teach System/370 Assembler Language, focusing on the basics of that
language and avoiding the extensions of the language introduced with the later models.

The Mainframe Evolves: The z10 Enterprise Servers.


While this textbook and the course based on it will focus on the state of mainframe assembler
writing as of about 1979 (the date at which the textbook we previously used was published), it
is important to know where IBM has elected to take this architecture. The present state of the
design is reflected in the z/Series, first introduced in the year 2000.
The major design goal of the z/Series is reflected in its name, in which the “z” stands for
“Zero Down–Time”. The mainframe has evolved into a highly reliable transaction server for
very high transaction volumes. A typical transaction takes place every time a credit card is
used for a purchase. The credit card reader at the merchant location contacts a central server,
which might be a z10, and the transaction is recorded for billing later. In such a high–volume
business, loss of the central server for as much as an hour could result in the loss of millions
of dollars in profits to a company. It is this model for which IBM designed the mainframe.
We end this chapter by noting that some at IBM prefer to discontinue the use of the term
“mainframe”, considering it to be obsolete. In this thought, the term would refer to an early
S/360 or S/370, and not to the modern z/Series systems which are both more powerful and
much smaller in physical size. The preferred term would be “Enterprise Server”. The only
difficulty is that the customers prefer the term “mainframe”, so it stays.

Page 67 Chapter 3 Last Revised on November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 4 – Data Representation
The focus of this chapter is the representation of data in a digital computer. We begin with a
review of several number systems (decimal, binary, octal, and hexadecimal) and a discussion
of methods for conversion between the systems. The two most important methods are
conversion from decimal to binary and binary to decimal. The conversions between binary
and each of octal and hexadecimal are quite simple. Other conversions, such as hexadecimal
to decimal, are often best done via binary.

After discussion of conversion between bases, we discuss the methods used to store integers
in a digital computer: one’s complement and two’s complement arithmetic. This includes a
characterization of the range of integers that can be stored given the number of bits allocated
to store an integer. The most common integer storage formats are 16, 32, and 64 bits.

The next topic for this chapter is the storage of real (floating point) numbers. This discussion
will mention the standard put forward by the Institute of Electrical and Electronic Engineers,
the IEEE Standard 754 for floating point numbers, but will focus on the base–16 format used
by IBM Mainframes. The chapter closes with a discussion of codes for storing characters,
focusing on the EBCDIC system used on IBM mainframes.

Number Systems
There are four number systems of possible interest to the computer programmer: decimal,
binary, octal, and hexadecimal. Each system is characterized by its base or radix, always
given in decimal, and the set of permissible digits. Note that the hexadecimal numbering
system calls for more than ten digits, so we use the first six letters of the alphabet.

Decimal Base = 10
Digit Set = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Binary Base = 2
Digit Set = {0, 1}
Octal Base = 8 = 23
Digit Set = {0, 1, 2, 3, 4, 5, 6, 7}
Hexadecimal Base = 16 = 24
Digit Set = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}

The fact that the bases for octal and hexadecimal are powers of the basis for binary facilitates
the conversion between these bases. The conversion can be done one digit at a time,
remembering that each octal digit corresponds to three binary bits and each hexadecimal digit
corresponds to four binary bits. Conversion between octal and hexadecimal is best done by
first converting to binary.

Except for an occasional reference, we shall not use the octal system much, but focus on the
decimal, binary, and hexadecimal numbering systems.

Page 68 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The figure below shows the numeric equivalents in binary and decimal of the first 16
hexadecimal numbers. The following is taken from that figure.

Binary Decimal Hexadecimal


(base 2) (base 10) (base 16)
0000 00 0
0001 01 1 Note that conversions from hexadecimal
0010 02 2 to binary can be done one digit at a time,
0011 03 3 thus DE = 11011110, as D = 1101 and
0100 04 4 E = 1110. We shall normally denote
0101 05 5 this as DE = 1101 1110 with a space
0110 06 6 to facilitate reading the binary.
0111 07 7
1000 08 8 Conversion from binary to hexadecimal
1001 09 9 is also quite easy. Group the bits four at
1010 10 A a time and convert each set of four.
1011 11 B Thus 10111101, written 1011 1101 for
1100 12 C clarity is BD because 1011 = B and
1101 13 D 1101 = D.
1110 14 E
1111 15 F

Consider conversion of the binary number 111010 to hexadecimal. If we try to group the bits
four at a time we get either 11 1010 or 1110 10. The first option is correct as the grouping
must be done from the right. We then add leading zeroes to get groups of four binary bits,
thus obtaining 0011 1010, which is converted to 3A as 0011 = 3 and 1010 = A.

Unsigned Binary Integers


There are two common methods to store unsigned integers in a computer: binary numbers
(which we discuss now) and Packed Decimal (which we discuss later). From a theoretical
point of view, it is important to note that no computer really stores the set of integers in that it
can represent an arbitrary member of that infinite set. Computer storage formats allow only
for the representation of a large, but finite, subset of the integers.
It is easy to show that an N–bit binary integer can represent one of 2N possible integer values.
Here is the proof by induction.
1. A one–bit integer can store 2 values: 0 or 1. This is the base for induction.
2. Suppose an N–bit integer, unconventionally written as BNBN–1 … B3B2B1.
By the inductive hypothesis, this can represent one of 2N possible values.
3. We now consider an (N+1)–bit integer, written as BN+1BNBN–1 … B3B2B1.
By the inductive hypothesis, there are 2N values of the form 0BNBN–1 … B3B2B1,
and 2N values of the form 1BNBN–1 … B3B2B1.
4. The total number of (N+1)–bit values is 2N + 2N = 2N+1. The claim is proved.
By inspection of the above table, we see that there are 16 possible values for a four–bit
unsigned integer. These range from decimal 0 through decimal 15 and are easily represented
by a single hexadecimal digit. Each hexadecimal digit is shorthand for four binary bits.

Page 69 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

In the standard interpretation, always used in this course, an N–bit unsigned integer will
represent 2N integer values in the range 0 through 2N – 1, inclusive. Sample ranges include:
N= 4 0 through 24 – 1 0 through 15
N= 8 0 through 28 – 1 0 through 255
N= 12 0 through 212 – 1 0 through 4095
N= 16 0 through 216 – 1 0 through 65535
N= 20 0 through 220 – 1 0 through 1,048,575
N= 32 0 through 232 – 1 0 through 4,294,967,295
For most applications, the most important representations are 8 bit, 16 bit, and 32 bit. To this
mix, we add 12–bit unsigned integers as they are used in the base register and offset scheme
of addressing used by the IBM Mainframe computers. Recalling that a hexadecimal digit is
best seen as a convenient way to write four binary bits, we have the following.
8 bit numbers 2 hexadecimal digits 0 through 255,
12 bit numbers 3 hexadecimal digits 0 through 4095,
16 bit numbers 4 hexadecimal digits 0 through 65535, and
32 bit numbers 8 hexadecimal digits 0 through 4,294,967,295.

Conversions between Decimal and Binary


We now consider methods for conversion from decimal to binary and binary to decimal. We
consider not only whole numbers (integers), but numbers with decimal fractions. To convert
such a number, one must convert the integer and fractional parts separately.
We begin this discussion by describing how to convert unsigned decimal integers to unsigned
binary numbers. Remember the requirement that the decimal number fit within the range
supported by the representation to be used; the number 967 cannot be converted to 8–bit
binary as it lies outside the range 0 – 255. As 210 = 1024, this number requires 10 bits.
In this discussion, we shall use as many bits as are needed to represent the number. After we
do this, we shall then consider signed representations that allow the use of negative integers.
Both whole numbers (integers) and fractional parts of decimal numbers can be converted to
binary and represented in that notation. Obviously, the integer formats discussed above do
not support fractional parts; they are needed to support the floating point representations.
Consider the conversion of the number 23.375. The method used to convert the integer part
(23) is different from the method used to convert the fractional part (.375). We shall discuss
two distinct methods for conversion of each part and leave the student to choose his/her
favorite. After this discussion we note some puzzling facts about exact representation of
decimal fractions in binary; e.g. the fact that 0.20 in decimal cannot be exactly represented in
binary. As before we present two proofs and let the student choose his/her favorite.

The intuitive way to convert decimal 23 to binary is to note that 23 = 16 + 7 = 16 + 4 + 2 + 1.


Thus decimal 23 = 10111 binary. As an eight bit binary number this is 0001 0111. Note that
we needed 5 bits to represent the number; this reflects the fact that 24 < 23  25. We expand
this to an 8-bit representation by adding three leading zeroes.

Page 70 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The intuitive way to convert decimal 0.375 to binary is to note that 0.375 = 1/4 + 1/8 =
0/2 + 1/4 + 1/8, so decimal .375 = binary .011 and decimal 23.375 = binary 10111.011.

Most students prefer a more mechanical way to do the conversions. Here we present that
method and encourage the students to learn this method in preference to the previous.

Conversion of integers from decimal to binary is done by repeated integer division with
keeping of the integer quotient and noting the integer remainder. The remainder numbers are
then read top to bottom as least significant bit to most significant bit. Here is an example.

Quotient Remainder
23/2 = 11 1 Thus decimal 23 = binary 10111
11/2 = 5 1
5/2 = 2 1 Remember to read the binary number
2/2 = 1 0 from bottom to top.
1/2 = 0 1 This last step must be done to get the first 1.

Conversion of the fractional part is done by repeated multiplication with copying of the
whole number part of the product and subsequent multiplication of the fractional part. All
multiplications are by 2. Here is an example.

Number Product Binary


0.375 x 2 = 0.75 0
0.75 x 2 = 1.5 1
0.5 x 2 = 1.0 1
The process terminates when the product of the last multiplication is 1.0. At this point we
copy the last 1 generated and have the result; thus decimal 0.375 = 0.011 binary.

We now develop a “power of 2” notation that will be required when we study the IEEE
floating point standard. We have just shown that decimal 23.375 = 10111.011 binary. Recall
that in the scientific “power of 10” notation, when we move the decimal to the left one place
we have to multiply by 10. Thus, 1234 = 123.4  101 = 12.34  102 = 1.234  103.

We apply the same logic to the binary number. In the IEEE standard we need to form the
number as a normalized number, which is of the form 1.xxx  2p. In changing 10111 to
1.0111 we have moved the decimal point (O.K. – it should be called binary point) 4 places to
the left, so 10111.011 = 1.0111011  24. Recalling that 24 = 16 and 25 = 32, and noting that
16.0 < 23.375  32.0 we see that the result is as expected.

Conversion from binary to decimal is quite easy. One just remembers the decimal
representations of the powers of 2. We convert 10111.011 binary to decimal. Recalling the
positional notation used in all number systems:
10111.011 = 124 + 023 + 122 + 121 + 120 + 02-1 + 12-2 + 12-3
= 116 + 08 + 14 + 12 + 11 + 00.5 + 10.25 + 10.125
= 23.375

Page 71 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Conversions between Decimal and Hexadecimal


The conversion is best done by first converting to binary. We consider conversion of 23.375
from decimal to hexadecimal. We have noted that the value is 10111.011 in binary.

To convert this binary number to hexadecimal we must group the binary bits in groups of
four, adding leading and trailing zeroes as necessary. We introduce spaces in the numbers in
order to show what is being done.
10111.011 = 1 0111.011.
To the left of the decimal we group from the right and to the right of the decimal we group
from the left. Thus 1.011101 would be grouped as 1.0111 01.

At this point we must add extra zeroes to form four bit groups. So
10111.011 = 0001 0111.0110.
Conversion to hexadecimal is done four bits at a time. The answer is 17.6 hexadecimal.

Another (More Confusing Way) to Convert Decimal to Hexadecimal


Some readers may ask why we avoid the repeated division and multiplication methods in
conversion from decimal to hexadecimal. Just to show it can be done, here is an example.
Consider the number 7085.791748046875. As an example, we convert this to hexadecimal.
The first step is to use repeated division to produce the whole–number part.
7085 / 16 = 442 with remainder = 13 or hexadecimal D
442 / 16 = 27 with remainder = 10 or hexadecimal A
27 / 16 =1 with remainder = 11 or hexadecimal B
1 / 16 =0 with remainder = 1 or hexadecimal 1.
The whole number is read bottom to top as 1BAD.
Now we use repeated multiplication to obtain the fractional part.
0.791748046875  16 = 12.6679875 Remove the 12 or hexadecimal C
0.6679875  16 = 10.6875 Remove the 10 or hexadecimal A
0.6875  16 = 11.00 Remove the 11 or hexadecimal B
0.00  16 = 0.0
The fractional part is read top to bottom as CAB.
The hexadecimal value is 1BAD.CAB, which is a small joke on the author’s part.
Long division is of very little use in converting the whole number part. It does correctly
produce the first quotient and remainder. The intermediate numbers may be confusing.
442
16)7085
64
68
64
45
32
13

Page 72 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Non-terminating Fractions
We now make a detour to note a surprising fact about binary numbers – that some fractions
that terminate in decimal are non-terminating in binary. We first consider terminating and
non-terminating fractions in decimal. All of us know that 1/4 = 0.25, which is a terminating
fraction, but that 1/3 = 0.333333333333333333333333333333…, a non-terminating fraction.

We offer a demonstration of why 1/4 terminates in decimal notation and 1/3 does not, and
then we show two proofs that 1/3 cannot be a terminating fraction.

Consider the following sequence of multiplications


1/4  10 = 2½
½  10 = 5. Thus 1/4 = 25/100 = 0.25.

However, 1/3  10 = 10/3 = 3 + 1/3, so repeated multiplication by 10 continues to yield a


fraction of 1/3 in the product; hence, the decimal representation of 1/3 is non-terminating.

In decimal numbering, a fraction is terminating if and only if it can be represented in the


form J / 10K for some integers J and K. We have seen that 1/4 = 25/100 = 25/102, thus the
fraction 1/4 is a terminating fraction because we have shown the integers J = 25 and K = 2.
Note that this representation is never unique if it exists; 1/4 = 250/1000 (J = 250 and K = 3),
and 1/4 = 2500/10000 (J = 2500 and K = 4). By convention, we use the smallest values.

Here are two proofs that the fraction 1/3 cannot be represented as a terminating fraction in
decimal notation. The first proof relies on the fact that every positive power of 10 can be
written as 9M + 1 for some integer M. The second relies on the fact that 10 = 25, so that
10K = 2K5K. To motivate the first proof, note that 100 = 1 = 90 + 1, 10 = 91 + 1,
100 = 911 + 1, 1000 = 9111 + 1, etc. If 1/3 were a terminating decimal, we could solve the
following equations for integers J and M.
1 J J
 K , which becomes 3J = 9M + 1 or 3(J – 3M) = 1. But there is no
3 10 9  M 1
integer X such that 3X = 1 and the equation has no integer solutions.

The other proof also involves solving an equation. If 1/3 were a non-terminating fraction,
then we could solve the following equation for J and K.
1 J  J
, which becomes 3J = 2K5K. This has an integer solution J only if the
3 10 K
2 5
K K
right hand side of the equation can be factored by 3. But neither 2K nor 5K can be factored by
3, so the right hand side cannot be factored by 3 and hence the equation is not solvable.

Page 73 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Now consider the innocent looking decimal 0.20. We show that this does not have a
terminating form in binary. We first demonstrate this by trying to apply the multiplication
method to obtain the binary representation.

Number Product Binary


0.20  2 = 0.40 0
0.40  2 = 0.80 0
0.80  2 = 1.60 1
0.60  2 = 1.20 1
0.20  2 = 0.40 0
0.40  2 = 0.80 0
0.80  2 = 1.60 1 but we have seen this – see four lines above.

So decimal 0.20 in binary is 0.00110011001100110011 … ad infinitum.

The proof that no terminating representation exists depends on the fact that any terminating
J
fraction in binary can be represented in the form K for some integers J and K. Thus we
2
1 J
solve  K or 5J = 2K. This equation has a solution only if the right hand side is divisible
5 2
by 5. But 2 and 5 are relatively prime numbers, so 5 does not divide any power of 2 and the
equation has no integer solution. Hence 0.20 in decimal has no terminating form in binary.

Binary Addition
The next topic is storage of integers in a computer. We shall be concerned with storage of
both positive and negative integers. Two’s complement arithmetic is the most common
method of storing signed integers. Calculation of the two’s complement representation of an
integer requires binary addition. For that reason, we first discuss binary addition.

To motivate our discussion of binary addition, let us first look at decimal addition. Consider
the sum 15 + 17 = 32. First, note that 5 + 7 = 12. In order to speak of binary addition, we
must revert to a more basic way to describe 5 + 7; we say that the sum is 2 with a carry-out of
1. Consider the sum 1 + 1, which is known to be 2. However, the correct answer to our
simple problem is 32, not 22, because in computing the sum 1 + 1 we must consider the
carry-in digit, here a 1. With that in mind, we show two addition tables – for a half-adder
and a full-adder. The half-adder table is simpler as it does not involve a carry-in. The
following table considers the sum and carry from A + B.

Half-Adder A + B
A B Sum Carry
0 0 0 0 Note the last row where we claim that 1 + 1 yields a
0 1 1 0 sum of zero and a carry of 1. This is similar to the
1 0 1 0 statement in decimal arithmetic that 5 + 5 yields a
1 1 0 1 sum of 0 and carry of 1 when 5 + 5 = 10.

Page 74 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Remember that when the sum of two numbers equals or exceeds the value of the base of the
numbering system (here 2) that we decrease the sum by the value of the base and generate a
carry. Here the base of the number system is 2 (decimal), which is 1 + 1, and the sum is 0.

For us the half-adder is only a step in the understanding of a full-adder, which implements
binary addition when a carry-in is allowed. We now view the table for the sum A + B, with a
carry-in denoted by C. One can consider this A + B + C, if that helps.

Full-Adder: A + B with Carry


A B C Sum Carry
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
Immediately, we have the Boolean implementation of a Full Adder; how to make such a
circuit using only AND, OR, and NOT gates.

As an example, we shall consider a number of examples of addition of four-bit binary


numbers. The problem will first be stated in decimal, then converted to binary, and then
done. The last problem is introduced for the express purpose of pointing out an error.

We shall see in a minute that four-bit binary numbers can represent decimal numbers in the
range 0 to 15 inclusive. Here are the problems, first in decimal and then in binary.
1) 6 + 1 0110 + 0001
2) 11 + 1 1011 + 0001
3) 13 + 5 1101 + 0101

0110 1011 1101 In the first sum, we add 1 to an even number. This
0001 0001 0101 is quite easy to do. Just change the last 0 to a 1.
0111 1100 0010 Otherwise, we may need to watch the carry bits.

In the second sum, let us proceed from right to left. 1 + 1 = 0 with carry = 1. The second
column has 1 + 0 with carry-in of 1 = 0 with carry-out = 1. The third column has 0 + 0 with
a carry-in of 1 = 1 with carry-out = 0. The fourth column is 1 + 0 = 1.

Analysis of the third sum shows that it is correct bit–wise but seems to be indicating that
13 + 5 = 2. This is an example of “busted arithmetic”, more properly called overflow. A
give number of bits can represent integers only in a given range; here 13 + 5 is outside the
range 0 to 15 inclusive that is proper for four-bit numbers.

Page 75 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Signed Integers
Fixed point numbers include real numbers with a fixed number of decimals, such as those
commonly used to denote money amounts in the United States. We shall focus only on
integers and relegate the study of real numbers to the floating point discussion.

Integers are stored in a number of formats. The most common formats today include 16 and
32 bits. The new edition of Visual Basic will include a 64-bit standard integer format.

Bits in the storage of an integer are usually numbered right to left, with bit 0 being the right-
most or least-significant. In eight bit integers, the bits from left to right are numbered 7 to 0.
In 32 bit integers, the bits from left to right are numbered 31 to 0. As we shall see, the IBM
Mainframe documentation numbers the bits left to right, with bit 0 being the leftmost.

Although 32-bit integers are probably the most common, we shall focus on eight-bit integers
because they are easy to illustrate. In these discussions, the student should recall the powers
of 2: 20 = 1, 21 = 2, 22 = 4, 23 = 8, 24 = 16, 25 = 32, 26 = 64, 27 = 128, and 28 = 256.

The simplest topic to cover is the storage of unsigned integers. As there are 2N possible
combinations of N binary bits, there are 2N unsigned integers ranging from 0 to 2N – 1. For
eight-bit unsigned integers, this range is 0 though 255, as 28 = 256. Conversion from binary
to decimal is easy and follows the discussion earlier in this chapter.

Of the various methods for storing signed integers, we shall discuss only three
Two’s complement
One’s complement (but only as a way to compute the two’s complement)
Excess 127 (for 8-bit numbers only) as a way to understand the floating point standard.

One’s complement arithmetic is mostly obsolete and interests us only as a stepping-stone to


two’s complement arithmetic. To compute the one’s complement of a number:
1) Represent the number as an N-bit binary number
2) Convert every 0 to a 1 and every 1 to a 0.

Note that it is essential to state how many bits are to be used. Consider the 8-bit two’s
complement of 100. Now 100 = 64 + 32 + 4, so decimal 100 = 0110 0100 binary. Note the
leading 0; we must have an 8-bit representation. As another example, consider the decimal
number 12. It can be represented in binary as 1100, but is 0000 1100 as an 8–bit binary
number. Recall that the space in the binary is for readability only.

Decimal 100 = 0110 0100


One’s complement 1001 1011; in one’s complement, decimal –100 = 1001 1011 binary.

There are a number of problems in one’s complement arithmetic, the most noticeable being
illustrated by the fact that the one’s complement of 0 is 1111 1111. In this system, we have
–0  0, a violation of some of the basic principles of mathematics.

Page 76 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The two’s complement of a number is obtained as follows:


1) First take the one’s complement of the number
2) Add 1 to the one’s complement and discard the carry out of the left-most column.

Decimal 100 = 0110 0100


One’s complement 1001 1011

We now do the addition 1001 1011


1
1001 1100

Thus, in eight-bit two’s complement arithmetic


Decimal 100 = 0110 0100 binary
Decimal – 100 = 1001 1100 binary

This illustrates one pleasing feature of two’s complement arithmetic: for both positive and
negative integers the last bit is zero if and only if the number is even.

The real reason for the popularity of two’s complement can be seen by calculating the
representation of – 0. To do this we take the two’s complement of 0.

In eight bits, 0 is represented as 0000 0000


Its one’s complement is represented as 1111 1111.
We now take the two’s complement of 0.

Here is the addition 1111 1111


1
1 0000 0000 – but discard the leading 1.
Thus the two’s complement of 0 is represented as 0000 0000, as required by algebra, and we
avoid the messy problem of having – 0  0.

In N- bit two’s complement arithmetic, + 127 0111 1111


the range of integers that can be + 10 0000 1010
represented is – 2N-1 through 2N-1 – 1 +1 0000 0001
inclusive, thus the range for eight-bit 0 0000 0000
two’s complement integers is –128 –1 1111 1111 The number is
through 127 inclusive, as 27 = 128. The – 10 1111 0110 negative if and
table at the right shows a number of – 127 1000 0001 only if the high
binary representations for this example. – 128 1000 0000 order bit is 1.

We now give the ranges allowed for the most common two’s complement representations.
Eight bit – 128 to +127
16–bit – 32,768 to +32,767
32–bit – 2,147,483,648 to +2,147,483,647

Page 77 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The range for 64-bit two’s complement integers is – 263 to 263 – 1. As an exercise in math, I
propose to do a rough calculation of 263. This will be done using only logarithms.

There is a small collection of numbers that the serious student of computer science should
memorize. Two of these numbers are the base-10 logarithms of 2 and 3. To five decimal
places, log 2 = 0.30103 and log 3 = 0.47712.

Now 263 = (100.30103)63 = 1018.9649 = 100.9649  1018 = 9.224  1018, so a 64-bit integer allows
the representation of 18 digit numbers and most 19 digit numbers.

Reminder: For any number of bits, in two’s complement arithmetic the number is negative if
and only if the high-order bit in the binary representation is a 1.

Sign Extension
This applies to numbers represented in one’s-complement and two’s-complement form. The
issue arises when we store a number in a form with more bits; for example when we store a
16-bit integer in a 32-bit register. The question is how to set the high-order bits.

Consider a 16-bit integer stored in two’s-complement form. Bit 15 is the sign bit. We can
consider bit representation of the number as A15A14A13A12A11A10A9A8A7A6A5A4A3A2A1A0.
Consider placing this number into a 32-bit register with bits numbered R31 through R0, with
R31 being the sign bit. Part of the solution is obvious: make Rk = Ak for 0  k  15. What is
not obvious is how to set bits 31 through 16 in R as the 16-bit integer A has no such bits.

For non-negative numbers the solution is obvious and simple, set the extra bits to 0. This is
like writing the number two hundred (200) as a five digit integer; write it 00200. But
consider the 16-bit binary number 1111 1111 1000 0101, which evaluates to decimal –123.
If we expanded this to 0000 0000 0000 0000 1111 1111 1000 0101 by setting the high order
bits to 0’s, we would have a positive number, evaluating as 65413. This is not correct.

The answer to the problem is sign extension, which means filling the higher order bits of the
bigger representation with the sign bit from the more restricted representation. In our
example, we set bits 31 through 16 of the register to the sign bit of the 16-bit integer. The
correct answer is then 1111 1111 1111 1111 1111 1111 1000 0101.

Note – the way I got the value 1111 1111 1000 0101 for the 16-bit representation of – 123
was to compute the 8-bit representation, which is 1000 0101. The sign bit in this
representation is 1, so I extended the number to 16-bits by setting the high order bits to 1.

Page 78 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Nomenclature: “Two’s-Complement Representation” vs. “Taking the Two’s-Complement”


We now address an issue that seems to cause confusion to some students. There is a
difference between the idea of a complement system and the process of taking the
complement. Because we are interested only in the two’s-complement system, I restrict my
discussion to that system.

Question: What is the representation of the positive number 123 in 8–bit two’s complement
arithmetic?
Answer: 0111 1011. Note that I did not take the two’s complement of anything to get this.

Two’s-complement arithmetic is a system of representing integers in which the two’s-


complement is used to compute the negative of an integer. For positive integers, the method
of conversion to binary differs from unsigned integers only in the representable range.

For N-bit unsigned integers, the range of integers representable is 0 ... 2N – 1, inclusive. For
N-bit two’s-complement integers the range of non-negative integers representable is
0 ... 2N-1 – 1, inclusive. The rules for converting decimal to binary integers are the same for
non-negative integers – one only has to watch the range restrictions.

The only time when one must use the fact that the number system is two’s-complement (that
is – take the two’s-complement) is when one is asked about a negative number. Strictly
speaking, it is not necessary to take the two’s-complement of anything in order to represent a
negative number in binary, it is only that most students find this the easiest way.

Question: What is the representation of –123 in 8-bit two’s-complement arithmetic?


Answer: Perhaps I know that the answer is 1000 0101. As a matter of fact, I can calculate
this result directly without taking the two’s-complement of anything, but most students find
the mechanical way the easiest way to the solution. Thus, the preferred solution for most
students is
1) We note that 0  123  27 – 1, so both the number and its negative
can be represented as an 8-bit two’s-complement integer.
2) We note that the representation of +123 in 8-bit binary is 0111 1011
3) We take the two’s-complement of this binary result to get the binary
representation of –123 as 1000 0101.

We note in passing a decidedly weird way to calculate the representations of non-negative


integers in two’s-complement form. Suppose we want the two’s-complement representation
of +123 as an eight-bit binary number. We could start with the fact that the representation of
–123 in 8-bit two’s-complement is 1000 0101 and take the two’s complement of 1000 0101
to obtain the binary representation of 123 = –(–123). This is perfectly valid, but decidedly
strange. One could work this way, but why bother?

Summary: Speaking of the two’s-complement does not mean that one must take the
two’s-complement of anything.

Page 79 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Arithmetic Overflow – “Busting the Arithmetic”


We continue our examination of computer arithmetic to consider one more topic – overflow.
Arithmetic overflow occurs under a number of cases:
1) when two positive numbers are added and the result is negative
2) when two negative numbers are added and the result is positive
3) when a shift operation changes the sign bit of the result.

In mathematics, the sum of two negative numbers is always negative and the sum of two
positive numbers is always positive. The overflow problem is an artifact of the limits on the
range of integers and real numbers as stored in computers. We shall consider only overflows
arising from integer addition.

For two’s-complement arithmetic, the range of storable integers is as follows:


16-bit – 215 to 215 – 1 or – 32768 to 32767
31 31
32-bit – 2 to 2 – 1 or – 2147483648 to 2147483647

In two’s-complement arithmetic, the most significant (left-most) bit is the sign bit

Overflow in addition occurs when two numbers, each with a sign bit of 0, are added and the
sum has a sign bit of 1 or when two numbers, each with a sign bit of 1, are added and the sum
has a sign bit of 0. For simplicity, we consider 16-bit addition. As an example, consider the
sum 24576 + 24576 in both decimal and binary. Note 24576 = 16384 + 8192 = 214 + 213.

24576 0110 0000 0000 0000


24576 0110 0000 0000 0000
– 16384 1100 0000 0000 0000

In fact, 24576 + 24576 = 49152 = 32768 + 16384. The overflow is due to the fact that 49152
is too large to be represented as a 16-bit signed integer.

As another example, consider the sum (–32768) + (–32768). As a 16–bit signed integer,
the sum is 0!
–32768 1000 0000 0000 0000
–32768 1000 0000 0000 0000
0 0000 0000 0000 0000

It is easily shown that addition of a validly positive integer to a valid negative integer cannot
result in an overflow. For example, consider again 16–bit two’s–complement integer
arithmetic with two integers M and N. We have 0  M  32767 and –32768  N  0. If
|M|  |N|, we have 0  (M + N)  32767 and the sum is valid. Otherwise, we have
–32768  (M + N)  0, which again is valid.

Integer overflow can also occur with subtraction. In this case, the two values (minuend and
subtrahend) must have opposite signs if overflow is to be possible.

Page 80 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Excess–64 and Excess–127


We now cover excess–M representation for both M = 64 and M = 127. This method is of
limited utility in storing integers, but is used to store the exponent in several common
floating point representations, including the IEEE floating point standard (with M = 127) and
the IBM Mainframe format (M = 64). In general, we can consider an excess–M notation for
any positive integer M.

For an N–bit excess–M representation, the rules for conversion from binary to decimal are:
1) Evaluate as an unsigned binary number
2) Subtract M.

To convert from decimal to binary, the rules are


1) Add M
2) Evaluate as an N–bit unsigned binary number.

The observant reader will note an obvious relationship between the values of the integers
N and M. Recall that an N–bit number can represent 2N values, as unsigned integers this
represents the range 0 through 2N – 1. One would expect that M  2N/ 2 = 2N-1. The
following table gives some values for typical floating–point standards.
Format N 2N M
IEEE Single Precision 8 256 127
IEEE Double Precision 11 2048 1023
IBM Single Precision 7 128 64
IBM Double Precision 7 128 64
As an example consider eight-bit excess–127 notation. The range of values that can be
stored is based on the range that can be stored in the plain eight-bit unsigned standard:
0 through 255. Remember that in excess–127 notation, to store an integer N we first form
the number N + 127. The limits on the unsigned eight-bit storage require that
0  (N + 127)  255, or – 127  N  128.

As an exercise, we note the eight-bit excess-127 representation of – 5, – 1, 0 and 4.


– 5 + 127 = 122. Decimal 122 = 0111 1010 binary, the answer.
– 1 + 127 = 126. Decimal 126 = 0111 1110 binary, the answer.
0 + 127 = 127. Decimal 127 = 0111 1111 binary, the answer.
4 + 127 = 131 Decimal 131 = 1000 0011 binary, the answer.

We have now completed the discussion of common ways to represent unsigned and signed
integers in a binary computer. We now start our progress towards understanding the storage
of real numbers in a computer. There are two ways to store real numbers – fixed point and
floating point. We focus this discussion on floating point, specifically the IEEE and IBM
single precision standards for storing floating point numbers in a computer.

Page 81 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Normalized Numbers
The last topic to be discussed prior to defining the standards for floating point numbers is that
of normalized numbers. We must also mention the concept of denormalized numbers,
though we shall spend much less time on the latter.

A normalized number is defined in terms of a positive base B, with B  2 being required.


Such a normalized number is one with a representation of the form X  BP, where we require
that 1.0  X < B. The two most common representations use B = 2 and B = 16. Thus we
have the following requirements for the representation.
B=2 N = X  2P, with 1.0  X < 2.0
B = 16 N = X  16P, with 1/16 = 0.625  X < 1.0

Before considering how to store floating–point numbers is the standard format, we ask a very
simple question, which holds for all representations.
“What common number cannot be represented as a normalized number?”

The answer is zero. Consider the binary floating point formats. There is no power of 2 such
that 0.0 = X  2P, where 1.0  X < 2.0. We shall return to this issue when we discuss the
IEEE standard, at which time we shall give a more precise definition of the denormalized
numbers, and note that they include 0.0. For the moment, we focus on obtaining the
normalized representation of positive real numbers.

We start with some simple examples.


1.0 = 1.0  20, thus X = 1.0 and P = 0.
1.5 = 1.5  20, thus X = 1.5 and P = 0.
2.0 = 1.0  21, thus X = 1.0 and P = 1
0.25 = 1.0  2-2, thus X = 1.0 and P = -2
7.0 = 1.75  22, thus X = 1.75 and P = 2
0.75 = 1.5  2-1, thus X = 1.5 and P = -1.

Normalizing a Number (Style of the IEEE Format)


To better understand this conversion, we shall do a few more examples using the more
mechanical approach to conversion of decimal numbers to binary. We start with an example:
9.375  10-2 = 0.09375. We now convert to binary.

0.09375  2 = 0.1875 0
0.1875  2 = 0.375 0 Thus decimal 0.09375 = 0.00011 binary
0.375  2 = 0.75 0 or 1.1  2-4 in the normalized notation.
0.75  2 = 1.5 1
0.5  2 = 1.0 1

Please note that these representations take the form X  2P, where X is represented as a
binary number but P is represented as a decimal number. Later, P will be converted to an
excess–127 binary representation, but for the present it is easier to keep it in decimal.

Page 82 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

We now convert the decimal number 80.09375 to binary notation. I have chosen 0.09375 as
the fractional part out of laziness as we have already obtained its binary representation. We
now convert the number 80 from decimal to binary. Note 80 = 64 + 16 = 26  (1 + ¼).

80 / 2 = 40 remainder 0
40/2 = 20 remainder 0
20 / 2 = 10 remainder 0
10 / 2 =5 remainder 0
5/2 =2 remainder 1
2/2 =1 remainder 0
1/2 =1 remainder 1

Thus decimal 80 = 1010000 binary and decimal 80.09375 = 1010000.00011 binary. To get
the binary point to be after the first 1, we move it six places to the left, so the normalized
form of the number is 1.01000000011  26, as expected. For convenience, we write this as
1.0100 0000 0110  26.

Normalizing a Number (Style of IBM Mainframe)


Consider again 80.09375 = 1010000.00011 binary, rewritten as 0101 0000.0001 1000, or
0x50.18. In hexadecimal, this should be seen as 0.5018162, where the number 5018 is
really a hexadecimal representation of the decimal number (5/16 + 0/162 + 1/163 + 8/164) that
might better be written as 0x0.5018.

Infinity and NAN (Not–A–Number)


Some formats for storing floating–point numbers, such as the IEEE 754 standard, allow for
representing items that are not really numbers. Among these values are the pseudo–numbers
called Infinity and NAN. We explain the two with a thought experiment.

Consider the quotient 1/0. The equation 1 / 0 = X is equivalent to solving for a number X
such that 0  X = 1. There is no such number. Loosely speaking, we say 1 / 0 = .

More precisely, consider the value of (1.0 / w) for w > 0. As the real number w becomes very
small, the value (1.0 / w) grows very large. As the value w approaches 0, the value (1.0 / w)
1
grows without bound. In terms of calculus, we say that lim     . In the precise
w0 w 
reasoning associated with calculus, we never consider the pseudo–number 1/0, just the limit.

Now consider the quotient 0/0. Again we are asking for the number X such that 0  X = 0.
The difference here is that this equation is true for every number X. In terms of the
standards, 0 / 0 is called “Not a Number”, or “NaN”. The number NaN can also be used for
arithmetic operations that have no solutions, such as taking the square root of –1 while
limited to the real number system, or finding the angle whose trigonometric sine has value 2.

There is no evidence that the IBM Mainframe assembler supports either Infinity or NaN.

Page 83 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The IBM Mainframe Floating–Point Formats


In this discussion, we shall adopt the bit numbering scheme used in the IBM documentation,
with the leftmost (sign) bit being number 0. The IBM Mainframe supports three formats;
those representations with more bits can be seen to afford more precision.
Single precision 32 bits numbered 0 through 31,
Double precision 64 bits numbered 0 through 63, and
Extended precision 128 bits numbered 0 through 127.
As in the IEEE–754 standard, each floating point number in this standard is specified by
three fields: the sign bit, the exponent, and the fraction. Unlike the IEEE–754 standard, the
IBM standard allocates the same number of bits for the exponent of each of its formats. The
bit numbers for each of the fields are shown below.
Format Sign bit Bits for exponent Bits for fraction
Single precision 0 1–7 8 – 31
Double precision 0 1–7 8 – 63
Extended precision 0 1–7 8 – 127
Note that each of the three formats uses eight bits to represent the exponent, in what is called
the characteristic field, and the sign bit. These two fields together will be represented by
two hexadecimal digits in a one–byte field.
The size of the fraction field does depend on the format.
Single precision 24 bits 6 hexadecimal digits,
Double precision 56 bits 14 hexadecimal digits, and
Extended precision 120 bits 30 hexadecimal digits.
The Characteristic Field
In IBM terminology, the field used to store the representation of the exponent is called the
“characteristic”. This is a 7–bit field, used to store the exponent in excess–64 format; if the
exponent is E, then the value (E + 64) is stored as an unsigned 7–bit number.
Recalling that the range for integers stored in 7–bit unsigned format is 0  N  127, we have
0  (E + 64)  127, or –64  E  63.
Range for the Standard
We now consider the range and precision associated with the IBM floating point formats.
The reader should remember that the range is identical for all of the three formats; only the
precision differs. The range is usually specified as that for positive numbers, from a very
small positive number to a large positive number. There is an equivalent range for negative
numbers. Recall that 0 is not a positive number, so that it is not included in either range.
Given that the base of the exponent is 16, the range for these IBM formats is impressive. It is
from somewhat less than 16–64 to a bit less than 1663. Note that 1663 = (24)63 = 2252, and
16–64 = (24)–64 = 2–256 = 1.0 / (2256) and recall that log10(2) = 0.30103. Using this, we compute
the maximum number storable at about (100.30103)252 = 1075.86  91075. We may approximate
the smallest positive number at 1.0 / (361075) or about 3.010–77. In summary, the following
real numbers can be represented in this standard: X = 0.0 and 3.010–77 < X < 91075.
One would not expect numbers outside of this range to appear in any realistic calculation.

Page 84 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Precision for the Standard


Unlike the range, which depends weakly on the format, the precision is very dependent on
the format used. More specifically, the precision is a direct function of the number of bits
used for the fraction. If the fraction uses F bits, the precision is 1 part in 2F.
We can summarize the precision for each format as follows.
Single precision F = 24 1 part in 224.
Double precision F = 56 1 part in 256.
Extended precision F = 120 1 part in 2120.
The first power of 2 is easily computed; we use logarithms to approximate the others.
224 = 16,777,216
256  (100.30103)56 = 1016.85  91016.
2120  (100.30103)120 = 1036.12  1.21036.
The argument for precision is quite simple. Consider the single precision format, which is
more precise than 1 part in 10,000,000 and less precise than 1 part in 100,000,000. In other
words it is better than 1 part in 107, but not as good as 1 in 108; hence we say 7 digits.
Range and Precision
We now summarize the range and precision for the three IBM Mainframe formats.
Format Positive Range Precision
Single Precision 3.010–77 < X < 91075 7 digits
Double Precision 3.010–77 < X < 91075 16 digits
Extended Precision 3.010–77 < X < 91075 36 digits
Representation of Floating Point Numbers
As with the case of integers, we shall most commonly use hexadecimal notation to represent
the values of floating–point numbers stored in the memory. From this point, we shall focus
on the two more commonly used formats: Single Precision and Double Precision.
The single precision format uses a 32–bit number, represented by 8 hexadecimal digits.
The double precision format uses a 64–bit number, represented by 16 hexadecimal digits.
Due to the fact that the two formats use the same field length for the characteristic,
conversion between the two is quite simple. To convert a single precision value to a double
precision value, just add eight hexadecimal zeroes.
Consider the positive number 128.0.
As a single precision number, the value is stored as 4280 0000.
As a double precision number, the value is stored as 4280 0000 0000 0000.
Conversions from double precision to single precision format will involve some rounding.
For example, consider the representation of the positive decimal number 123.45. In a few
pages, we shall show that it is represented as follows.
As a double precision number, the value is stored as 427B 7333 3333 3333.
As a single precision number, the value is stored as 427B 7333.

Page 85 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

The Sign Bit and Characteristic Field


We now discuss the first two hexadecimal digits in the representation of a floating–point
number in these two IBM formats. In IBM nomenclature, the bits are allocated as follows.
Bit 0 the sign bit
Bits 1 – 7 the seven–bit number storing the characteristic.
Bit Number 0 1 2 3 4 5 6 7
Hex digit 0 1
Use Sign bit Characteristic (Exponent + 64)
Consider the four bits that comprise hexadecimal digit 0. The sign bit in the floating–point
representation is the “8 bit” in that hexadecimal digit. This leads to a simple rule.
If the number is not negative, bit 0 is 0, and hex digit 0 is one of 0, 1, 2, 3, 4, 5, 6, or 7.
If the number is negative, bit 0 is 1, and hex digit 0 is one of 8, 9, A, B, C, D, E, or F.
Some Single Precision Examples
We now examine a number of examples, using the IBM single–precision floating–point
format. The reader will note that the methods for conversion from decimal to hexadecimal
formats are somewhat informal, and should check previous notes for a more formal method.
Note that the first step in each conversion is to represent the magnitude of the number in the
required form X16E, after which we determine the sign and build the first two hex digits.
Example 1: Positive exponent and positive fraction.
The decimal number is 128.50. The format demands a representation in the form X16E,
with 0.625  X < 1.0. As 128  X < 256, the number is converted to the form X162.
Note that 128 = (1/2)162 = (8/16)162 , and 0.5 = (1/512)162 = (8/4096)162.
Hence, the value is 128.50 = (8/16 + 0/256 + 8/4096)162; it is 1620x0.808.
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The fractional part comprises six hexadecimal digits, the first three of which are 808.
The number 128.50 is represented as 4280 8000.
Example 2: Positive exponent and negative fraction.
The decimal number is the negative number –128.50. At this point, we would normally
convert the magnitude of the number to hexadecimal representation. This number has the
same magnitude as the previous example, so we just copy the answer; it is 1620x0.808.
We now build the first two hexadecimal digits, noting that the sign bit is 1.
Field Sign Characteristic
Value 1 1 0 0 0 0 1 0
Hex value C 2
The number 128.50 is represented as C280 8000.
Note that we could have obtained this value just by adding 8 to the first hex digit.

Page 86 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Example 3: Negative exponent and positive fraction.


The decimal number is 0.375. As a fraction, this is 3/8 = 6/16. Put another way, it is
1600.375 = 160(6/16). This is in the required format X16E, with 0.625  X < 1.0.
The exponent value is 0, so the characteristic value is either 64 or 0x40 = 100 0000. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 0 0
Hex value 4 0
The fractional part comprises six hexadecimal digits, the first of which is a 6.
The number 0.375 is represented in single precision as 4060 0000.
The number 0.375 is represented in double precision as 4060 0000 0000 0000.
Example 4: A Full Conversion
The number to be converted is 123.45. As we have hinted, this is a non–terminator.
Convert the integer part.
123 / 16 = 7 with remainder 11 this is hexadecimal digit B.
7 / 16 = 0 with remainder 7 this is hexadecimal digit 7.
Reading bottom to top, the integer part converts as 0x7B.
Convert the fractional part.
0.45  16 = 7.20 Extract the 7,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3, and so on.
In the standard format, this number is 1620x0.7B33333333…...
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The number 123.45 is represented in single precision as 427B 3333.
The number 0.375 is represented in double precision as 427B 3333 3333 3333.
Example 5: One in “Reverse”
We are given the single precision representation of the number. It is 4110 0000.
What is the value of the number stored? We begin by examination of the first two hex digits.
Field Sign Characteristic
Value 0 1 0 0 0 0 0 1
Hex value 4 1
The sign bit is 0, so the number is positive. The characteristic is 0x41, so the exponent is
1 and the value may be represented by X161. The fraction field is 100 000, so the value is
161(1/16) = 1.0.

Page 87 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Example 6: Another in “Reverse”


We are given the single precision representation of the number. It is BEC8 0000.
What is the value of the number stored? We begin by examination of the first two hex digits.
Field Sign Characteristic
Value 1 0 1 1 1 1 1 0
Hex value B E
The characteristic has value 0x3E or decimal 316 + 14 = 62. The exponent has value
62 – 64 = –2. The number is then 16-20x0.C8 = 16-2(12/16 + 8/256), which can be
converted to decimal in any number of ways. I prefer the following conversion.
16-2(12/16 + 8/256) = 16-2(3/4 + 1/32) = 16-2(24/32 + 1/32) = 16-2(25/32)
= 25 / (32256) = 25 / 8192  3.051757810–3.
The answer is approximately the negative number –3.051757810–3.
Why Excess–64 Notation for the Exponent?
We have introduced two methods to be used for storing signed integers: two’s–complement
notation and excess–64 notation. One might well ask why two’s-complement notation is not
used to store the exponent in the characteristic field.

The answer for integer notation is simple. Consider some of examples.


128.50 is represented as 4280 8000. Viewed as a 32–bit integer, this is positive.
–128.50 is represented as C280 8000. Viewed as a 32–bit integer, this is negative.
1.00 is represented as 4110 0000. Viewed as a 32–bit integer, this is positive.
–3.0510–3 is represented as BEC8 0000. Viewed as a 32–bit integer, this is negative

It turns out that the excess–64 notation allows the use of the integer compare unit to compare
floating point numbers. Consider two floating point numbers X and Y. Pretend that they are
integers and compare their bit patterns as integer bit patterns. It viewed as an integer, X is
less than Y, then the floating point number X is less than the floating point Y. Note that we
are not converting the numbers to integer form, just looking at the bit patterns and pretending
that they are integers. For example, the above examples would yield the following order.
4280 8000 for 128.50. This is the largest.
4110 0000 for 1.00.
BEC8 0000 for –3.0510–3.
C280 8000 for –128.50. This is the most smallest (most negative).

Page 88 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Packed Decimal Formats


While the IBM mainframe provides three floating–point formats, it also provides another
format for use in what are called “fixed point” calculations. The term “fixed point” refers to
decimal numbers in which the decimal point takes a predictable place in the number; money
transactions in dollars and cents are a good and very important example of this.

Consider a ledger such as might be maintained by a commercial firm. This contains credits
and debits, normally entered as money amounts with dollars and cents. The amount that
might be printed as “$1234.56” could easily be stored as the integer 123456 if the program
automatically adjusted to provide the implicit decimal point. This fact is the basis for the
Packed Decimal Format developed by IBM in response to its business customers.

One may well ask “Why not use floating point formats for financial transactions?”. We
present a fairly realistic scenario to illustrate the problem with such a choice. This example
is based on your author’s experience as a consultant to a bank in Rochester, NY.

It is a fact that banks loan each other money on an overnight basis; that is, the bank borrows
the money at 6:00 PM today and repays it at 6:00 AM tomorrow. While this may seem a bit
strange to those of us who think in terms of 20–year mortgages, it is an important practice.
Overnight loans in the amount of one hundred million dollars are not uncommon.

Suppose that I am a bank officer, and that another bank wants to borrow $100,000,000
overnight. I would like to make the loan, but do not have the cash on hand. On the other
hand, I know a bank that will lend me the money at a smaller interest rate. I can make the
loan and pocket the profit.

Suppose that the borrowing bank is willing to pay 8% per year on the borrowed amount.
This corresponds to a payback of (1.08)1/730 = 1.0001054, which is $10,543 in interest.

Suppose that I have to borrow the money at 6% per annum. This corresponds to my paying
at a rate of (1.06)1/730 = 1.0000798, which is a cost of $7,982 to me. I make $2,561.

Consider these numbers as single–precision floating point format in the IBM Mainframe.
My original money amount is $100,000,000
The interest I make is $10,543
My principal plus interest is $100,010,500 Note the truncation due to precision.
The interest I pay is $7,982
What I get back is $100,002,000 Again, note the truncation.

The use of floating–point arithmetic has cost me $561 for an overnight transaction. I do not
like that. I do not like numbers that are rounded off; I want precise arithmetic.

Almost all banks and financial institutions demanded some sort of precise decimal
arithmetic; IBM’s answer was the Packed Decimal format.

Page 89 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

BCD (Binary Coded Decimal)


The best way to introduce the Packed Decimal Data format is to first present an earlier
format for encoding decimal digits. This format is called BCD, for “Binary Coded Decimal”.
As may be inferred from its name, it is a precursor to EBCDIC (Extended BCD Interchange
Code) in addition to heavily influencing the Packed Decimal Data format.
We shall introduce BCD and compare it to the 8–bit unsigned binary previously discussed for
storing unsigned integers in the range 0 through 255 inclusive. While BCD doubtless had
encodings for negative numbers, we shall postpone signed notation to Packed Decimal.
The essential difference between BCD and 8–bit binary is that BCD encodes each decimal in
a separate 4–bit field (sometimes called “nibble” for half–byte). This contrasts with the usual
binary notation in which it is the magnitude of the number, and not the number of digits, that
determines whether or not it can be represented in the format.
We begin with a table of the BCD codes for each of the ten decimal digits. These codes are
given in both binary and hexadecimal. It will be important for future discussions to note that
these encodings are actually hexadecimal digits; they just appear to be decimal digits.
Digit ‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’
Binary 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001
Hexadecimal 0 1 2 3 4 5 6 7 8 9
To emphasize the difference between 8–bit unsigned binary and BCD, we shall examine a
selection of two–digit numbers and their encodings in each system.
Decimal Number 8–bit binary BCD (Represented in binary) BCD (hexadecimal)
5 0000 0101 0000 0101 05
13 0000 1101 0001 0011 13
17 0001 0001 0001 0111 17
23 0001 0111 0010 0011 23
31 0001 1111 0011 0001 31
64 0100 0000 0110 0100 64
89 0101 1001 1000 1001 89
96 0110 0000 1001 0110 96
As a hypothetical aside, consider the storage of BCD numbers on a byte–addressable
computer. The smallest addressable unit would be an 8–bit byte. As a result of this, all BCD
numbers would need to have an even number of digits, as to fill up an integral number of
bytes. Our solution to the storage of integers with an odd number of digits is to recall that a
leading zero does not change the value of the integer.
In this hypothetical scheme of storage:
1 would be stored as 01,
22 would be stored as 22,
333 would be stored as 0333,
4444 would be stored as 4444,
55555 would be stored as 055555, and
666666 would be stored as 666666.

Page 90 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Packed Decimal Data


The packed decimal format should be viewed as a generalization of the BCD format with the
specific goal of handling the fixed point arithmetic so common in financial transactions. The
two extensions of the BCD format are as follows:
1. The provision of a sign “half byte” so that negative numbers can be handled.
2. The provision for variable length strings.
While the term “fixed point” is rarely used in computer literature these days, the format is
very common. Consider any transaction denominated in dollars and cents. The amount will
be represented as a real number with exactly two digits to the right of the decimal point; that
decimal point has a fixed position in the notation, hence the name “fixed point”.
The packed decimal format provides for a varying number of digits, one per half–byte,
followed by a half–byte denoting the sign of the number. Because of the standard byte
addressability issues, the number of half–bytes in the representation must be an even number;
given the one half–byte reserved for the sign, this implies an odd number of digits.
In the BCD encodings, we use one hexadecimal digit to encode each of the decimal digits.
This leaves the six higher–valued hexadecimal digits (A, B, C, D, E, and F) with no use; in
BCD these just do not encode any values. In Packed Decimal, each of these will encode a
sign. Here are the most common hexadecimal digits used to represent signs.
Binary Hexadecimal Sign Comment
1100 C + The standard plus sign
1101 D – The standard minus sign
1111 F + A plus sign seen in converted EBCDIC
We now move to the IBM implementation of the packed decimal format. This section breaks
with the tone previously established in this chapter – that of discussing a format in general
terms and only then discussing the IBM implementation. The reason for this change is
simple; the IBM implementation of the packed decimal format is the only one used.
The Syntax of Packed Decimal Format
1. The length of a packed decimal number may be from 1 to 31 digits; the
number being stored in memory as 1 to 16 bytes.
2. The rightmost half–byte of the number contains the sign indicator. In constants
defined by code, this is 0xC for positive numbers and 0xD for negative.
3. The remaining number of half–bytes (always an odd number) contain the
hexadecimal encodings of the decimal digits in the number.
4. The rightmost byte in the memory representation of the number holds one
digit and the sign half–byte. All other bytes hold two digits.
5. The number zero is always represented as the two digits 0C, never 0D.
6. Any number with an even number of digits will be converted to an equivalent
number with a prepended “0” prior to storage as packed decimal.
7. Although the format allows for storage of numbers with decimal points, neither
the decimal point nor any indication of its position is stored. As an example,
each of 1234.5, 123.45, 12.345, and 1.2345 is stored as 12345C.

Page 91 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

There are two common ways to generate numbers in packed decimal format, and quite a
variety of instructions to operate on data in this format. We shall discuss these in later
chapters. For the present, we shall just show a few examples.
1. Store the positive number 144 in packed decimal format.
Note that the number 144 has an odd number of digits. The format just adds the half–byte
for non–negative numbers, generating the representation 144C. This value is often written
as 14 4C, with the space used to emphasize the grouping of half–bytes by twos.
2. Store the negative number –1023 in packed decimal format.
Note that the magnitude of the number (1023) has an even number of digits, so the format
will prepend a “0” to produce the equivalent number 01023, which has an odd number of
digits. The value stored is 01023D, often written as 01 02 3D.
2. Store the negative number –7 in packed decimal format.
Note that the magnitude of the number (7) has an odd number of digits, so the format
just adds the sign half–byte to generate the representation 7D.
4. Store the positive number 123.456 in packed decimal format.
Note that the decimal point is not stored. This is the same as the storage of the number
123456 (which has a decidedly different value). This number has an even number of digits,
so that it is converted to the equivalent value 0123456 and stored as 01 23 45 6C.
5. Store the positive number 1.23456 in packed decimal format.
Note that the decimal point is not stored. This is the same as the storage of the number
123456 (which has a decidedly different value). This number has an even number of digits,
so that it is converted to the equivalent value 0123456 and stored as 01 23 45 6C.
6. Store the positive number 12345.6 in packed decimal format.
Note that the decimal point is not stored. This is the same as the storage of the number
123456 (which has a decidedly different value). This number has an even number of digits,
so that it is converted to the equivalent value 0123456 and stored as 01 23 45 6C.
7. Store the number 0 in packed decimal form.
Note that 0 is neither positive nor negative. IBM convention treats the zero as a positive
number, and always stores it as 0C.
8. Store the number 12345678901234567890 in packed decimal form.
Note that very large numbers are easily stored in this format. The number has 20 digits, an
even number, so it must first be converted to the equivalent 012345678901234567890. It is
stored as 01 23 45 67 89 01 23 45 67 89 0C.

Comparison: Floating–Point and Packed Decimal


Here are a few obvious comments on the relative advantages of each format.
1. Packed decimal format can provide great precision and range, more that is required
for any conceivable financial transaction. It does not suffer from round–off errors.
2. The packed decimal format requires the code to track the decimal points explicitly.
This is easily done for addition and subtraction, but harder for other operations.
The floating–point format provides automatic management of the decimal point.

Page 92 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Character Codes
We now consider the methods by which computers store character data. There are three
character codes of interest: ASCII, EBCDIC, and Unicode. The EBCDIC code is only used
by IBM in its mainframe computer. The ASCII code is by far more popular, so we consider
it first and then consider EBCDIC.

ASCII
The figure below shows the ASCII code. Only the first 128 characters (Codes 00 – 7F in
hexadecimal) are standard. There are several interesting facts.

Last Digit \ First Digit 0 1 2 3 4 5 6 7


0 NUL DLE SP 0 @ P ` p
1 SOH DC1 ! 1 A Q a q
2 STX DC2 “ 2 B R b r
3 ETX DC3 # 3 C S c s
4 EOT DC4 $ 4 D T d t
5 ENQ NAK % 5 E U e u
6 ACK SYN & 6 F V f v
7 BEL ETB ` 7 G W g w
8 BS CAN ( 8 H X h x
9 HT EM ) 9 I Y i y
A LF SUB * : J Z j z
B VT ESC + ; K [ k {
C FF FS ‘ < L \ l |
D CR GS - = M ] m }
E SO RS . > N ^ n ~
F SI US / ? O _ o DEL

Let X be the ASCII code for a digit. Then X – ‘0’ = X – 30 is the value of the digit.
For example ASCII(‘7’) = 37, with value 37 – 30 = 7.

Let X be an ASCII code. If ASCII(‘A’)  X  ASCII(‘Z’) then X is an upper case letter.


If ASCII(‘a’)  X  ASCII(‘z’) then X is an lower case letter.
If ASCII(‘0’)  X  ASCII(‘9’) then X is a decimal digit.

Let X be an upper-case letter. Then ASCII ( lower_case(X) ) = ASCII ( X ) + 32


Let X be a lower case letter. Then ASCII ( UPPER_CASE(X) ) = ASCII (X ) – 32.
The expressions are ASCII ( X ) + 20 and ASCII (X ) – 20 in hexadecimal.

Page 93 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

EBCDIC
The EBCDIC (Extended Binary Coded Decimal Interchange Code) was developed in 1963
and 1964 by IBM for use on its System/360 line of computers. It was created as an extension
of the BCD (Binary Coded Decimal) encoding that existed at the time.
EBCDIC code uses eight binary bits to encode a character set; it can encode 256 characters.
The codes are binary numeric values, traditionally represented as two hexadecimal digits.
Character codes 0x00 through 0x3F and 0xFF represent control characters.
0x0D is the code for a carriage return; this moves the cursor back to the left margin.
0x20 is used by the ED (Edit) instruction to represent a packed digit to be printed.
0x21 is used by the ED (Edit) instruction to force significance.
All digits, including leading 0’s, from this position will be printed.
0x25 is the code for a line feed; this moves the cursor down but not horizontally.
0x2F is the BELL code; it causes the terminal to emit a “beep”.
Character codes 0x40 through 0x7F represent punctuation characters.
0x40 is the code for a space character: “ ”.
0x4B is the code for a decimal point: “.”.
0x4E is the code for a plus sign: “+”.
0x50 is the code for an ampersand: “&”.
0x5B is the code for a dollar sign: “$”.
0x5C is the code for an asterisk: “*”.
0x60 is the code for a minus sign: “–”.
0x6B is the code for a comma: “,”.
0x6F is the code for a question mark: “?”.
0x7C is the code for the commercial at sign: “@”.
Character codes 0x81 through 0xA9 represent the lower case Latin alphabet.
0x81 through 0x89 represent the letters “a” through “i”,
0x91 through 0x99 represent the letters “j” through “r”, and
0xA2 through 0xA9 represent the letters “s” through “z”.
Character codes 0xC1 through 0xE9 represent the upper case Latin alphabet.
0xC1 through 0xC9 represent the letters “A” through “I”,
0xD1 through 0xD9 represent the letters “J” through “R”, and
0xE2 through 0xE9 represent the letters “S” through “Z”.
Character codes 0xF0 through 0xF9 represent the digits “0” through “9”.
NOTES:
1. The control characters are mostly used for network data transmissions.
The ones listed above appear frequently in user code for terminal I/O.
2. There are gaps in the codes for the alphabetical characters.
This is due to the origins of the codes for the upper case alphabetic characters
in the card codes used on the IBM–029 card punch.
3. One standard way to convert an EBCDIC digit to its numeric value
is to subtract the hexadecimal number 0xF0 from the character code.

Page 94 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

An Abbreviated Table: The Common EBCDIC


Code Char. Comment Code Char. Comment Code Char. Comment
80 C0 } Right brace
81 a C1 A
82 b C2 B
83 c C3 C
84 d C4 D
85 e C5 E
86 f C6 F
87 g C7 G
0C FF Form feed 88 h C8 H
0D CR Return 89 i C9 I
16 BS Back space 90 D0 { Left brace
25 LF Line Feed 91 j D1 J
27 ESC Escape 92 k D2 K
2F BEL Bell 93 l D3 L
40 SP Space 94 m D4 M
4B . Decimal 95 n D5 N
4C < 96 o D6 O
4D ( 97 p D7 P
4E + 98 q D8 Q
4F | Single Bar 99 r D9 R
50 & A0 E0 \ Back slash
5A ! A1 ~ Tilde E1
5B $ A2 s E2 S
5C * A3 t E3 T
5D ) A4 u E4 U
5E ; A5 v E5 V
5F Not A6 w E6 W
60 – Minus A7 x E7 X
61 / Slash A8 y E8 Y
6A ¦ Dbl. Bar A9 z E9 Z
6B , Comma B0 ^ Carat F0 0
6C % Percent B1 F1 1
6D _ Underscore B2 F2 2
6E > B3 F3 3
6F ? B4 F4 4
79 ‘ Apostrophe B5 F5 5
7A : Colon B6 F6 6
7B # Sharp B7 F7 7
7C @ At Sign B8 F8 8
7D ' Apostrophe B9 F9 9
7E = Equals BA [ Left Bracket
7F " Quote BB ] R. Bracket

Page 95 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Some Final Comments


We end this chapter with a few comments on the value of numbers and their representation.
This set of comments addresses an issue that is a problem for only a few students.
While these comments apply to all numeric forms, they are restricted to a discussion of
positive integer forms. This restriction is only for the purpose of simplicity in the discussion;
having grasped these arguments, the reader may extend them to other numeric formats.
Consider the number 6143. This is obviously a positive integer. What is to be said about it?
The first thing to say is that it is not possible to write an integer. The set of integers can be
viewed as an abstract idea; what we write is best called the “print representation” of a
member of the set of integers. Thus, when we write “6143”, this set of symbols represents,
and is interpreted as, denoting the abstract concept associated with the integer.
In considering assembler language, it is important to note that integers are what they are. We
may speak of a number of representations of an integer; but the representations do not define
that integer, they only show how the integer might be represented. As an example, let us
consider the integer denoted by the print representation 6143.
If this integer is to be printed by an IBM assembler language program, it must be explicitly
be converted to its EBCDIC representation: F6 F1 F4 F3. This sequence of four bytes will be
printed on the output device as “6143”.
One may ask if this number is a binary, decimal, or hexadecimal number. This question is
not valid; the integer is what it is. One may ask about its representation in different bases.
As a binary number, decimal 6143 is represented as 1 0111 1111 1111.
As a hexadecimal number, decimal 6143 is represented as 0x17FF.
Put another way, we can ask the invalid question “Is 0x17FF a binary number?”. The answer
is simple: the number is what it is and is not to be confused with the mode of representation.
This number can be represented in many other forms, as a binary number it is
1 0111 1111 1111 or 0001 0111 1111 1111, depending on one’s preferences.
The “bottom line” is quite simple. No integer is to be viewed as essentially binary, octal,
decimal, or hexadecimal; integers are what they are and nothing more. Rather we should ask
about various representations of the number.
A Note on Bit Numbering.
Any N–bit number has bit numbers ranging from 0 through (N – 1). The common notation
assigns bit 0 as the rightmost bit and bit (N – 1) as the leftmost bit, usually the sign bit.
In IBM terminology, the leftmost bit is bit zero, so we have the following.
Byte
0 1 2 3 4 5 6 7
Halfword
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Fullword
0–7 8 – 15 16 – 23 24 – 31

Page 96 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

Some Solved Problems


Here is a collection of solved problems, taken from the answer keys to a few homework
assignments and several quizzes. These have been only minimally edited from the original.
In order to save time, this section retains the font styles used in the original answer keys.
The questions are in black font, the answers are in blue font, and comments are in red font.

1. Write the EBCDIC representation of the 9 character sequence “CPSC 3121”.

Answer: Look up the EBCDIC codes. The relevant codes are:


‘C’ C3 ‘P’ D7 ‘S’ E2 Blank 40
‘3’ F3 ‘1’ F1 ‘2’ F2

The codes: C3 D7 E2 C3 40 F3 F1 F2 F1, or C3D7 E2C3 40F3 F1F2 F1

2. These questions concern 10–bit integers, which are not common.


a) What is the range of integers storable in 10–bit unsigned binary form?
b) What is the range of integers storable in 10–bit two’s–complement form?
c) Represent the positive number 366 in 10–bit two’s–complement binary form.
d) Represent the negative number –172 in 10–bit two’s–complement binary form.
e) Represent the number 0 in 10–bit two’s–complement binary form.
ANSWER: Recall that an N–bit scheme can store 2N distinct representations.
For unsigned integers, this is the set of integers from 0 through 2N – 1.
For 2’s–complement, this is the set from – (2N–1) through 2N–1 – 1.
a) For 10–bit unsigned the range is 0 though 210 – 1, or 0 through 1023.
b) For 10–bit 2’s–complement, this is – (29) through 29 – 1, or – 512 through 511.
c) 366 / 2 = 183 remainder = 0
183 / 2 = 91 remainder = 1
91 / 2 = 45 remainder = 1
45 / 2 = 22 remainder = 1
22 / 2 = 11 remainder = 0
11 / 2 =5 remainder = 1
5/2 =2 remainder = 1
2/2 =1 remainder = 0
1/2 =0 remainder = 1. READ BOTTOM TO TOP!
The answer is 1 0110 1110, or 01 0110 1110, which equals 0x16E.
0x16E = 1256 + 616 + 14 = 256 + 96 + 14 = 256 + 110 = 366.
The number is not negative, so we stop here.
Comment: This question always fools some students, who feel compelled to take the
two’s–complement and thus produce the representation of –366.
d) 172 / 2 = 86 remainder = 0
86 / 2 = 43 remainder = 0

Page 97 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

43 / 2 = 21 remainder = 1
21 / 2 = 10 remainder = 1
10 / 2 =5 remainder = 0
5/2 =2 remainder = 1
2/2 =1 remainder = 0
1/2 =0 remainder = 1. READ BOTTOM TO TOP!
This number is 1010 1100, or 00 1010 1100, which equals 0x0AC.
0xAC = 1016 + 12 = 160 + 12 = 172.
The absolute value: 00 1010 1100
Take the one’s complement: 11 0101 0011
Add one: 1
The answer is: 11 0101 0100 or 0x354.
Comment: The conversion to binary just gives the value 1010 1100.
As this is to be a 10–bit number, it must be expanded to 10 bits
before the two’s–complement is taken. Convert 00 1010 1100.
e) The answer is 00 0000 0000.
You should just know this one.

3. This question concerns the range of integers that can be represented


in different formats. The answers can be either decimal or powers of 2 (–215).
a) What range can be represented by 12–bit unsigned integers?
b) What range can be represented by 12–bit two’s–complement signed integers?
c) What range can be represented by 16–bit two’s–complement signed integers?
Answer: In general, the ranges for N–bit integer representations are
0 through 2N–1 for N–bit unsigned integers, and
–(2N–1) through (2N–1) – 1 for N–bit two’s–complement integers.
a) For 12–bit unsigned integers, the range is 0 through 212 – 1 or 0 through 4,096.
b) For 12–bit two’s–complement, the range is –(211) through (211) – 1,
or –2,048 through 2,047.
c) For 16–bit two’s–complement, the range is –(215) through (215) – 1,
or –32,768 through 32,767.

4. a) How many hexadecimal digits are required to represent an 8–bit integer?


b) How many hexadecimal digits are required to represent a 32–bit integer?
ANSWER: Recall that each hexadecimal digit represents four bits.
a) It takes two hexadecimal digits to represent an 8–bit byte, or 8–bit integer.
b) It takes eight hexadecimal digits to represent a 32–bit integer.

Page 98 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

5. The System/360 uses 32–bit two’s–complement form for binary numbers.


Show the following answers as 16–bit binary numbers or four–digit hexadecimal.
a) Show the binary and hexadecimal representation of the positive integer +349.
b) Show the binary and hexadecimal representation for the negative integer –589.
Answer: a) Find 349 by repeated division.
349 / 2 = 174 remainder = 1
174 / 2 = 87 remainder = 0
87 / 2 = 43 remainder = 1 1 0101 1101, or 0001 0101 1101
43 / 2 = 21 remainder = 1 0000 0001 0101 1101
21 / 2 = 10 remainder = 1
10 / 2 = 5 remainder = 0 0x01 5D
5/2 = 2 remainder = 1
2/2 = 1 remainder = 0 1256 + 516 + 13 =
1/2 = 0 remainder = 1 256 + 80 + 13 = 349
Answer: b) Find 589 by repeated division.
589 / 2 = 294 remainder = 1
294 / 2 = 147 remainder = 0
147 / 2 = 73 remainder = 1 10 0100 1101 or 0010 0100 1101
73 / 2 = 36 remainder = 1 0000 0010 0100 1101
36 / 2 = 18 remainder = 0
18 / 2 = 9 remainder = 0 0x02 4D
9/2 = 4 remainder = 1
4/2 = 2 remainder = 0 2256 + 416 + 13 =
2/2 = 1 remainder = 0
1/2 = 0 remainder = 1 512 + 64 + 13 = 589
Take the two’s complement of 0000 0010 0100 1101
The positive binary number 0000 0010 0100 1101
Its one’s complement 1111 1101 1011 0010
Add one to get 1111 1101 1011 0011 or 0xFD B3
Comment: The correct answer to the first problem is shown above.
I accepted 0001 0101 1101 or 0x15D, which is a 12–bit number.
The 12–bit answer to part b) is just wrong. Deduct 4 points.
Also: A correct answer without showing the method is only partly correct.
I deducted 4 points for failure to show the method.
Also: At this point, this is not Packed Decimal Notation.
The leading 1111 is 0xF, the hexadecimal digit.

Page 99 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

6. Use the System/360 standard for Packed Decimal representation.


a) Represent the positive integer +19372 in the packed decimal format.
b) Represent the negative integer –8191 in the packed decimal format.
c) Represent the positive number 4,321.54 in the packed decimal format.
d) Represent the negative number –3.14159 in the packed decimal format.
Answer: a) This has five digits, so 19 37 2C
b) This has four digits, so 08 19 1D
c) This has six digits, so 04 32 15 4C Decimal point is not stored.
d) This has six digits, so 03 14 15 9D Decimal point is not stored.

Comment: There is not much method to show for this one,


so I did not deduct for just showing the answer.
Also: There must be an odd number of decimal digits.
Writing c) as 432154C is incorrect; this is 6 decimal digits.

7. These questions refer to the IBM Packed Decimal Format.


a) How many bytes are required to represent a 3–digit integer?
b) Give the Packed Decimal representation of the positive integer 123.
c) Give the Packed Decimal representation of the negative integer –107.
ANSWER: Recall that each decimal digit is stored as a hexadecimal digit, and
that the form calls for one hexadecimal digit to represent the sign.
a) One needs four hexadecimal digits, or two bytes, to represent three decimal digits.
b) 12 3C c) 10 7D

8. These questions also refer to the IBM Packed Decimal Format.


a) How many decimal digits can be represented in Packed Decimal form
if three bytes (8 bits each) are allocated to store the number?
b) What is the Packed Decimal representation of the largest integer stored in 3 bytes?
ANSWER: Recall that N bytes will store 2N hexadecimal digits. With one of these
reserved for the sign, this is (2N – 1) decimal digits.
a) 3 bytes can store five decimal digits.
b) The largest integer is 99,999. It is represented as 99 99 9C.

Page 100 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

9. The following numbers are given in System/360 Packed Decimal format. Perform the
indicated additions and show the sum as a packed decimal.
HINT: I would first convert to standard decimal, add them, and convert to packed format
a) The sum of 012C and 47344D.
b) The sum of 019D and 019C.
c) The sum of 32256C and 128D.
d) The sum of 044D and 122D.
Answer: a) This is 12 – 47344 = – 47332. 47 33 2D
b) This is 19 – 19 = 0 0C. (0D is wrong)
c) This is 32256 – 128 = 32128 32 12 8C
d) This is –44 – 122 = –166 16 6D
Comment: The answer to c) is 0C. The standard defines 0D as incorrect.
We must have a sign half–byte in this notation.
0000 is not a correct answer. It must have a sign indicator.
0 is also not a correct answer. It must have a sign indicator.
Also: Some students want to show the binary equivalent of each answer,
such as 0100 0111 0011 0011 0010 1101 for a).
This is not necessary and tends to be a bit confusing.

10. Give the correct Packed Decimal representation of the following numbers.
a) 31.41 b) –102.345 c) 1.02345
ANSWER: Recall that the decimal is not stored, and that we need to have an odd
count of decimal digits.
a) This becomes 3141, or 03141. 03141C
b) This becomes 102345, or 0102345 0102345D
c) This also becomes 102345, or 0102345 0102345C.
Comment: The purpose of this problem is to remind one that the decimal point
is not stored. Consider the answer 0102345C. It could represent any
of the following: 1.02345, 10.2345, 102.345, 1023.45, etc.

Page 101 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Data Representation

11. Perform the following sums of numbers in Packed Decimal format. Convert
to standard integer and show your math. Use Packed Decimal for the answers.
a) 025C + 085C d) 666D + 444D
b) 032C + 027D e) 091D + 0C
c) 10003C + 09989D
ANSWER: Just do the math required and convert back to standard Packed Decimal
format.
a) 025C + 085C represents 25 +85 = 110. This is represented as 110C.
b) 032C + 027D represents 32 –27 = 5. This is represented as 5C.
c) 10003C + 09989D represents 10003 –9989 = 14. This is represented as 01 4C.
d) 666D + 444D represents –666 –444 = –1110. This is represented as 01 11 0D.
e) 091D + 0C represents –91 +0 = –91. This is represented as 091D.

Page 102 Chapter 4 Last Revised On July 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 5: Introduction to Computer Architecture

We now begin an overview of the architecture of a typical stored program computer. It


should be noted that this architecture is common to almost all computers running today, from
the smallest industrial controller to the largest supercomputer. What sets the larger
computers, such as the IBM ASCII Blue (a supercomputer capable of 1015 floating point
operations per second), apart from the typical PC is that many larger computers are built
from a large number of processor and memory modules that communicate and work
cooperatively on a problem. The basic architecture is the same.
Stored program computers have four major components: the CPU (Central Processing Unit),
the memory, I/O devices, and one or more bus structures to allow the other three components
to communicate. The figure below illustrates a typical architecture.

Figure: Top-Level Structure of a Computer


The functions of the three top-level components of a computer seem to be obvious. The I/O
devices allow for communication of data to other devices and the users. The memory stores
both program data and executable code in the form of binary machine language. The CPU
comprises components that execute the machine language of the computer. Within the CPU,
it is the function of the control unit to interpret the machine language and cause the CPU to
execute the instructions as written. The Arithmetic Logic Unit (ALU) is that component of
the CPU that does the arithmetic operations and the logical comparisons that are necessary
for program execution. The ALU uses a number of local storage units, called registers, to
hold results of its operations. The set of registers is sometimes called the register file.

Page 103 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Fetch-Execute Cycle
As we shall see, the fetch-execute cycle forms the basis for operation of a stored-program
computer. The CPU fetches each instruction from the memory unit, then executes that
instruction, and fetches the next instruction. An exception to the “fetch next instruction” rule
comes when the equivalent of a Jump or Go To instruction is executed, in which case the
instruction at the indicated address is fetched and executed.
Registers vs. Memory
Registers and memory are similar in that both store data. The difference between the two is
somewhat an artifact of the history of computation, which has become solidified in all
current architectures. The basic difference between devices used as registers and devices
used for memory storage is that registers are faster and more expensive.
In modern computers, the CPU is usually implemented on a single chip. Within this context,
the difference between registers and memory is that the registers are on the CPU chip while
most memory is on a different chip. As a result of this, the registers are not addressed in the
same way as memory – memory is accessed through an address in the MAR (more on this
later), while registers are directly addressed. Admittedly the introduction of cache memory
has somewhat blurred the difference between registers and memory – but the addressing
mechanism remains the primary difference.
The CPU contains two types of registers, called special purpose registers and general
purpose registers. The general purpose registers contain data used in computations and can
be accessed directly by the computer program. The special purpose registers are used by the
control unit to hold temporary results, access memory, and sequence the program execution.
Normally, with one now-obsolete exception, these registers cannot be accessed by the
program.
The program status register (PSR), also called “program status word (PSW)”, is one of
the special purpose registers found on most computers. The PSR contains a number of bits to
reflect the state of the CPU as well as the result of the most recent computation. Some of the
common bits are
C the carry-out from the last arithmetic computation
V Set to 1 if the last arithmetic operation resulted in an overflow
N Set to 1 if the last arithmetic operation resulted in a negative number
Z Set to 1 if the last arithmetic operation resulted in a zero
I Interrupts enabled (Interrupts are discussed later)
The CPU (Central Processing Unit)
The CPU is that part of the computer that “does the work”. It fetches and executes the
machine language that represents the program under execution. It responds to the interrupts
(defined later) that usually signal Input/Output events, but which can signal issues with the
memory as well as exceptions in the program execution. As indicated above, the CPU has
three major components:
1) the ALU
2) the Control Unit
3) the register set
a) the general purpose register file
b) a number of special purpose registers used by the control unit.

Page 104 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The ALU (Arithmetic–Logic Unit)


This unit is the part of the CPU that carries out the arithmetic and logical operations of the
CPU, hence its name. The ALU acts in response to control signals issued by the Control
Unit. Quite often there is an attached floating–point unit that handles all real–number
arithmetic, so it is not completely accurate to say that the ALU handles all arithmetic.
The Control Unit
This unit interprets the machine language representing the computer program under
execution and issues the control signals that are necessary to achieve the effect that should be
associated with the program. This is often the most complex part of the CPU.
Structure of a Typical Bus
A typical computer contains a number of bus structures. We have already mentioned the
system bus and a bus internal to the CPU. Some computer designs include high-speed point-
to-point busses, used for such tasks as communication to the graphics card. In this section,
we consider the structure of the system bus. The system bus is a multi-point bus that allows
communication between a number of devices that are attached to the bus. There are two
classes of devices that can be connected to the bus.
Master Device a device that can initiate action on the bus.
The CPU is always a bus master.

Slave Device a device that responds to requests by a bus master.


Memory is an excellent example of a slave device.
Devices connected to a bus are often accessed by address. System memory is a primary
example of an addressable device; in a byte-addressable machine (more later on this),
memory can be considered as an array of bytes, accessed in the same way as an array as seen
in a typical programming language. I/O devices are often accessed by address; it is up to the
operating system to know the address used to access each such device.
Memory Organization and Addressing
We now give an overview of RAM – Random Access Memory. This is the memory called
“primary memory” or “core memory”. The term “core” is a reference to an earlier memory
technology in which magnetic cores were used for the computer’s memory. This discussion
will pull material from a number of chapters in the textbook.
Primary computer memory is best considered as an array of addressable units. Such a unit is
the smallest unit of memory that can have an independent address. In a byte–addressable
memory unit, each byte (8 bits) has an independent address, although the computer often
groups the bytes into larger units (words, long words, etc.) and retrieves that group. Most
modern computers manipulate integers as 32–bit (4–byte) entities, but 64–bit integers are
becoming common. Many modern designs retrieve multiple bytes at a time.

Page 105 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

In this author’s opinion, byte addressing in computers became important as the result of the
use of 8-bit character codes. Many applications involve the movement of large numbers of
characters (coded as ASCII or EBCDIC) and thus profit from the ability to address single
characters. Some computers, such as the CDC-6400, CDC-7600, and all Cray models, use
word addressing. This is a result of a design decision made when considering the main goal
of such computers – large computations involving floating point numbers. The word size in
these computers is 60 bits (why not 64? – I don’t know), yielding good precision for numeric
simulations such as fluid flow and weather prediction.

Memory as a Linear Array


Consider a byte-addressable memory with N bytes of memory. As stated above, such a
memory can be considered to be the logical equivalent of a C++ array, declared as
byte memory [N] ; // Address ranges from 0 through (N – 1)
The computer on which these notes were written has 384 MB of main memory, now only an
average size but once unimaginably large. 384 MB = 384220 bytes and the memory is byte-
addressable, so N = 3841048576 = 402,653,184. Quite often the memory size will either be
a power of two or the sum of two powers of two; 384 MB = (256 + 128)220 = 228 + 227.
Early versions of the IBM S/360 provided addressability of up to 224 = 16,777,216 bytes of
memory, or 4,194,304 32–bit words. All addresses in the S/360 series are byte addresses.
The term “random access” used when discussing computer memory implies that memory
can be accessed at random with no performance penalty. While this may not be exactly true
in these days of virtual memory, the key idea is simple – that the time to access an item in
memory does not depend on the address given. In this regard, it is similar to an array in
which the time to access an entry does not depend on the index. A magnetic tape is a typical
sequential access device – in order to get to an entry one must read over all pervious entries.
There are two major types of random-access computer memory. These are:
RAM Read-Write Memory
ROM Read-Only Memory
The usage of the term “RAM” for the type of random access memory that might well be
called “RWM” has a long history and will be continued in this course. The basic reason is
probably that the terms “RAM” and “ROM” can easily be pronounced; try pronouncing
“RWM”. Keep in mind that both RAM and ROM are random access memory.
Of course, there is no such thing as a pure Read–Only memory; at some time it must be
possible to put data in the memory by writing to it, otherwise there will be no data in the
memory to be read. The term “Read-Only” usually refers to the method for access by the
CPU. All variants of ROM share the feature that their contents cannot be changed by normal
CPU write operations. All variants of RAM (really Read-Write Memory) share the feature
that their contents can be changed by normal CPU write operations. Some forms of ROM
have their contents set at time of manufacture, other types called PROM (Programmable
ROM), can have contents changed by special devices called PROM Programmers.

Page 106 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The Idea of Address Space


We now must distinguish between the idea of address space and physical memory. The
address space defines the range of addresses (indices into the memory array) that can be
generated. The size of the physical memory is usually somewhat smaller, this may be by
design (see the discussion of memory-mapped I/O below) or just by accident.
The memory address is specified by a binary number placed in the Memory Address Register
(MAR). The number of bits in the MAR determines the range of addresses that can be
generated. N address lines can be used to specify 2N distinct addresses, numbered 0 through
2N – 1. This is called the address space of the computer. The early IBM S/360 had a 24–bit
MAR, corresponding to an address space of 0 through 224 – 1, or 0 through 4,194,303.
For example, we show some MAR sizes.
Computer MAR bits Address Range The PDP-11/20 was an elegant small
0 to 65,535
machine made by the now defunct
PDP-11/20 16
Digital Equipment Corporation. As
Intel 8086 20 0 to 1,048,575 soon as it was built, people realized
0 to 4,194,303 that its address range was too small.
IBM 360 24
S/370–XA 31 0 to 2,147,483,647
Pentium 32 0 to 4,294,967,295
In general, the address space is much
z/Series 64 A very big number.
larger than the physical memory
available. For example, my personal
computer has an address space of 232 (as do all Pentiums), but only 384MB = 228 + 227 bytes.
Until recently the 32–bit address space would have been much larger than any possible
amount of physical memory. At present one can go to a number of companies and order a
computer with a fully populated address space; i.e., 4 GB of physical memory. Most high-
end personal computers are shipped with 1GB of memory.
Word Addresses in a Byte-Addressable Machine
Most computers today, including all of those in the IBM S/360 series, have memories that
are byte-addressable; thus each byte in the memory has a unique address that can be used to
address it. Under this addressing scheme, a word corresponds to a number of addresses.
A 16-bit word at address Z contains bytes at addresses Z and Z + 1.
A 32-bit word at address Z contains bytes at addresses Z, Z + 1, Z + 2, and Z + 3.
In many computers with byte addressing, there are constraints on word addresses.
A 16-bit word must have an even address
A 32-bit word must have an address that is a multiple of 4.
This is true of the IBM S/360 series in which 16–bit words are called “halfwords”,
32–bit words are called “words”, and 64–bit words are called “double words”. A halfword
must have an even address, a word must have an address that is a multiple of 4 and a double
word (64 bits) an address that is a multiple of 8.
Even in computers that do not enforce this requirement, it is a good idea to observe these
word boundaries. Most compilers will do so automatically.

Page 107 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Suppose a byte-addressable computer with a 24–bit address space. The highest byte address
is 224 – 1. From this fact and the address allocation to multi-byte words, we conclude
the highest address for a 16-bit word is (224 – 2), and
the highest address for a 32-bit word is (224 – 4), because the 32–bit word addressed at
(224 – 4) comprises bytes at addresses (224 – 4), (224 – 3), (224 – 2), and (224 – 1).
Byte Addressing vs. Word Addressing
We have noted above that N address lines can be used to specify 2N distinct addresses,
numbered 0 through 2N – 1. We now ask about the size of the addressable items. As a
simple example, consider a computer with a 24–bit address space. The machine would have
16,777,216 (16M) addressable entities. In a byte–addressable machine, such as the
IBM S/360, this would correspond to:
16 M Bytes 16,777,216 bytes, or
8 M halfwords 8,388,608 16-bit halfwords, or
4 M words 4,194,304 32–bit fullwords.
The advantages of byte-addressability are clear when we consider applications that process
data one byte at a time. Access of a single byte in a byte-addressable system requires only
the issuing of a single address. In a 16–bit word addressable system, it is necessary first to
compute the address of the word containing the byte, fetch that word, and then extract the
byte from the two–byte word. Although the processes for byte extraction are well
understood, they are less efficient than directly accessing the byte. For this reason, many
modern machines are byte addressable.
Big–Endian and Little–Endian
The reference here is to a story in Gulliver’s Travels written by Jonathan Swift in which two
groups went to war over which end of a boiled egg should be broken – the big end or the
little end. The student should be aware that Swift did not write pretty stories for children but
focused on biting satire; his work A Modest Proposal is an excellent example.
Consider the 32-bit number represented by the eight–digit hexadecimal number 0x01020304,
stored at location Z in memory. In all byte–addressable memory locations, this number will
be stored in the four consecutive addresses Z, (Z + 1), (Z + 2), and (Z + 3). The difference
between big-endian and little-endian addresses is where each of the four bytes is stored.
In our example 0x01 represents bits 31 – 24,
0x02 represents bits 23 – 16,
0x03 represents bits 15 – 8, and
0x04 represents bits 7 – 0.
As a 32-bit signed integer, the number represents 01(256)3 + 02(256)2 + 03(256) + 04
or 0167 + 1166 + 0165 + 2164 + 0163 + 3162 + 0161 + 4160, which evaluates to
116777216 + 265536 + 3256 + 41 = 16777216 + 131072 + 768 + 4 = 16909060. Note
that the number can be viewed as having a “big end” and a “little end”, as in the next figure.

Page 108 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The “big end” contains the most significant digits of the number and the “little end” contains
the least significant digits of the number. We now consider how these bytes are stored in a
byte-addressable memory. Recall that each byte, comprising two hexadecimal digits, has a
unique address in a byte-addressable memory, and that a 32-bit (four-byte) entry at address Z
occupies the bytes at addresses Z, (Z + 1), (Z + 2), and (Z + 3). The hexadecimal values
stored in these four byte addresses are shown below.
Address Big-Endian Little-Endian
Z 01 04
Z+1 02 03
Z+2 03 02
Z+3 04 01
The figure below shows a graphical way to view these two options for ordering the bytes
copied from a register into memory. We suppose a 32-bit register with bits numbered from
31 through 0. Which end is placed first in the memory – at address Z? For big-endian, the
“big end” or most significant byte is first written. For little-endian, the “little end” or least
significant byte is written first.

Just to be complete, consider the 16-bit number represented by the four hex digits 0A0B,
with decimal value 10256 + 11 = 2571. Suppose that the 16-bit word is at location W; i.e.,
its bytes are at locations W and (W + 1). The most significant byte is 0x0A and the least
significant byte is 0x0B. The values in the two addresses are shown below.
Address Big-Endian Little-Endian
W 0A 0B
W+1 0B 0A
Here we should note that the IBM S/360 is a “Big Endean” machine.
As an example of a typical problem, let’s examine the following memory map, with byte
addresses centered on address W. Note the contents are listed as hexadecimal numbers.
Each byte is an 8-bit entry, so that it can store unsigned numbers between 0 and 255,
inclusive. These are written in hexadecimal as 0x00 through 0xFF inclusive.

Address (W – 2) (W – 1) W (W + 1) (W + 2) (W + 3) (W + 4)
Contents 0B AD 12 AB 34 CD EF

Page 109 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

We first ask what 32-bit integers are stored at address W. Recalling that the value of the
number stored depends on whether the format is big-endian or little-endian, we draw the
memory map in a form that is more useful.

This figure should illustrate one obvious point: the entries (W – 2), (W – 1), and (W + 4) are
“red herrings”, data that have nothing to do with the problem at hand. We now consider the
conversion of the number in big-endian format. As a decimal number, this evaluates to
1167 + 2166 + A165 + B164 + 3163 + 4162 + C161 + D, or
1167 + 2166 + 10165 + 11164 + 3163 + 4162 + 12161 + 13, or
1268435456 + 216777216 + 101048576 + 1165536 + 34096 + 4256 + 1216 + 13, or
268435456 + 33554432 + 10485760 + 720896 + 12288 + 1024 + 192 + 13, or
313210061.
The evaluation of the number as a little–endian quantity is complicated by the fact that the
number is negative. In order to maintain continuity, we convert to binary (recalling that
A = 1010, B = 1011, C = 1100, and D = 1101) and take the two’s-complement.
Hexadecimal CD 34 AB 12
Binary 11001101 00110100 10101011 00010010
One’s Comp 00110010 11001011 01010100 11101101
Two’s Comp 00110010 11001011 01010100 11101110
Hexadecimal 32 AB 54 EE
Converting this to decimal, we have the following
3167 + 2166 + A165 + B164 + 5163 + 4162 + E161 + E, or
3167 + 2166 + 10165 + 11164 + 5163 + 4162 + 14161 + 14, or
3268435456 + 216777216 + 101048576 + 1165536 + 54096 + 4256 + 1416 + 14, or
805306368 + 33554432 + 10485760 + 720896 + 20480 + 1024 + 224 + 14, or
850089198
The number represented in little-endian form is – 850,089,198.
We now consider the next question: what 16-bit integer is stored at address W? We begin
our answer by producing the drawing for the 16-bit big-endian and little-endian numbers.

Page 110 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The evaluation of the number as a 16-bit big-endian number is again the simpler choice. The
decimal value is 1163 + 2162 + 1016 + 11 = 4096 + 512 + 160 + 11 = 4779.
The evaluation of the number as a little–endian quantity is complicated by the fact that the
number is negative. We again take the two’s-complement to convert this to positive.
Hexadecimal AB 12
Binary 10101011 00010010
One’s Comp 01010100 11101101
Two’s Comp 01010100 11101110
Hexadecimal 54 EE
The magnitude of this number is 5163 + 4162 + 1416 + 14 = 20480 + 1024 + 224 + 14, or
21742. The original number is thus the negative number – 21742.
One might ask similar questions about real numbers and strings of characters stored at
specific locations. For a string constant, the value depends on the format used to store strings
and might include such things as /0 termination for C and C++ strings. A typical question on
real number storage would be to consider the following:
A real number is stored in byte-addressable memory in little-endian form.
The real number is stored in IEEE-754 single-precision format.
Address W (W + 1) (W + 2) (W + 3)
Contents 00 00 E8 42

The trick here is to notice that the number written in its proper form, with the “big end” on
the left hand side is 0x42E80000, which we have seen represents the number 116.00. Were
the number stored in big-endian form, it would be a denormalized number, about 8.3210-41.
There seems to be no advantage of one system over the other. Big-endian seems more
natural to most people and facilitates reading hex dumps (listings of a sequence of memory
locations), although a good debugger will remove that burden from all but the unlucky.
Big-endian computers include the IBM 360 series, Motorola 68xxx, and SPARC by Sun.
Little-endian computers include the Intel Pentium and related computers.

Page 111 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The big-endian vs. little-endian debate is one that does not concern most of us directly. Let
the computer handle its bytes in any order desired as long as it produces good results. The
only direct impact on most of us will come when trying to port data from one computer to a
computer of another type. Transfer over computer networks is facilitated by the fact that the
network interfaces for computers will translate to and from the network standard, which is
big-endian. The major difficulty will come when trying to read different file types.
The big-endian vs. little-endian debate shows in file structures when computer data are
“serialized” – that is written out a byte at a time. This causes different byte orders for the
same data in the same way as the ordering stored in memory. The orientation of the file
structure often depends on the machine upon which the software was first developed.
Any student who is interested in the literary antecedents of the terms “big-endian” and “little-
endian” should read the quotation at the end of this chapter.
The Control Unit
“Time is nature’s way of keeping everything from happening at once”
Woody Allen
We now turn our attention to a discussion of the control unit, which is that part of the Central
Processing Unit that causes the machine language to take effect. It does this by reacting to
the machine language instruction in the Instruction Register, the status flags in the Program
Status Register, and the interrupts in order to produce control signals that direct the
functioning of the computer.
The main strategy for the control unit is to break the execution of a machine language
instruction into a number of discrete steps, and then cause these primitive steps to be
executed sequentially in the order appropriate to achieve the affect of the instruction.
The System Clock
The main tool for generating a sequence of basic execution steps is the system clock, which
generates a periodic signal used to generate time steps. In some designs the execution of an
instruction is broken into major phases (e.g., Fetch and Execute), each of which is broken
into a fixed number of minor phases that corresponds to a time signal. In other systems, the
idea of major and minor phases is not much used. This figure shows a typical representation
of a system clock; the CPU “speed” is just the number of clock cycles per second.

The student should not be mislead into believing that the above is an actual representation of
the physical clock signal. A true electrical signal can never rise instantaneously or fall
instantaneously. This is a logical representation of the clock signal, showing that it changes
periodically between logic 0 and logic 1. Although the time at logic 1 is commonly the same
as the time at logic 0, this is not a requirement.

Page 112 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Two Types of Control Units


The function of the control unit is to emit control signals. We now ask how the control unit
works. A detailed study of the control unit should be the topic for another course, but we
may make a few general remarks at this time.

The two major classes of control unit are hardwired and microprogrammed. In a
hardwired control unit, the control signals are the output of combinational logic (AND, OR,
NOT gates, etc.) that has the above as input. The system clock drives a binary counter that
breaks the execution cycle into a number of states. As an example, there will be a fetch state,
during which control signals are emitted to fetch the instruction and an execute state during
which control signals are emitted to execute the instruction just fetched.
In a microprogrammed control unit, the control signals are the output of a register called the
micro-memory buffer register. The control program (or microcode) is just a collection of
words in the micro-memory or CROM (Control Read-Only Memory). The control unit is
sequenced by loading a micro-address into the –MAR, which causes the corresponding
control word to be placed into the –MBR and the control signals to be emitted.

In many ways, the control program appears to be written in a very primitive machine
language, corresponding to a very primitive assembly language. As an example, we show a
small part of the common fetch microcode from a paper design called the Boz–5. Note that
the memory is accessed by address and that each micro–word contains a binary number, here
represented as a hexadecimal number. This just a program that can be changed at will,
though not by the standard CPU write–to–memory instructions.

Page 113 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Address Contents
0x20 0x0010 2108 2121
0x21 0x0011 1500 2222
0x22 0x0006 4200 2323
0x23 0x0100 0000 0000
Microprogrammed control units are more flexible than hardwired control units because they
can be changed by inserting a new binary control program. As noted in a previous chapter,
this flexibility was quickly recognized by the developers of the System/360 as a significant
marketing advantage. By extending the System/360 micromemory (not a significant cost)
and adding additional control code, the computer could either be run in native mode as a
System/360, or in emulation mode as either an IBM 1401 or an IBM 7094. This ability to
run the IBM 1401 and IBM 7094 executable modules with no modification simplified the
process of upgrading computers and made the System/360 a very popular choice.
It is generally agreed that the microprogrammed units are slower than hardwired units,
although some writers dispute this. The disagreement lies not in the relative timings of the
two control units, but on a critical path timing analysis of a complete CPU. It may be that
some other part of the Fetch/Execute cycle is dominating the delays in running the program.

Interrupts and Interrupt Handling


The standard idea of a stored program computer is that it fetches machine language
instructions sequentially from memory and executes each in order until the program has
terminated. Such a simplistic strategy will not suffice for modern computation.
Consider the case of I/O processing. Let us focus on the arrival of an Ethernet frame at the
Network Interface Card (NIC). The data in the frame must be stored in primary computer
memory for later processing before being overwritten. In order to do this, the program under
execution must be suspended temporarily while the program controlling the NIC starts the
data transfer. The primary mechanism for suspending one program in order to execute
another program is called an interrupt.
The primary rule for processing interrupts is that the execution of the interrupted program
must not be disrupted; only delayed. There is a strategy for handling interrupts that works
for all I/O interrupts. This is a modification of the basic instruction fetch cycle. Here it is:
1) At the beginning of each instruction fetch state, the status of the interrupt line
is tested. In general, this is an active–low signal.
2) If the interrupt signal has been asserted, the CPU saves the current state of the CPU,
which is that set of information required to restart the program as if it had not been
suspended. The CPU then fetches the first instruction of the interrupt handler routine.
3) The interrupt handler identifies the source of the interrupt and calls the handler
associated with the device that raised the interrupt.
4) When the interrupt handler has finished its job, it terminates and the CPU resumes
the execution of the suspended program. Since the complete state of the suspended
program has been saved, it resumes execution as it nothing had happened.

Page 114 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Virtual Memory and Interrupt Handling


There is one situation under which the above–mentioned interrupt strategy is not adequate.
This occurs in a virtual memory scenario, in which a program can issue addresses that do not
correspond to physical memory. Here are the rules:
1) the program issues logical addresses,
2) the address is converted to a physical address by the operating system,
3) if the physical address is not in physical memory, a page fault is raised. This is an
interrupt that can occur after the instruction fetch phase has completed.
Consider the execution of a memory–to–memory transfer instruction, such as an assembly
language instruction that might correspond to the high–level language statement Y = X.
The microprogram to implement this instruction might appear as follows.
1. Fetch and decode the instruction.
2. Compute the address for the label X and fetch the value stored at that address.
Store that value in a temporary CPU register.
3. Compute the address for the label Y and store the value from the temporary
CPU register into that address.
The IBM S/360 and S/370 architecture contains a number of assembly language instructions
of precisely this format. The following two instructions are rather commonly used.
MVC (Move Characters) Moves a string of characters from one
memory location to another.
ZAP (Zero and Add Packed) Moves a sequence of packed decimal digits
from one memory location to another.
In each scenario, the problem is the same. Here is an analysis of the above sequence.
1. The instruction is fetched. If the instruction is located in a page that is not resident
in primary memory, raise a page fault interrupt. This program is suspended until
the page with the instruction is loaded into memory. This is not a problem.
2. The argument X is fetched. If the address of X is not resident in primary memory,
raise a page fault interrupt. The program is suspended until the page with the needed
data is loaded into memory. The instruction is restarted at step 1. Since the page
containing the instruction is also memory resident, this is not a problem.
3. The address of Y is computed. If that address is not in primary memory, there is
a problem. The instruction has already partially executed. What to do with the
partial results? In this case, the answer is quite easy, because the instruction has
had no side effects other than changing the value of a temporary register: raise a
page fault interrupt, wait for the page to be loaded, and restart the instruction.
The handling of such interrupts that can occur after the instruction has had other side effects,
such as storing a partial result into memory, can become quite complex.
As an aside, the IBM S/360 did not support virtual memory, which was introduced with the
S/370 in 1970.

Page 115 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Input/Output Processing
We now consider realistic modes of transferring data into and out of a computer. We first
discuss the limitations of program controlled I/O and then explain other methods for I/O.
As the simplest method of I/O, program controlled I/O has a number of shortcomings that
should be expected. These shortcomings can be loosely grouped into two major issues.
1) The imbalance in the speeds of input and processor speeds.
Consider keyboard input. An excellent typist can type about 100 words a minute (the author
of these notes was tested at 30 wpm – wow!), and the world record speeds are 180 wpm (for
1 minute) in 1918 by Margaret Owen and 140 wpm (for 1 hour with an electric typewriter) in
1946 by Stella Pajunas. Consider a typist who can type 120 words per minute – 2 words a
second. In the world of typing, a word is defined to be 5 characters, thus our excellent typist
is producing 10 characters per second or 1 character every 100,000 microseconds. This is a
waste of time; the computer could execute almost a million instructions if not waiting.
2) The fact that all I/O is initiated by the CPU.
The other way to state this is that the I/O unit cannot initiate the I/O. This design does not
allow for alarms or error interrupts. Consider a fire alarm. It would be possible for someone
at the fire department to call once a minute and ask if there is a fire in your building; it is
much more efficient for the building to have an alarm system that can be used to notify the
fire department. Another good example is a patient monitor that alarms if either the
breathing or heart rhythm become irregular. While such a monitor should be polled by the
computer on a frequent basis, it should be able to raise an alarm at any time.
As a result of the imbalance in the timings of the purely electronic CPU and the electro-
mechanical I/O devices, a number of I/O strategies have evolved. We shall discuss these in
this chapter. All modern methods move away from the designs that cause the CPU to be the
only component to initiate I/O.
The first idea in getting out of the problems imposed by having the CPU as the sole initiator
of I/O is to have the I/O device able to signal when it is ready for an I/O transaction.
Specifically, we have two possibilities.
1) The input device has data ready for reading by the CPU. If this is the case, the CPU
can issue an input instruction, which will be executed without delay.
2) The output device can take data from the CPU, either because it can output the data
immediately or because it can place the data in a buffer for output later. In this case,
the CPU can issue an output instruction, which will be executed without delay.
The idea of involving the CPU in an I/O operation only when the operation can be executed
immediately is the basis of what is called interrupt-driven I/O. In such cases, the CPU
manages the I/O but does not waste time waiting on busy I/O devices. There is another
strategy in which the CPU turns over management of the I/O process to the I/O device itself.
In this strategy, called direct memory access or DMA, the CPU is interrupted only at the
start and termination of the I/O. When the I/O device issues an interrupt indicating that I/O
may proceed, the CPU issues instructions enabling the I/O device to manage the transfer and
interrupt the CPU upon normal termination of I/O or the occurrence of errors.

Page 116 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

An Extended (Silly) Example of I/O Strategies


There are four major strategies that can be applied to management of the I/O process:
Program-Controlled, and
Interrupt-Driven, and
Direct Memory Access, and
I/O Channel.
We try to clarify the difference between these strategies by the example of having a party in
one’s house to which guests are invited. The issue here is balancing work done in the house
to prepare it for the party with the tasks of waiting at the front door to admit the guests.
Program-Controlled
The analogy for program-controlled I/O would be for the host to remain at the door,
constantly looking out, and admitting guests as each one arrives. The host would be at the
door constantly until the proper number of guests arrived, at which time he or she could
continue preparations for the party. While standing at the door, the host could do no other
productive work. Most of us would consider that a waste of time.
Interrupt-Driven
Many of us have solved this problem by use of an interrupt mechanism called a doorbell.
When the doorbell rings, the host suspends the current task and answers the door. Having
admitted the guest, the host can then return to preparations for the party. Note that this
example contains, by implication, several issues associated with interrupt handling.
The first issue is priority. If the host is in the process of putting out a fire in the kitchen, he
or she may not answer the door until the fire is suppressed. A related issue is necessary
completion. If the host has just taken a cake out of the oven, he or she will not drop the cake
on the floor to answer the door, but will first put the cake down on a safe place and then
proceed to the door. In this scenario, the host’s time is spent more efficiently as he or she
spends little time actually attending the door and can spend most of the time in productive
work on the party.
Direct Memory Access
In this case, the host unlocks the door and places a note on it indicating that the guests should
just open the door and come in. The host places a number of tickets at the door, one for each
guest expected, with a note that the guest taking the last ticket should so inform the host.
When the guest taking the last ticket has arrived, the host is notified and locks the door. In
this example the host’s work is minimized by removing the requirement to go to the door for
each arrival of a guest. There are only two trips to the door, one at the beginning to set up for
the arrival of guests and one at the end to close the door.
I/O Channel
The host hires a butler to attend the door and lets the butler decide the best way to do it. The
butler is expected to announce when all the guests have arrived.
Note that the I/O channel is not really a distinct strategy. Within the context of our silly
example, we note that the butler will use one of the above three strategies to admit guests.
The point of the strategy in this context is that the host is relieved of the duties. In the real
world of computer I/O, the central processor is relieved of most I/O management duties.

Page 117 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Implementation of I/O Strategies


We begin our brief discussion of physical I/O by noting that it is based on interaction of a
CPU and a set of registers associated with the I/O device. In general, each I/O device has
three types of registers associated with it: data, control, and status. From the view of a
programmer, the I/O device can be almost completely characterized by these registers,
without regard to the actual source or destination of the data.
For this section, we shall imagine a hopelessly simplistic computer with a single CPU
register, called the ACC (accumulator) and four instructions. These instructions are:
1. LOAD Address Loads the accumulator from the memory address,
2. STORE Address Stores the accumulator contents into the memory address,
3. GET Register Loads the accumulator from the I/O register, and
4. PUT Register Stores the accumulator contents into the I/O register.
The best way to understand IBM’s rationale for its I/O architecture to consider some simpler
designs that might have been chosen. We begin with a very primitive I/O scheme.
The First Idea, and Why It Cannot Work
At first consideration, I/O in a computer system would appear trivial. We just issue the
instructions and access the data register by address, so that we have:
GET TEXT_IN_DATA -- this reads from the input unit.
PUT TEXT_OUT_DATA -- this writes to the output unit.
Strictly speaking, these instructions operate as advertised in the code fragments above. We
now expose the difficulties, beginning with the input problem. The input unit is connected to
the CPU through the register at address TEXT_IN_DATA. Loading a CPU from that input
register will always transfer some data, but might not transfer what we want. Normally, we
expect an input request to wait until a character has been input by the user and only then
transfer the character to the CPU. As written above, the instruction just copies what is in the
data buffer of the input unit; it might be user data or it might be garbage left over from
initialization. We must find a way to command the unit to read, wait for a new character to
have been input, and only then transfer the data to the CPU.
The output instruction listed above might as well be stated as “Just throw it over the wall and
hope someone catches it.” We are sending data to the output unit without first testing to see
if the output unit is ready for data. Early in his career as a programmer, this author wrote a
program that sent characters to a teletype printer faster than they could be printed; the result
was that each character printed was a combination of two or more characters actually sent to
the TTY, and none were actually correct. As this was the intended result of this experiment,
this author was pleased and determined that he had learned something.
The solution to the problem of actually being able to do input and output correctly is based
on the proper use of these two instructions. The solution we shall describe is called program
controlled I/O. We shall first describe the method and then note its shortcomings.

Page 118 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The basic idea for program–controlled I/O is that the CPU initiates all input and output
operations. The CPU must test the status of each device before attempting to use it and issue
an I/O command only when the device is ready to accept the command. The CPU then
commands the device and continually checks the device status until it detects that the device
is ready for an I/O event. For input, this happens when the device has new data in its data
buffer. For output, this happens when the device is ready to accept new data.
Pure program–controlled I/O is feasible only when working with devices that are always
instantly ready to transfer data. For example, we might use program–controlled input to read
an electronic gauge. Every time we read the gauge, the CPU will get a value. While this
solution is not without problems, it does avoid the busy wait problem.
The “busy wait” problem occurs when the CPU executes a tight loop doing nothing except
waiting for the I/O device to complete its transaction. Consider the example of a fast typist
inputting data at the rate of one character per 100,000 microseconds. The busy wait loop will
execute about one million times per character input, just wasting time. The shortcomings of
such a method are obvious (IBM had observed them in the late 1940’s).
As a result of the imbalance in the timings of the purely electronic CPU and the electro–
mechanical I/O devices, a number of I/O strategies have evolved. We shall discuss these in
this chapter. All modern methods move away from the designs that cause the CPU to be the
only component to initiate I/O.
The idea of involving the CPU in an I/O operation only when the operation can be executed
immediately is the basis of what is called interrupt-driven I/O. In such cases, the CPU
manages the I/O but does not waste time waiting on busy I/O devices. There is another
strategy in which the CPU turns over management of the I/O process to the I/O device itself.
In this strategy, called direct memory access or DMA, the CPU is interrupted only at the
start and termination of the I/O. When the I/O device issues an interrupt indicating that I/O
may proceed, the CPU issues instructions enabling the I/O device to manage the transfer and
interrupt the CPU upon normal termination of I/O or the occurrence of errors.
Interrupt Driven I/O
Here the CPU suspends the program that requests the Input and activates another process.
While this other process is being executed, the input device raises 80 interrupts, one for each
of the characters input. When the interrupt is raised, the device handler is activated for the
very short time that it takes to copy the character into a buffer, and then the other process is
activated again. When the input is complete, the original user process is resumed.
In a time–shared system, such as all of the S/370 and successors, the idea of an interrupt
allows the CPU to continue with productive work while a program is waiting for data. Here
is a rough scenario for the sequence of events following an I/O request by a user job.
1. The operating system commands the operation on the selected I/O device.
2. The operating system suspends execution of the job, places it on a wait queue,
and assigns the CPU to another job that is ready to run.
3. Upon completion of the I/O, the device raises an interrupt. The operating system
handles the interrupt and places the original job in a queue, marked as ready to run.
4. At some time later, the job will be run.

Page 119 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

In order to consider the next refinement of the I/O structure, let us consider what we have
discussed previously. Suppose that a line of 80 typed characters is to be input.
Interrupt Driven
Here the CPU suspends the program that requests the Input and activates another process.
While this other process is being executed, the input device raises 80 interrupts, one for each
of the characters input. When the interrupt is raised, the device handler is activated for the
very short time that it takes to copy the character into a buffer, and then the other process is
activated again. When the input is complete, the original user process is resumed.
Direct Memory Access
DMA is a refinement of interrupt-driven I/O in that it uses interrupts at the beginning and
end of the I/O, but not during the transfer of data. The implication here is that the actual
transfer of data is not handled by the CPU (which would do that by processing interrupts),
but by the I/O controller itself. This removes a considerable burden from the CPU.
In the DMA scenario, the CPU suspends the program that requests the input and again
activates another process that is eligible to execute. When the I/O device raises an interrupt
indicating that it is ready to start I/O, the other process is suspended and an I/O process
begins. The purpose of this I/O process is to initiate the device I/O, after which the other
process is resumed. There is no interrupt again until the I/O is finished.
The design of a DMA controller then involves the development of mechanisms by which the
controller can communicate directly with the computer’s primary memory. The controller
must be able to assert a memory address, specify a memory READ or memory WRITE, and
access the primary data register, called the MBR (Memory Buffer Register).
Immediately, we see the need for a bus arbitration strategy – suppose that both the CPU
and a DMA controller want to access the memory at the same time. The solution to this
problem is called “cycle stealing”, in which the CPU is blocked for a cycle from accessing
the memory in order to give preference to the DMA device.
Any DMA controller must contain at least four registers used to interface to the system bus.
1) A word count register (WCR) – indicating how many words to transfer.
2) An address register (AR) – indicating the memory address to be used.
3) A data buffer.
4) A status register, to allow the device status to be tested by the CPU.
In essence, the CPU tells the DMA controller “Since you have interrupted me, I assume that
you are ready to transfer data. Transfer this amount of data to or from the memory block
beginning at this memory address and let me know when you are done or have a problem.”

Page 120 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

I/O Channel
A channel is a separate special-purpose computer that serves as a sophisticated Direct
Memory Access device controller. It directs data between a number of I/O devices and the
main memory of the computer. Generally, the difference is that a DMA controller will
handle only one device, while an I/O channel will handle a number of devices.
The I/O channel concept was developed by IBM (the International Business Machine
Corporation) in the 1940’s because it was obvious even then that data Input/Output might be
a real limit on computer performance if the I/O controller were poorly designed. By the IBM
naming convention, I/O channels execute channel commands, as opposed to instructions.
There are two types of channels – multiplexer and selector.
A multiplexer channel supports more than one I/O device by interleaving the transfer of
blocks of data. A byte multiplexer channel will be used to handle a number of low-speed
devices, such as printers and terminals. A block multiplexer channel is used to support
higher-speed devices, such as tape drives and disks.
A selector channel is designed to handle high speed devices, one at a time. This type of
channel became largely disused prior to 1980, probably replaced by blocked multiplexers.
Each I/O channel is attached to one or more I/O devices through device controllers that are
similar to those used for Interrupt-Driven I/O and DMA, as discussed above.

I/O Channels, Control Units, and I/O Devices

Page 121 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

In one sense, an I/O channel is not really a distinct I/O strategy, due to the fact that an I/O
channel is a special purpose processor that uses either Interrupt-Driven I/O or DMA to affect
its I/O done on behalf of the central processor. This view is unnecessarily academic.
In the IBM System-370 architecture, the CPU initiates I/O by executing a specific instruction
in the CPU instruction set: EXCP for Execute Channel Program. Channel programs are
essentially one word programs that can be “chained” to form multi-command sequences.

Physical IOCS
The low level programming of I/O channels, called PIOCS for Physical I/O Control System,
provides for channel scheduling, error recovery, and interrupt handling. At this level, the one
writes a channel program (one or more channel command words) and synchronizes the main
program with the completion of I/O operations. For example, consider double-buffered I/O,
in which a data buffer is filled and then processed while another data buffer is being filled. It
is very important to verify that the buffer has been filled prior to processing the data in it.
In the IBM PIOCS there are four major macros used to write the code.
CCW Channel Command Word
The CCW macro causes the IBM assembler to construct an 8-byte channel command word.
The CCW includes the I/O command code (1 for read, 2 for write, and other values), the start
address in main memory for the I/O transfer, a number of flag bits, and a count field.
EXCP Execute Channel Program
This macro causes the physical I/O system to start an I/O operation. This macro takes as its
single argument the address of a block of channel commands to be executed.
WAIT
This synchronizes main program execution with the completion of an I/O operation. This
macro takes as its single argument the address of the block of channel commands for which it
will wait.
Chaining
The PIOCS provides a number of interesting chaining options, including command chaining.
By default, a channel program comprises only one channel command word. To execute more
than one channel command word before terminating the I/O operation, it is necessary to
chain each command word to the next one in the sequence; only the last command word in
the block does not contain a chain bit.
Here is a sample of I/O code.
The main I/O code is as follows. Note that the program waits for I/O completion.
// First execute the channel program at address INDEVICE.
EXCP INDEVICE
// Then wait to synchronize program execution with the I/O
WAIT INDEVICE
// Fill three arrays in sequence, each with 100 bytes.
INDEVICE CCW 2, ARRAY_A, X’40’, 100
CCW 2, ARRAY_B, X’40’, 100
CCW 2, ARRAY_C, X’00’, 100

Page 122 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

The first number in the CCW (channel command word) is the command code indicating the
operation to be performed; e.g., 1 for write and 2 for read. The hexadecimal 40 in the CCW
is the “chain command flag” indicating that the commands should be chained. Note that the
last command in the list has a chain command flag set to 0, indicating that it is the last one.
Front End Processor
We can push the I/O design strategy one step further – let another computer handle it. One
example that used to be common occurred when the IBM 7090 was introduced. At the time,
the IBM 1400 series computer was quite popular. The IBM 7090 was designed to facilitate
scientific computations and was very good at that, but it was not very good at I/O processing.
As the IBM 1400 series excelled at I/O processing it was often used as an I/O front-end
processor, allowing the IBM 7090 to handle I/O only via tape drives.
The batch scenario worked as follows:
1) Jobs to be executed were “batched” via the IBM 1401 onto magnetic tape. This
scenario did not support time sharing.
2) The IBM 7090 read the tapes, processed the jobs, and wrote results to tape.
3) The IBM 1401 read the tape and output the results as indicated. This output
included program listings and any data output required.
Another system that was in use was a combined CDC 6400/CDC 7600 system (with
computers made by Control Data Corporation), in which the CDC 6400 operated as an I/O
front-end and wrote to disk files for processing by the CDC 7600. This combination was in
addition to the fact that each of the CDC 6400 and CDC 7600 had a number of IOPS (I/O
Processors) that were essentially I/O channels as defined by IBM.

Page 123 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Computer Architecute & Organization

Gulliver’s Travels and “Big-Endian” vs. “Little-Endian”


The author of these notes has been told repeatedly of the literary antecedents of the terms
“big-endian” and “little-endian” as applied to byte ordering in computers. In a fit of
scholarship, he decided to find the original quote. Here it is, taken from Chapter IV of Part I
(A Voyage to Lilliput) of Gulliver’s Travels by Jonathan Swift, published October 28, 1726.
The edition consulted for these notes was published in 1958 by Random House, Inc. as a part
of its “Modern Library Books” collection. The LC Catalog Number is 58-6364.
The story of “big-endian” vs. “little-endian” is described in the form on a conversation
between Gulliver and a Lilliputian named Reldresal, the Principal Secretary of Private
Affairs to the Emperor of Lilliput. Reldresal is presenting a history of a number of struggles
in Lilliput, when he moves from one difficulty to another. The following quote preserves the
unusual capitalization and punctuation found in the source material.
“Now, in the midst of these intestine Disquiets, we are threatened with an
Invasion from the Island of Blefuscu, which is the other great Empire of the
Universe, almost as large and powerful as this of his majesty. ….
[The two great Empires of Lilliput and Blefuscu] have, as I was going to tell you,
been engaged in a most obstinate War for six and thirty Moons past. It began
upon the following Occasion. It is allowed on all Hands, that the primitive Way
of breaking Eggs before we eat them, was upon the larger End: But his present
Majesty’s Grand-father, while he was a Boy, going to eat an Egg, and breaking it
according to the ancient Practice, happened to cut one of his Fingers.
Whereupon the Emperor his Father, published an Edict, commanding all his
Subjects, upon great Penalties, to break the smaller End of their Eggs. The
People so highly resented this Law, that our Histories tell us, there have been six
Rebellions raised on that Account; wherein one Emperor lost his Life, and
another his Crown. These civil Commotions were constantly fomented by the
Monarchs of Blefuscu; and when they were quelled, the Exiles always fled for
Refuge to that Empire. It is computed, that eleven Thousand Persons have, at
several Times, suffered Death, rather than submit to break their Eggs at the
smaller end. Many hundred large Volumes have been published upon this
Controversy: But the Books of the Big-Endians have been long forbidden, and
the whole Party rendered incapable by Law of holding Employments.”
Jonathan Swift was born in Ireland in 1667 of English parents. He took a B.A. at Trinity
College in Dublin and some time later was ordained an Anglican priest, serving briefly in a
parish church, and became Dean of St. Patrick’s in Dublin in 1713. Contemporary critics
consider the Big-Endians and Little-Endians to represent Roman Catholics and Protestants
respectively. Lilliput seems to represent England, and its enemy Blefuscu is variously
considered to represent either France or Ireland. Note that the phrase “little-endian” seems
not to appear explicitly in the text of Gulliver’s Travels.

Page 124 Chapter 5 Revised November 5, 2008


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 6: The Assembly Process

This chapter will present a brief introduction to the functioning of a standard two–pass
assembler. It will focus on the conversion of the text of an assembly language program,
written in a form that humans can read, into a machine language program that can be loaded
into memory and executed by a computer.
Particular attention will be placed on a logical construct called the location counter. This is
a counter used to allocate memory addresses to each line of machine code, whether it be an
executable instruction or a location reserved to store some value.
This chapter will then briefly discuss the process of loading and executing an assembly
language program. It will close with a few comments on the essential differences between a
compiler processing a high level program and an assembler processing its program.

The Sample Program Fragment


We shall focus on a fragment of assembly language code for the single high–level line of
code that adds three variables and places the result in a fourth variable.
W = X + Y + Z
Before giving the assembly language equivalent of this code fragment, we note that addition
is basically a dyadic instruction; it takes two arguments and produces a single result. Due to
the lack of a primitive three–input addition instruction, the above code fragment will be
processed somewhat as if it were the following lines of high–level code.
W = X
W = W + Y
W = W + Z
Here is a fragment of assembly language code that includes a translation of the above
high–level code. This discussion focuses on allocation of addresses to items in the assembly
language; thus it will use a number of concepts without sufficient explanation.
BALR 12,0 LOAD REGISTER 12 WITH CURRENT ADDRESS
USING *,12 AND USE IT AS A BASE FOR ADDRESSING.
L 5,X VALUE OF X INTO REGISTER 3
A 5,Y ADD VALUE OF Y TO REGISTER 5
A 5,Z ADD VALUE OF Z TO REGISTER 5
ST 5,W STORE SUM INTO W
W DC F‘0’ W HAS AN INITIAL VALUE OF 0
X DC F‘1’ X HAS AN INITIAL VALUE OF 1
Y DC F‘2’ Y HAS AN INITIAL VALUE OF 2
Z DC F‘3’ Z HAS AN INITIAL VALUE OF 3
At this point, we must notice a major flaw in the code. Every line of the code is correct, and
formatted in the standard style. Every instruction will execute correctly. The difficulty will
arise after the “ST 5,W” has been executed, placing a value of 6 into location W.
The program has no STOP or branch statement, so it will start executing the data.

Page 125 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

The Two–Pass Assembler


We now examine the action of a two–pass assembler on the above code fragment. Roughly
speaking, the functions of the passes are as follows.
Pass 1 This associates addresses with the various labels used. The code
fragment above uses four labels: W, X, Y, and Z.
Pass 2 Uses these addresses to generate the machine language code for each
line of assembly language.
The assembler assigns addresses by use of the location counter, here abbreviated LC, to
track the size of the address space already allocated. Later discussions of the LC will reflect
on its explicit use within the text of an assembler language program and treat it almost as a
general purpose register (which it is not), but this discussion treats it as a conceptual device.
We shall now trace the operation of the assembler on these program statements, generally
considering only one line at a time. The student should recall that some of these concepts,
especially the handling of the first two lines, will be explained very fully at a later time.
The first two lines of the code above should be viewed almost as non–executable. These are
used to “establish addressability” in the standard parlance. In effect, they tell the assembler
how to set an initial value for the location counter.
BALR 12,0 LOAD REGISTER 12 WITH CURRENT ADDRESS
USING *,12 AND USE IT AS A BASE FOR ADDRESSING.
Recalling that addresses issued by the assembler may be adjusted when the program is loaded
into memory, we note that the affect of this pair of lines is to set the LC.
Pass 1 processes the third line.
L 5,X VALUE OF X INTO REGISTER 3
At this point, we have LC = 0, as it was just initialized. The instruction will be assigned to
address 0. The instruction is a type RX, requiring four bytes for its storage.
Pass 1 processes line 4
A 5,Y ADD VALUE OF Y TO REGISTER 5
Since the previous instruction requires 4 bytes, the location counter has been incremented, so
that LC = 4 and this instruction will be placed at address 4. This instruction is also a type
RX, and also required four bytes. The next instruction will be at address 8.
Pass 1 processes line 5
A 5,Z ADD VALUE OF Z TO REGISTER 5
Since the previous instruction requires 4 bytes, the location counter has been incremented, so
that LC = 8 and this instruction will be placed at address 8. This instruction is also a type
RX, and also required four bytes. The next instruction will be at address 12 (decimal).
Pass 1 processes line 6
ST 5,W STORE SUM INTO W
Since the previous instruction requires 4 bytes, the location counter has been incremented, so
that LC = 12 and this instruction will be placed at address 12. This instruction is also a type
RX, and also required four bytes. The next instruction will be at address 16 (decimal).

Page 126 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

Pass 1 processes line 7


W DC F‘0’ W HAS AN INITIAL VALUE OF 0
Since the previous instruction requires 4 bytes, the location counter has been incremented, so
that LC = 16. This line is not an instruction, but is a declarative, used to define a label and
allocate storage space for a value to be associated with that label.
This line declares space to store a 32–bit fullword, so it allocates four bytes for storage. The
next line will be associated with address 20 (decimal). This line defines the symbol W as
being associated with address 16 (decimal).
Pass 1 processes line 8
X DC F‘1’ X HAS AN INITIAL VALUE OF 1
Since the previous declarative requires 4 bytes, the location counter has been incremented, so
that LC = 20, and the label X will be associated with address 20 (decimal).
This line also declares space to store a 32–bit fullword, so it allocates four bytes for storage.
The next line will be associated with address 24 (decimal).
Pass 1 processes line 9
Y DC F‘2’ Y HAS AN INITIAL VALUE OF 2
Since the previous declarative requires 4 bytes, the location counter has been incremented, so
that LC = 24, and the label Y will be associated with address 24 (decimal).
This line also declares space to store a 32–bit fullword, so it allocates four bytes for storage.
The next line will be associated with address 28 (decimal).
Pass 1 processes line 10
Z DC F‘3’ Z HAS AN INITIAL VALUE OF 3
Since the previous declarative requires 4 bytes, the location counter has been incremented, so
that LC = 28, and the label Z will be associated with address 28 (decimal).
One of the key outputs of pass 1 is a table associating each label with it address. Up to now,
we have been using decimal addresses. At this point, we must translate to hexadecimal.
Label Address
Decimal Hexadecimal
W 16 0x10
X 20 0x14
Y 24 0x18
Z 28 0x1C
One should note that our simple code sample is atypical in one regard. All labels in this
fragment are associated with values to be processed. A more typical program would have
labels associated with executable statements. The processing will be the same; as each line is
processed, the value of the LC will be associated with any label found on the line.
Pass 2 of the assembler will generate the binary machine code associated with each line and
prepare it for loading into the computer memory. At this point, we note another artificiality
of the simple program fragment; each line corresponds to exactly four bytes. As we shall see
later, this is rarely the case for IBM S/370 Assembler Language.

Page 127 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

Loading the Machine Code


Before considering the actions of a loader, it would help to give a representation of the
results of pass 1 of the assembler. The following listing gives the essence of what was done.
Address Assembly Statement
0000 L 5,X
0004 A 5,Y
0008 A 5,Z
000C ST 5,W
0010 W DC F‘0’
0014 X DC F‘1’
0018 Y DC F‘2’
001C Z DC F‘3’
Note that the addresses listed here are generated by the assembler and relative to the address
assigned to the first one listed here. When the code is loaded into memory and made ready to
execute, each of these statements will be moved to another address. One of the jobs of the
linking loader is to adjust these addresses.
Suppose that the program were loaded into address 0x1400 of real memory. Here is what the
memory map, as seen by the operating system, would appear to be.
Address Assembly Statement
1400 L 5,X
1404 A 5,Y
1408 A 5,Z
140C ST 5,W
1410 W DC F‘0’
1414 X DC F‘1’
1418 Y DC F‘2’
141C Z DC F‘3’
There are two approaches to handling this issue of addressing, which arises from the fact that
the assembler addresses are different from those physical memory addresses into which the
program is loaded. The first one relates to altering the machine code generated by pass 2 of
the assembler. Since the System/370 does not use this approach, we shall not discuss it.
The second approach depends on the fact that relocating a fragment of code does not change
the addresses of any line in the fragment relative to the addresses of any other fragment.
Consider each of the two fragments of code listed above. Simple subtraction will show that
the address of each statement relative to the first one listed remains constant.
This observation forms the basis of the addressing modes used by the IBM System/370.
Consider now the pair of code lines that we have not discussed.
BALR 12,0 LOAD REGISTER 12 WITH CURRENT ADDRESS
USING *,12 AND USE IT AS A BASE FOR ADDRESSING.
The effect of these two lines is to load the absolute memory address of the line of code
following the second statement into general purpose register 12, and make all address
references relative to that stored value.

Page 128 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

Pass 2 of the Assembler


The primary function of the second pass of the assembler is to emit binary machine language.
Here we shall jump ahead a bit and show the code generated. The student should be aware
that all of this will be explained in great detail in a later chapter; the point now is just to see
the association of machine code with addresses.
All of the instructions used in this program fragment are what is called “Type RX”.
Instructions in this format require four bytes, represented as eight hexadecimal digits.
The format of such an instruction is shown below.
Byte 1 Byte 2 Byte 3 Byte 4
OP R X B D D D
The first byte is the opcode for the instruction, represented as two hexadecimal digits.
For our instructions they are L Load Register 0x58
A Add to Register 0x5A
ST Store Register 0x50
The second byte contains two hexadecimal digits. The first is for the affected register, here
we are using 5. The second is for an index register. As this example does not use indexed
addressing, the value placed in this digit is 0.
The next two bytes contain the base register used, represented by a single hexadecimal digit.
Here we specify 0xC, because register 12 is used as a base. The “DDD” represents a
displacement address given as three hexadecimal digits.
Here is the output of pass 2 of the assembler.
Address Contents Assembly Statement
0000 58 50 C0 10 L 5,X
0004 5A 50 C0 14 A 5,Y
0008 5A 50 C0 18 A 5,Z
000C 50 50 C0 1C ST 5,W
0010 00 00 00 00 W DC F‘0’
0014 00 00 00 01 X DC F‘1’
0018 00 00 00 02 Y DC F‘2’
001C 00 00 00 03 Z DC F‘3’
A few points should be clear in the listing above.
1. The executable instructions produce code that follows a standard
format that is known to the assembler.
2. Each constant, here defined by a DC declarative, is just transformed
into a hexadecimal number of the proper length.
3. This code gets around the issue of absolute memory addressing by
making all addresses relative to the first one in the list.
4. This code lacks any proper termination code, so that it will simply
attempt to execute the data. This will cause problems.

Page 129 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

Compilers vs. Assemblers: Some Preliminary Remarks


At this point, it would be helpful to note a few differences between the actions of a compiler
and the actions of a typical assembler. Each takes a program written in text written by
humans and emits a machine language program that is executable on a computer.
The major difference between a compiled language and an assembled language has to do
with the construct called a variable in a high–level language. While it is tempting to refer to
data labels in assembler code as variables, this is not strictly correct.
The idea of a high–level language variable refers to a binding of three different attributes
associated with the label: the storage location, the data type, and the value. It is important to
recall that the compiler manages much of this automatically, following some directions that
are found in the code. Consider the following Java code, almost correct and roughly
equivalent to the assembly code we have just seen.
int w = 0;
int x = 1;
int y = 2;
int z = 3;

w = x + y + z;
In this language we have true variables. Note that the variables are simply declared and
given initial values. There is no need (or ability) to specify the storage locations assigned to
each. The compiler will do that automatically.
In the above Java code, it is obvious that each variable is declared as an integer. For this
reasons, the “+” sign in the line of code is interpreted by the compiler as integer addition.
Put another way, the declaration of the variable type defines the operations applied to it.
The situation in assembler coding is quite different. Each label (what might very loosely be
called a variable) must have its storage allocation specifically in the code. Furthermore, each
label must be declared in a location that will not interfere with the execution of the code.
The student will note this as an acknowledged failure of the assembly code fragment above.
The second major difference between assembler code and high–level code is that, in
assembler, the data declarations do not define the operations. Each operation is specific to a
data type and can be applied to another data type with amusing results.
Consider the following slight modification of the assembly code above.
LH 5,X VALUE OF X INTO REGISTER 3
AH 5,Y ADD VALUE OF Y TO REGISTER 5
AH 5,Z ADD VALUE OF Z TO REGISTER 5
STH 5,W STORE SUM INTO W
W DC F‘0’ W HAS AN INITIAL VALUE OF 0
X DC F‘1’ X HAS AN INITIAL VALUE OF 1
Y DC F‘2’ Y HAS AN INITIAL VALUE OF 2
Z DC F‘3’ Z HAS AN INITIAL VALUE OF 3
The data are still declared as 32–bit fullwords, but the operations are specific to 16–bit
halfwords. The code will execute, and the answer will be 0.

Page 130 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language The Assembly Process

Since I have mentioned this possibility of mismatching the assembler instruction with the
data type of the operands, I think that I should explain what is going on. Recall the address
assignments made by the assembler: W at 0x10, X at 0x14, Y at 0x18, and Z at 0x1C.
Consider the hexadecimal representation of the 32–bit number stored at address X. It is
00 00 00 01. Here is the memory map, in which the addresses are byte addresses.
Address Contents
0x14 00
0x15 00
0x16 00
0x17 01
We now consider the effect of two different instructions.
L 5, X Go to address 0x14. Get the four bytes at addresses 0x14, 0x15, 0x16 and
0x17. Treat these as a 32–bit integer and load into register 5.
LH 5, X Go to address 0x14. Get the two bytes at addresses 0x14 and 0x15.
Treat these as a 16–bit integer, sign extend to 32 bits, and load into register 5.
Note that the two–byte value stored at address 0x14 is 00 00, which will be interpreted as
decimal 0. The same is true for the values at addresses Y and Z.
To repeat himself, the author invites the student to note the names used in this part of the
discussion. The symbol “X”, which would be called a variable in a high–level language, will
be referred to either as an address or as a label. In assembler language, it is never exactly
correct to speak of a variable, though the term does have some valid informal use.
As another obvious example, consider the assembler language that might translate the
high–level language statement Y = X.
L 6, X LOAD REGISTER 6 WITH THE VALUE AT ADDRESS X.
ST 6, Y STORE THAT VALUE INTO ADDRESS Y.

Page 131 Chapter 6 Revised June 26,2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 7: Assembler Directives and Data Definitions

We begin the discussion of IBM Mainframe Assembler Language by making a broad


distinction. Every program to be processed on a computer begins in a form that can be seen
as a text file; that is, it is a sequence of statements that can be read by humans. The
distinction to be made here is between those statements that will be converted into executable
code and those that instruct the assembler to perform some specific function.
There are two specific classes of non–executable instructions: declaratives and directives.
Declaratives are used mostly to allocate memory in which to store data. Directives are used
for a number of functions that direct operation of the assembler. We shall discuss directives
first. There are a number of directives available; here are the ones that we shall discuss.
CSECT Identifies the start or continuation of a control section.
DSECT Identifies the start or continuation of a dummy control section.
A dummy section is used to pass data by reference to a subroutine.
EJECT Start a new page before continuing the assembler listing.
This is used to format a paper printout of the assembler text.
END End of the assembler module or control section.
EQU Equate a symbol to a name or number.
LTORG Begin the literal pool.
PRINT Sets some options for the assembly listing.
SPACE Provides for line spacing in the assembler listing.
START Define the start of the first control section in a program.
TITLE Provide a title at the top of each page of assembler listing.
USING Indicates the base registers to use in addressing.

CSECT
By definition, a control section (CSECT), is “a block of coding that can be relocated
(independent of other coding) without altering the operating logic of the program.”*
Every program to be executed must have at least one control section. If the program has only
one control section, as is usually the case for student programs, we may begin it with either a
CSECT or START directive.
When used, a START directive “defines the start of the first control section in a program”.
We shall later discuss reasons why a program might need more than one control section. In
this case, it is probably best to use only the CSECT directive.

Page 132 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

DSECT
A DSECT (Dummy Section) is used to describe a data area without actually reserving any
storage for it. This is used to pass arguments by reference from one program to another.
Recall that there are two common ways for a program to pass arguments to another: call by
value and call by reference. Students of programming languages will know several more.
In call by value, the value of an argument is passed to the receiving program, which can be
considered to get only a local copy of the value. If the receiving program changes this value,
the change is not reflected in the calling program. Some programming languages do not
allow the receiving program to change the value of an argument passed by value; most do.
In call by reference, the address or some other identifier of the argument is passed to the
receiving program. If the receiving program changes the value of the argument, the changed
value is returned to the calling program.
Suppose that PROGA calls PROGB and passes a list of arguments. When a DSECT is used,
what is passed is the starting address of a section of memory assigned to those arguments.
The receiving program has a DSECT that mimics the structure of the section of memory in
the calling program. This structure and the address of the data section in the calling program
are used to compute the address (in the calling program) of every argument.
We shall discuss Dummy Sections in more detail later.
END
The END statement must be the last statement of an assembler control section.
The form of the statement is quite simple. It is
END Section_Name
So, our first program had the following structure.
LAB1 CSECT
Some program statements
END LAB1
Note that it easily could have been the following.
LAB1 START
Some program statements
END LAB1
EQU
The EQU directive is used to equate a name with an expression, symbolic address,
or number. Whenever this name is used as a symbol, it is replaced.
We might do something, such as the following, which makes the symbol R12 to
be equal to 12, and replaced by that value when the assembler is run.
R12 EQU 12
Consider the following two lines of assembler code, assumed to occur after the above EQU
statement in the code. The original form uses “R12”, and appears as follows.
BALR R12,0
USING *,R12

Page 133 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

The effect of the EQU directive is to change this text into the following before the assembler
actually produces any machine language code.
BALR 12,0
USING *,12
Within this context, the label R12 will always reference register 12. We recognize this and
use the EQU directive to allow the listing to be “R12” to reflect that fact. One advantage of
the EQU is that the label R12 will show up in assembler cross–listings of labels used, while
the value 12 will not be used. We get to see every place register R12 is used.
There are also uses in which symbolic addresses are equated. Consider this example.
PRINT DC CL133’ ’
P EQU PRINT Each symbol references the same address
One can also use the location counter, denoted by “*”, to set the symbol equal to the current
address that is allocated by the assembler. This example sets the symbol RETURN to the
current address, which is not associated with an instruction.
RETURN EQU * BRANCH TO HERE FOR NORMAL RETURN

The Location Counter


The location counter is denoted by the asterisk “*”. One might have code such as.
SAVE DS CL3
KEEP EQU *+5
Suppose the symbol SAVE is associated with location X‘3012’. It reserves 3 bytes for
storage, so the location counter is set to X‘3015’ after assembling the item.
The symbol KEEP is now associated with X‘3015’ + X‘5’ = X‘301A’
LTORG
The Literal Pool contains a collection of anonymous constant definitions, which are
generated by the assembler. The LTORG directive defines the start of a literal pool.
While some textbooks may imply that the LTORG directive is not necessary for use of
literals, your instructor’s experience is different. It appears that an explicit LTORG directive
is required if the program uses literal arguments.
The classic form of the statement is as follows, where the “L” of “LTORG” is to be found in
column 10 of the listing.
Generally, this statement should be placed near the end of the listing, as in the next example
taken from an actual program.
240 * LITERAL POOL
241 *********************************
000308 242 LTORG *
000308 00000001 243 =F'1'
000000 244 END LAB1
Here, line 243 shows a literal that is inserted by the assembler. Note that lines 242 and 243
are listed at the same address (hexadecimal 000308). The directive generates no code.

Page 134 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

PRINT
This directive controls several options that impact the appearance of the listing.
Two common variants are:
PRINT ON,NOGEN,NODATA WE USE THIS FOR NOW
PRINT ON,GEN,NODATA USE THIS WHEN STUDYING MACROS
The first operand is the listing option. It has two values: ON or OFF.
ON Print the program listing from this point on. This is the normal setting,
especially for student programs that are run only a few times.
OFF Do not print the listing. This is used for “production programs” that
have been thoroughly tested and now are used for results only.
The second operand controls the listing of macros, which are single statements that
expand into multiple statements. We shall investigate them later.
The two options for this operand are NOGEN and GEN.
GEN Print all the statements that a macro generates.
NOGEN Suppress the generated code. This is the standard option.
Here is an two samples of the same code, which contains the user–defined macro STKPUSH,
used to manage a stack. The first sample is a listing generated with the GEN option.
100 STKPUSH HHW,H
000068 4830 C0C6 000CC 101+ LH R3,STKCOUNT
00006C 8B30 0002 00002 102+ SLA R3,2
000070 4120 C0CA 000D0 103+ LA R2,THESTACK
000074 4840 C1CE 001D4 104+ LH R4,HHW
000078 5043 2000 00000 105+ ST R4,0(3,2)
00007C 4830 C0C6 000CC 106+ LH R3,STKCOUNT
000080 4A30 C43A 00440 107+ AH R3,=H'1'
000084 4030 C0C6 000CC 108+ STH 3,STKCOUNT
109 STKPUSH FFW
000088 4830 C0C6 000CC 110+ LH R3,STKCOUNT
00008C 8B30 0002 00002 111+ SLA R3,2
000090 4120 C0CA 000D0 112+ LA R2,THESTACK
000094 5840 C1CA 001D0 113+ L R4,FFW
000098 5043 2000 00000 114+ ST R4,0(3,2)
00009C 4830 C0C6 000CC 115+ LH R3,STKCOUNT
0000A0 4A30 C43A 00440 116+ AH R3,=H'1'
0000A4 4030 C0C6 000CC 117+ STH 3,STKCOUNT
The second listing is generated with the NOGEN option. Note the suppression of all of
the code from the expansion of the two macros.
100 STKPUSH HHW,H
109 STKPUSH FFW
The NOGEN option is the standard because the student rarely wants to see the code
expansion of macros, especially the system macros such as OPEN, GET, and PUT. The
GEN option is mostly used in programs that explore the use of user–defined macros.
The above example is taken from a program that defines macros to operate on a stack data
structure. It is important in this program to see the code generated by each expansion of the
macro; it is for this reason that the GEN option has been selected.

Page 135 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

The third operand controls printing of the hexadecimal values of constants.


DATA Print the full hexadecimal value of all constants.
NODATA Print only the leftmost 16 hex digits of the constants.

USING
A typical use would be found in our first lab assignment.
BALR 12,0 ESTABLISH
USING *,12 ADDRESSABILITY
The structure of this pair of instructions is entirely logical, though it may appear as quite
strange. The first thing to note is that the statement “USING *,12” is a directive, so that it
does not generate binary machine language code, and is not assigned an address. To the
extent that the statement can have an address associated, it is the address of the next
executable assembly language instruction, which commonly follows it immediately.
The BALR 12,0 is an incomplete subroutine call. It loads the address of the next
instruction (the one following the USING, since that is not an instruction) into register 12 in
preparation for a Branch and Link that is never executed. We shall discuss subroutine calls
in a later lecture, focusing then on statements in which the second argument is not 0.
The “USING *” part of the directive tells the assembler to use register 12 as a base register
and begin displacements for addressing from the next instruction. The mechanism, base
register and offset, is used by IBM in order to save space. It serves to save memory space.
Directives Associated with the Listing
Here is a list of some of the directives used to affect the appearance of the
printed listing that usually was a result of the program execution process.
In our class, this listing can be seen in the Output Queue, but is never actually
printed on paper. As a result, these directives are mostly curiosities.
EJECT This causes a page to be ejected before it is full. The assembler keeps
a count of lines on a page and will automatically eject when a specified
count (maybe 66) is reached. One can issue an early page break.
SPACE This tells the assembler to place a number of blank lines between each line
of the text in the listing. Values are 1, 2, and 3; with 1 as the default.
SPACE Causes normal spacing of the lines.
SPACE 1 Causes normal spacing of the lines
SPACE 2 Double spacing; one blank line after each line of text
SPACE 3 Triple spacing; 2 blank lines after each line of text.
TITLE This allows any descriptive title to be placed at the top of each listing page.
The title is placed between two single quotes.
TITLE ‘THIS IS A GOOD TITLE’

Page 136 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

Data Definition
We now discuss the rules for defining data items to be used by an assembler program.
There are two important functions to be performed by each data definition statement.
1. To allocate space that will be associated with the label.
2. Optionally to allocate an initial value to be associated with the label.
The two primary data definition statements are the DS directive and the DC directive. The
DS directive allocates space for a label; the DC allocates space and assigns an initial value.

The DC and DS Declaratives


These declaratives are statements that assign storage locations.
The DC declarative assigns initialized storage space, possibly used to define constants.
This should be read as “Define Initialized Storage”; assembly language does not support
the idea of a constant value that cannot be changed by the program.
The DS assigns storage, but does not initialize the space.
The assembler recognizes a number of data types. There are many others.
Those of importance to this course are as follows:
A address (an unsigned binary number used as an address)
B binary (using the binary digits 0 and 1)
C character
F 32–bit word (a binary number, represented by decimal digits)
H 16–bit half–word
P packed decimal
X hexadecimal number

DS (Define Storage)
The general format of the DS statement is as follows.
Name DS dTLn ‘comments’

The name is an optional entry, but required if the program is to refer to the field by name.
The standard column positions apply here.
The declarative, DS, comes next in its standard position.
The entry “dTLn” is read as follows.
d is the optional duplication factor. If not specified, it defaults to 1.
T is the required type specification. We shall use A, B, C, F, P, or X.
note that the data actually stored at the location does not need to be
of this type, but it is a good idea to restrict it to that type.
L is an optional length of the data field in bytes.

Page 137 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

The next field does not specify a value, but should be viewed as a comment.
This comment field might indirectly specify the length of the field, if the L
directive is not specified.

Examples of the DS Statement


Consider the following examples.
C1 DS CL5 A CHARACTER FIELD OF LENGTH 5 BYTES.
THIS HOLDS FIVE CHARACTERS..
C2 DS 1CL5 EXACTLY THE SAME AS THE ABOVE.
THE DEFAULT REPETITION FACTOR IS 1.
P1 DS PL2 A PACKED DECIMAL FIELD OF LENGTH TWO
BYTES. THIS HOLDS THREE DIGITS.
P2 DS 5PL4 FIVE PACKED DECIMAL FIELDS, EACH OF
LENGTH 4 BYTES AND HOLDING 7 DIGITS.
F1 DS F‘23’ ONE 32-BIT FULL WORD. THE FIELD HAS
LENGTH 4 BYTES. THE ‘23’ IS TREATED
AS A COMMENT; NO VALUE IS STORED.
DS C AN ANONYMOUS FIELD FOR ONE CHARACTER.
THE LENGTH DEFAULTS TO 1. THERE IS
NO NEED TO NAME EVERY DECLARATION.

Input Records and Fields


Data are read into records. You may impose a structure on the record by declaring it with a
zero duplication factor. This allows the record to be broken into fields, each with a data item
relevant to the record. Note that the sum of the field sizes must be that of the record.
Here is a declaration of an 80–byte input area that will be divided into fields.
CARDIN DS 0CL80 The record has 80 bytes.
NAME DS CL30 The first field has the name.
YEAR DS CL10 The second field.
DOB DS CL8 The third field.
GPA DS CL3 The fourth field.
DS CL29 The last 29 chars are not used.
The idea is that the entire record is read into the 80–byte field CARDIN.
The data can be extracted one field at a time. Here is the COBOL equivalent.
01 CARDIN.
10 NAME PIC X(30).
10 YEAR PIC X(10).
10 DOB PIC X(08).
10 GPA PIC X(3).
10 FILLER PIC X(29).

Page 138 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

More on the Zero Repetition Factor


Consider the previous example, used to define fields in a card image input.
As in all of this type of programming the input is imagined as an 80–column card.
CARDIN DS 0CL80
NAME DS CL30
YEAR DS CL10
DOB DS CL8
GPA DS CL3
FILLER DS CL29
Because of the zero repetition factor the line CARDIN DS 0CL80 can be viewed
almost as a comment. It declares that a number of statements that follow will actually
allocate 80 bytes for 80 characters, and associate data fields with that input.
Here we see that 30 + 10 + 8 + 3 + 29 = 80. In this case, it is the five statements following
the CARDIN DS 0CL80 that actually allocate the storage space.
Remember that it is not the number of statements that is important, but the number of bytes
allocated. For character data in EBCDIC form the character count is the byte count.

Another Card Definition


Suppose that we have a program that is to read a list of integers, one per card and do some
processing with those integers. The same logic will apply to numbers in any format (fixed
point, floating point, etc.), but the example is most easily made with positive integer data.
At this point, we cannot process a sign bit; “+” and “–” are out.
The first choice is how many digits are to be used for the positive integer.
The second choice is where to place those digits.
Here we choose to use five digits, placed in the first five columns of the card.
The appropriate declaration follows.
RECORDIN DS 0CL80 THE CARD HAS 80 COLUMNS
DIGITS DS CL5 FIVE BYTES FOR FIVE DIGITS
FILLER DS CL75 THE NEXT 75 COLUMNS ARE IGNORED.
Notice that the first statement does not allocate space. The next two statements
allocate a total of 80 bytes for 80 characters.

Sample Input Data Record: Reading Positive Integers


Suppose that we wanted to read a list of five–digit numbers, one number per “card”.
Each digit is represented as a character, encoded in EBCDIC form.
The appropriate declaration might be written as follows.
RECORDIN DS 0CL80 THE CARD HAS 80 COLUMNS
DIGITS DS CL5 FIVE BYTES FOR FIVE DIGITS
FILLER DS CL75 THE NEXT 75 COLUMNS ARE IGNORED.
In this, the first five columns of each input line hold a character to be interpreted as a
digit. The other 75 are not used. This input is not free form.

Page 139 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

Based on the above declaration, one would characterize the first five columns as follows:

Sample Code and Data Structure


Consider the code fragment below, containing operations not yet defined. This
uses the above declarations, specifically the first five columns as digits.
PACK PACKIN,DIGITS CONVERT TO PACKED DECIMAL
AP PACKSUM,PACKIN ADD TO THE SUM.
Given the definition of DIGITS, the PACK instruction expects the input to be
right justified in the first five columns. The input below will be read as “23”.
23 Note the three spaces before the digits.
2 is in the tens column and 3 is in the units.
The following input is not proper for this declaration.
37 “3” in column 3, “7” in column 4, column 5 blank.
The PACK instruction will process the first five columns, and result in a number that
does not have the correct format. The AP (an addition instruction) will fail because its
input does not have the correct input, and the program will terminate abnormally.

DC (Define Constant)
Remember that this declarative defines initialized storage, not a constant in the
sense of a modern programming language. For example, one might declare an
output area for a 132–column line printer as follows:
PRINT DS 0CL133
CONTROL DC C’ ’ The single control character
LINEOUT DC CL132’ ’ Clear out the area for data output
One definitely wants to avoid random junk in the printer control area.
The data to be output should be moved to the LINEOUT field.
NOTE: One might have to clear out the output area after each line is printed.
Character constants are left justified. Consider the following.
B1 DC CL4‘XYZ’ THREE CHARACTERS IN 4 BYTES
What is stored? ANSWER E7 E8 E9 40 (hexadecimal)
The above is the EBCDIC for the string “XYZ ”

Page 140 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

DC: Define Initialized Storage


Consider the following assembly language code and associated data declarations.
Again, this uses assembly language operators that have yet to be defined.
L R5,=F‘2234’ PUT THE VALUE 2234 INTO REGISTER
R4. IT IS A 32-BIT INTEGER.
ST R5,FW01 STORE INTO THIS LOCATION.
More code here.
FW01 DC F‘0’ A 32-BIT FULLWORD WITH VALUE
INITIALIZED TO ZERO.
There is no problem with changing the value of this “constant”, called FW01.
The DC declaration just sets aside storage space (here four bytes for a fullword) and assigns it
an initial value. The program is free to change that value.
There is nothing in this assembler language that corresponds to a constant, as the term is used
in a higher level language such as Java, C++, or Pascal. The only way to insure that a value
initialized with a DC directive is treated as a real constant is not to write code to change it.
The assembler enforces very little, and certainly not the idea of a constant. Nevertheless, the
idea of using a DIS directive might be too strange for some students.

More On DC (Define Constant)


The general format of the DC statement is as follows.
Name DC dTLn ‘constant’

The name is an optional entry, but required if the program is to refer to


the field by name. The standard column positions apply here.
The declarative, DC, comes next in its standard position.
The entry “dTLn” is read as follows.
d is the optional duplication factor. If not specified, it defaults to 1.
T is the required type specification. We shall use A, B, C, F, P, or X.
Note that the data actually stored at the location does not need to be
of this type, but it is a good idea to restrict it to that type.
L is an optional length of the data field in bytes.
The ‘constant’ entry is required and is used to specify a value.
If the length attribute is omitted, the length is specified implicitly by this entry.

Page 141 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

The Duplication Factor


The duplication factor is used in both the DC and DS statements.
Here are a few examples.
P1 DS 3PL4 Three 4–byte fields for packed decimal
C1 DS 1CL5 ONE 5-CHARACTER FIELD.
C2 DS CL5 ANOTHER 5-CHARACTER FIELD.
H1 DS 4H FOUR HALF WORDS (8 BYTES)
F2 DS 5F FIVE FULL WORDS (20 BYTES)
F3 DC 2F‘32’ TWO FULL WORDS, EACH HAS VALUE 32
EIGHT BYTES OF STORAGE ARE ALLOCATED,
WITH CONTENTS 00 00 00 20 00 00 00 20.
In the above example, recall that decimal 32 is hexadecimal 0x20. As a 32–bit fullword, this
number is stored in four bytes represented by the eight hexadecimal digits 0x0000 0020.
TPL DC 3C‘1234’ THREE COPIES OF THE CONSTANT ‘1234’
TWELVE BYTES OF STORAGE ARE ALLOCATED:
F1 F2 F3 F4 F1 F2 F3 F4 F1 F2 F3 F4
NOTE: The address associated with each label is the leftmost byte allocated.
For TPL, this would be the byte containing the F1 (the first one).
In this and the next example, the EBCDIC code for the character string “1234”
is “F1 F2 F3 F4”. The spaces are added to improve readability.

More on the Duplication Factor


Consider again the declaration of the three character strings.
TPL DC 3C‘1234’ THREE COPIES OF THE CONSTANT ‘1234’
Here is the explicit allocation of the twelve bytes, for the twelve characters. Each byte
contains the EBCDIC code for the digit represented as two hexadecimal digits.
Address Contents
TPL F1
TPL+1 F2
TPL+2 F3
TPL+3 F4
TPL+4 F1
TPL+5 F2
TPL+6 F3
TPL+7 F4
TPL+8 F1
TPL+9 F2
TPL+10 F3
TPL+11 F4

Page 142 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

Some Trick Questions


Consider the following two statements.
To what value is each label initialized?
DATE1 DS CL8‘DD/MM/YY’
DATE2 DC CL8‘MM/DD/YY’
ANSWER:
1. DATE1 is not initialized to anything. The string ‘DD/MM/YY’ is treated as a
comment. I view this as a trick, and would prefer the assembler not to allow this.
2. DATE2 is initialized as expected.
What about the following?
DATE3 DC CL8 ‘MM/DD/YY’ Note the space after CL8.
This is an error, likely to cause a problem in the assembly process. The space after the
“CL8” initiates a comment, so the label is not initialized.
As an aside, this problem will be seen any time a space is used inappropriately. The standard
for the assembler is to treat the line as having four distinct fields: an optional label followed
by a number of spaces, then an instruction or directive followed by some spaces, then an
operand. The operand is terminated by a space and anything after that is a comment.

Hexadecimal Constants
Two hexadecimal digits can represent any of the 256 possible values that can appear in a byte
or represented as an EBCDIC character. This is handy for specifying character strings that
are otherwise hard to code in the assembly language.
Consider the following example.
ENDLINE DC X’0D25’ Carriage return / line feed.

WARNING
Do not confuse hexadecimal constants with other formats. For example:
Format Constant Bytes Hex Representation
Character DC C’ABCD’ 4 C1C2C3C4
Hexadecimal DC X’ABCD’ 2 ABCD
Character DC C’1234’ 4 F1F2F3F4
Hexadecimal DC X’1234’ 2 1234
Packed DC P’123’ 2 123C
Hexadecimal DC X’123’ 2 0123
In the last example, the three hexadecimal digits would require one and a half bytes to store.
However, memory cannot be allocated in half–bytes, so the allocation is two bytes.

Page 143 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

More Confusion: All Storage Can Be Seen as Hexadecimal


The trouble is that all data types are stored as binary strings, which can easily be represented
as hexadecimal digits.
Consider the positive binary number 263. Now 263 = 256 + 4 + 2 + 1, so we have
its binary representation as 01 0000 0110. The table below uses the IBM bit numbering.
Bit No. 0 1 2 3 4 5 6 7 8 9
Value 0 1 0 0 0 0 0 1 1 1
Hex 1 0 7

Suppose that we have two data declarations


BINCON DC H‘263’
PACKCON DC P‘263’
What would be stored. Recall that each form takes two bytes, or four hexadecimal
digits for storage. Recall also that a memory map shows the contents in hexadecimal.
Here is what we would see:
Hexadecimal Assembly Code
0107 BINCON DC H‘263’
263C PACKCON DC P‘263’

An Important Difference from High–Level Languages


Note that each of BINCON and PACKCON can represent perfectly a perfectly good
binary number. Each can be viewed as a half–word.
The value in a location depends on the instruction used to process the bits in that location.
Consider the following code fragments, each of which defines RESULT as necessary.
In each case, RESULT occupies two bytes: either a half–word or 3 packed digits.
Case 1:Packed decimal arithmetic
ZAP RESULT, PACKCON COPY PACKCON TO RESULT
AP RESULT, PACKCON RESULT NOW HOLDS 526C
As 263 + 263 = 526, the value in RESULT is now 526 (represented as 526C).
Case 2: Two’s–Complement Integer Arithmetic
LH R3, PACKCON LOAD HEXADECIMAL 263C
AH R3, PACKCON 263C + 263C = 4C78
STH R3, RESULT RESULT NOW HOLDS 4C78.
In hexadecimal: C + C = 18 and 6 + 6 = C
(12 + 12 = 24 = 16 + 8 and 6 + 6 = 12)
Note that the second case represents a mismatch of the operator type and data type.

Page 144 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

Literals
The assembler provides for the use of literals as shortcuts to the DC declarative.
This allows the use of a constant operand in an assembly language instruction.
The immediate operand, another option, will be discussed later.
The assembler processes the literal statement by:
1. Creating an object code constant,
2. Assigning the value of the literal to this constant,
3. Assigning an address to this constant for use by the assembler, and
4. Placing this object in the literal pool, an area of storage
that is managed by the assembler.
The constants created by the literal are placed at a location in the program indicated
by the LTORG directive.
Your instructor’s experience is that the assembler cannot process any use of a literal
argument if the LTORG directive has not been used.

Setting Up the Literal Pool


The easiest way to do this is to “uncomment” the LTORG declaration in the sample
program and change the comment. The sample program has the following. Note the
“*” in column 1 of the line containing the declaration.
****************************************************************
*
* LITERAL POOL - THIS PROGRAM DOES NOT USE LITERALS.
*
****************************************************************
* LTORG *
Here is the changed declaration, with a new comment that is more appropriate.
****************************************************************
*
* LITERAL POOL – THE ASSEMBLER PLACES LITERALS HERE.
*
****************************************************************
LTORG *
Note that the only real change is to remove the “*” from line 1 of the last statement.

Page 145 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

More on Literals
A literal begins with an equal (=) sign, followed by a character for the type of
constant to be used and then the constant value between single quotes.
Here are two examples that do the same thing.
Use of a DC: HEADING DC‘INVENTORY’
MVC PRINT,HEADING
Use of a literal MVC PRINT,=C‘INVENTORY’

Here is another example of a literal, here used to load a constant into a register.
We begin with the instruction itself: L R4,=F'1' Set R4 equal to 1.
000014 5840 C302 00308 47 L R4,=F'1'
Here is the structure of the literal pool, after the assembler has inserted the constant 1.
240 * LITERAL POOL
241 ***************************
000308 242 LTORG *
000308 00000001 243 =F'1'
000000 244 END LAB1

Organization of the Literal Pool


The literal pool is organized into sections in order to provide for efficient use of memory.
Consider the following plausible placement, which is not used.
H1 DC X’CDEF’
C1 DC CL3’123’ At address H1 + 4
F1 DC F’1728’ At address H1 + 7
If the assembler must place F1 at an address that is a multiple of four, it would have to add a
useless single byte as a “pad”.
The rules for allocation of the literal pool minimize the fragmentation of memory.
The literals are organized in four sections, which appear in the following order.
1. All literals whose length is a multiple of 8.
2. All literals whose length is a multiple of 4.
3. All literals whose length is a multiple of 2.
4. All other literals.
The implicit statement is the literal pool begins on an address that is a multiple of 8.

Page 146 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Directives and Data Definitions

Declarations: High Level vs. Assembler


It is important to re–emphasize the difference between data declarations in a high level
language and data declarations in assembler language.

High–Level Languages
Suppose a declaration such as the following in Java.
int a, b ; // Declares each as a 32-bit integer
The compiler does a number of things.
1) It creates two four–byte (32 bit) storage areas and associates one of the areas
with each of the labels. The labels are now called “variables”.
2) It often will clear each of these storage areas to 0.
3) It will interpret each arithmetic operator on these variables as an integer
operation. Thus “a + b” is an invocation to the integer addition function.

Assembler
A DS H Set aside two bytes for label A
B DS H and two bytes for label B.
It is the actual assembly operation that determines the interpretation of the data associated
with each label. Note that neither is actually initialized to a value.
Note again that neither directive associates a type with the space allocated; it just allocates
space appropriate for the type. In fact, standard practice in writing assembler code often calls
for use of a directive to set aside storage to be used with a different type.
As an example, consider the double precision floating point type, designated by a D, which is
represented by 64 bits, or 8 bytes. A typical declaration might be of the form
XX DS D Set aside 8 bytes for the label X.
After label XX has been so declared, it may be used to store any eight–byte unit of data,
even a double precision floating point number.

Page 147 Chapter 7 Revised June 23, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 8: Addressing in the IBM S/370

All stored–program computers run programs that have been converted to binary machine
code and loaded into the primary memory. The presence of virtual memory on most modern
computers is just a variation of that scheme; the basic idea remains the same.
Fundamental to the execution of a loaded computer program is the association of an absolute
address in primary memory for every line of code and data item. Again, the presence of
virtual memory adds a variation on this scheme, but does not change the basic idea.
There are two types of addresses in a virtual memory system: the logical address issued by
the program and the physical address used for actual memory reference. In fact, the basic
definition of virtual memory is that it is a mechanism for decoupling logical addresses from
physical addresses. In a virtual memory system, the executing program calculates a logical
address, and some mechanism (usually part of the Operating System) converts that logical
address into a physical address that is used for the actual memory reference.
While it is a fact that almost every implementation of virtual memory makes use of a disk as
a backing store, reading sections of the program and data into physical memory as needed,
this is not an essential part of the definition. As a matter of fact, it is possible (but very
misleading) to claim that the early IBM mainframe computers supported virtual memory: the
physical address was always the logical address.
This chapter discusses the mechanisms by which an executing S/370 assembler language
program generates a logical address that will later be converted to a physical address. While
later models of the IBM Mainframe line, such as the current z/10, make use of considerably
more complex mechanisms to generate logical addresses, the methods discussed here will
still work in a program executing on these more modern systems.
Perhaps the major difference between the early and current models in the IBM Mainframe
line is the size of logical address that can be generated. There are three different phases of
address generation: 24 bit, 31 bit, and 64 bit. The progress in evolution of the address space
is shown in the following table.
Address Space Year First Model
24 bits 1964 S/360 and early S/370
31 bits 1983 3081 processor running S/370–XA
64 bits 2000 zSeries model 900 running z/OS or z/VM
The curious reader might wonder why IBM elected to use a 31–bit address space rather than
a 32–bit address space when it introduced S/370–XA. The answer seems to have been a
desire to maintain compatibility with some of the instructions on the S/360.
This chapter will focus exclusively on the mechanisms used to generate the 24–bit logical
addresses in the S/360 and early S/370 models. As suggested above, there are 2 reasons.
1. Programs written in this mode will still run on the modern zSeries servers.
2. This simpler scheme illustrates the methods used in all systems to generate
addresses without getting lost in the complexity of a 64–bit address space.

Page 148 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

The topics in this chapter include the following.


1. A review of 32–bit binary arithmetic, as described by IBM.
2. A characterization of the sixteen general–purpose registers in the
System/370. Which are really general purpose?
3. Control sections and their relation to address calculation.
4. Base register addressing. Computing effective addresses.
5. Assigning and loading base registers.

32–bit binary arithmetic, as described by IBM.


The IBM System/370 architecture calls for sixteen general–purpose registers, numbered
0 through 15, or 0 through F in hexadecimal. Each of these registers can store a 32–bit
signed binary integer in two’s–complement form. The range of these integers is
–231 to 231 – 1, inclusive, or –2,147,483,648 through 2,147,483,6647.
The IBM standard calls for the bits in the registers to be numbered left to right. Notice that
this is not a standard used by other designs. In particular, it is not used in the lecture
material for other courses.
In the IBM notation, bit 0 is the sign bit. It is 1 for a negative number and 0 for a non–
negative. Consider a 32–bit integer. In some terminology, bit 0 is said to be the sign bit and
bits 1 – 31 are said to be data. Thus, what is often called a 32–bit signed integer might be
referenced in the IBM literature as a 31–bit integer. This is not the way I would say it,
but it is the terminology we shall use for this course.
To be specific, consider an eight–bit integer, which can store –128 through 127 as a
two’s–complement signed integer. All notations call for the bits to be numbered 0 through 7.
The bit labels would be as follows.
The IBM notation
Bit Number 0 1 2 3 4 5 6 7
Use Sign MSB LSB
The More Common Notation
Bit Number 7 6 5 4 3 2 1 0
Use Sign MSB LSB
For the IBM S/370 addressing scheme, there are two number systems that are significant.
Each is an unsigned number system, so that there are no negative values considered. These
systems are 12–bit unsigned integers and 24–bit unsigned integers. Each of these systems is
used in address computation.
The range of a 12–bit unsigned integer is from 0 through 212 – 1, or 0 through 4,095
inclusive, as 212 = 4,096.
The range of a 24–bit unsigned integer is from 0 through 224 – 1, or 0 through 16,777,215
inclusive, as 224 = 16,777,216.

Page 149 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

The General Purpose Registers


The general–purpose registers in the System/370 are identified by number: 0 – 15, or
0 – F in hexadecimal. Of these, only the ten registers 3 through 12 ( 3 – C in hexadecimal)
can be used for any purpose. The other six registers are “less general purpose” and should be
used with caution.
Registers 0 and 1 can be used as temporary registers, but calls to supervisor routines will
destroy their contents.
Register 2 can be used as a temporary and possibly as a base register.
The TRT (Translate and Test) instruction will change the value of this register.
Registers 13, 14, and 15 are used by the control programs and subprograms.
Each of the sixteen registers is identified by a four–bit binary number, or equivalently by a
single hexadecimal digit.
Suggested convention: Use register 12 as the single required base register.
The standard prefix code would contain the following sequence.
BALR 12, 0
USING *, 12
Within this scheme, only registers 3 through 11 (3 through B, in hexadecimal) are to be
viewed as truly general–purpose. All other registers have pre–assigned uses.
Recall that many programs will begin with some equate statements, in particular those that
give more useable symbolic names to registers. In this scheme, the above would appear as:
R12 EQU 12 Synonym for 12
Other declarations
BALR R12, 0
USING *, R12

Base Register Addressing


The System/370 uses a common design feature that splits addresses into two parts:
1. A base address, stored in a specified base register.
In general, only registers 3 through 12 should be used as base registers.
2. A displacement, specifying the positive offset (in bytes) from the start
of the section. The System/370 uses a 12–bit number for this displacement.
The displacement value is in the range 0 through 4095, inclusive.
The format of the address in this form is as follows:
|B|DDD|
where B is the single hexadecimal digit indicating the base register, and
“D D D” denotes the three hexadecimal digits used to specify the offset.
Suppose that general–purpose register 3 contains the value X’4500’.
The address reference 3507, interpreted as | 3 | 507 | refers to the address that is offset
X‘507’ from the value stored in the base register. The base register is 3, with contents
X‘4500’, so the value is X’4500’ + X’507’ = X’4A07’ In hexadecimal 5 + 5 = A.

Page 150 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

NOTE: Register 0 cannot be used as a base register. The assembler will interpret
the address | 0 | D D D | as no base register being used.
More on Register 0 As a Base Register
The bottom line is “Don’t try this (at home)”. In other words, any attempt to use register 0
for anything other than temporary results is likely to cause problems.
As noted above, some addresses are given in the form | B | D D D |, where
B is a hexadecimal digit indicating a base register, and
D D D is a set of three hexadecimal digits indicating an offset in the range 0 – 4095.
If the object code generated has the form | 0 | D D D |, then no base register is used in
computing the address. We shall use this later to load registers with positive constants.
One has another option that might force register 0 to be a base register. We can start the
program as follows.
BALR R0, 0
USING *, R0
While this MIGHT assemble correctly (I have no idea), it is most certainly a very bad idea.
Any call to a system procedure will disrupt the addressing.
Options: No Base Register vs. The Default Base Register
So far, we have considered only the object code form of a typical address. We now “jump
ahead” a bit and look at two typical instructions that use this address type.

One type of instruction, called “RS”, used for register–to–storage instructions.


Such an instruction has source code of the form OP R1,R3,D2(B2).
Such an instruction has object code of the form OP R1R3 B2D2 D2D2.
We look at LM, an interesting example of this format.
LM R1,R3,S2 loads multiple registers in the range R1 – R3 from the memory
location specified by S2, the address of which will be in the form | B2 | D2 D2 D2 |.
We now interpret the following code fragment.
BALR R12, 0 Establish register R12 (X‘C’)
USING *, R12 as the default base resister.
LM R5,R7,S2 might have object code 98 57 C1 00.
This uses the default base register.
LM R9,R11,S3(R3) Use R3 as an explicit base register.
might have object code 98 9B 31 40.
Object code such as 98 9B 0E 00 would call for use of an absolute address, not
computed from a base register. For this example, it is likely to be bad code.

Rationale for Base Register Addressing


There are two advantages of base/displacement addressing. One reason is still valid and one
shows an interesting history. Remember that the System/370 of the time admitted a 24–bit
address space, with addresses ranging from 0 through 224–1 or 0 through 16,777,215.

Page 151 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

A full 24–bit address would require 24 bits, or six hexadecimal digits, or three bytes.
The base register/displacement method of addressing allocates
4 bits to the base register
12 bits to the displacement
In this method, an address requires 16 bits, or two bytes. The instruction length is reduced
because each address requires only two bytes rather than three.
One might infer that some of the System/360 and System/370 installations had very little
memory. Indeed, some of the early S/360 systems shipped with only 128 KB of memory.

Base Register/Displacement Addressing: Relocating the Code


The second major advantage of base/displacement addressing still applies today.
The system facilitates program relocatability. Instead of assigning specific fixed storage
addresses, the assembler determines each address relative to a base address. At execute
time (after the program is loaded), the base address, which may be anywhere in storage, is
loaded into a base register.”
The standard prefix code
BALR 12, 0
USING *, 12
may be translated as follows:
1. What is my address?
2. Load that address into register 12 and use it as an base address in that register.
The other option for relocating code is to use a relocating loader to adjust fixed
address references to reflect the starting address of the code. This is also acceptable.
In the 1960’s, code that did not reference absolute addresses was thought to be superior.
Such code was called “position independent code”.

Base/Displacement vs. Indexed Addressing


Note the similarities with indexed addressing, in which the base is given by a variable and
the offset is given by a register. Systems that use the register contents as a base do so
because the registers can store larger numbers than the bits in the machine code.
For example, the System/360 allocates only 12 bits for the displacement, which is combined
with the contents of a register, which can be a 32–bit number. The MIPS–32, a design from
the mid 1980’s, also uses base/displacement addressing rather than indexed addressing.
In the MIPS–32 architecture, the displacement is a 16–bit signed integer, and the register
values are 32–bit numbers. This is basically the same idea, except that the displacement can
be a negative number. The range for the MIPS–32 is –32,768 through 32,767 inclusive.

Page 152 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Addressing: More Discussion


Here are some more examples of addressing using an index register and a base register.
All of these examples are taken from type RX instructions, which use indexing.
Each of these is a four–byte instruction of the form OP R1,D2(X2,B2). The format
of the object code is OP R1X2 B2D2 D2D2. Each byte contains two hexadecimal digits.
We interpret the 32–bit object code as follows.
OP This is an eight–bit operation code.
R1X2 This byte contains two hexadecimal digits, each of which is significant.
R1 denotes a register as the source or destination of the operation.
X2 denotes a general–purpose register to be used as an index register.
B2D2 D2D2 This contains the argument address as a base register and displacement.
Remember that the displacement, given by three hexadecimal digits, is treated as a
12–bit unsigned integer. In decimal, the limit is 0  Displacement  4095.
The general form by which an address is computed is
Contents (Base Register) + Contents (Index Register) + Displacement.
Some instructions do not use index register addressing.

Addressing: Example 1
Here is some object code for analysis.
58 40 C1 23
The first thing to note is that the opcode, 58, is that for L, a Register Load. This is a type RX
instruction with object code of the form OP R1X2 B2D2 D2D2.
As noted above, OP = 58.
We see that R1 = 4. It is register 4 that is being loaded from memory.
We see that X2 = 0. Indexed addressing is not used.
We also note that B2D2 D2D2 = C1 23, indicating an offset of X‘123’, or decimal 291, from
the address value stored in general–purpose register 12 (hexadecimal C).
Suppose that the value in general–purpose register 12 is X‘2500’. The effective
address for this instruction is then X‘2500’ + X‘123’ = X‘2623’.

Page 153 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Addressing: Example 2
Here is another example of object code.
58 A7 B1 25
The first thing to note is that the opcode, 58, is that for L, a Register Load. This
is a type RX instruction with object code of the form OP R1X2 B2D2 D2D2.
As noted above, OP = 58.
The hexadecimal digit for the register is A, indicating that register 10 is being loaded.
Recall that all of the digits in the object code are given in hexadecimal.
We see that X2 = 7, indicating that general–purpose register 7 is being used as an
index register.
We also note that B2D2 D2D2 = B1 25, indicating an offset of X‘125’ from the
address value stored in general–purpose register 11 (hexadecimal B).
Suppose the following: Register 11 contains X‘0012 4000’
The displacement is X‘0000 0125’
Register 7 contains X‘0000 0300’
The address is thus X‘0012 4425’

An Aside: When Is It NOT An Address?


Let’s look at the standard form used for a base & displacement address.
|B|DDD|
Technically, the 12–bit unsigned integer indicated by D D D is added to the contents of the
register indicated by B, and the results used as an address. There are instructions in which
the value so computed is just used as a value and not as an address. Consider the instruction
SLL R4,1, which is a Shift Left instruction. It is assembled as shown below.
000018 8940 0001 00001 48 SLL R4,1
The base register is 0, indicating that no base register is used. The “offset” is 1.
The value by which to shift is given as the sum, which is 1.
We could use a standard register to hold the value of the shift count, as in the following,
which uses R8 to hold the shift count.
000018 8940 8000 00001 48 SLL R4,0(R8)
NOTE: This is a good example of not using a “base register” in order to generate
an “absolute constant”, not relative to any address. Here, the value is a count.
Assigning and loading base registers.
If the program is to use a base register for base register/displacement addressing, that register
must be specified and provided with an initial value.

Page 154 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Again, the standard prefix code handles this.


BALR 12, 0
USING *, 12
If register 12 is used as a base register, it cannot be used for any other purpose.
In other words, your code should not reference register 12 explicitly.
We have two standards suggested for a base register. The textbook uses register 3
and one of our examples uses register 12. Pick one and use it consistently.

The Standard OS Prefix Code


Just to be complete, we show typical prefix code for running under OS.
This is taken from our lab 1.
LAB1 CSECT , COMMA REQUIRED IF COMMENT ON THIS STMT
**************************************************************
* STANDARD LINKAGE FOR A REUSABLE OS/MVS CSECT
* THIS USES REGISTER 12 AS A BASE REGISTER. THIS ASSUMES THAT
* THE SYMBOL R12 HAS BEEN DEFINED AS 12 IN A PRECEEDING EQU.
*************************************************************
SAVE (14,12) SAVE CALLER'S REGS
BALR R12,0 ESTABLISH
USING *,R12 ADDRESSABILITY
LA R2,SAVEAREA POINT TO MY LOWER-LEVEL SA
ST R2,8(,R13) FORWARD-CHAIN MINE FROM CALLER'S
ST R13,SAVEAREA+4 BACK-CHAIN CALLER'S FROM MINE
LR R13,R2 SET 13 FOR MY SUBROUTINE CALLS
********************** BEGIN LOGIC *************************

Relative Addressing
As we have seen, all symbolic addresses are based on variants of the concept of base address
(stored in a base register) and an offset. Note that the offset, encoded as a 12–bit unsigned
integer, is always non–negative. The possible offset values range from 0 through 4095.
We now introduce a way to reference a storage position relative to the symbolic address of
another label. This allows direct reference to unlabeled storage.
The form of a relative address is LABEL+N, where N is the byte offset of the desired
storage relative to the symbolic address associated with LABEL. Again, note the lack of
spaces in the relative address. This is important.
Consider the two data declarations.
F1 DC F‘0’ A four–byte full-word.
F2 DC F‘2’ Another full-word at address F1 + 4
Consider the following two instructions. They are identical.
L R6, F2
L R6, F1+4

Page 155 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Relative Addressing: A More Common Use


The most common use of relative addressing is to access an unlabeled section of a multi–byte
storage area associated with a symbolic address. Consider the following very common
declaration for card data. It sets aside a storage of 80 bytes to receive the 80 characters
associated with standard card input.
CARDIN DS CL80
While only the first byte (at offset 0 from CARDIN) is directly named, we may use relative
addressing to access any byte directly. Consider this figure.

The second byte of input it is at address CARDIN+1, the third at CARDIN+2, etc.
Remember that the byte at address CARDIN+N is the character in column (N + 1) of the
card. Punched cards do not have a column 0, so valid addresses in this case range from
CARDIN through (CARDIN + 79).

Digression: Labels and Addresses


While we use labels to indicate addresses, we must recall that no label has an explicit data
type associated with it when the program is run. Each definition serves only to set aside
memory. The actual data type is associated with the assembly language operation.
Consider the following declarations and assume that the addresses are sequential. In these
examples, each is defined as hexadecimal, so that we can more easily see the problem.
FW1 DC X‘1234 ABCD’
HW1 DC X‘8888’ AT ADDRESS F1+4
HW2 DC X‘7777’ AT ADDRESS F1+6
The fullword at address FW1 has value X‘1234 ABCD’.
The halfword at address FW1 has value X‘1234’.
The halfword at address FW1+2 has value X‘ABCD’.
The halfword at address HW1 has value X‘8888’.
The halfword at address HW2 has value X‘7777’.
The fullword at address HW1 has value X‘8888 7777’.
Again, note that it does not matter that FW1 was intended to be a fullword or that each of
HW1 and HW2 to be a halfword. It is the instruction that matters.

Page 156 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Explicit Base Addressing for Character Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 271 – 273].
Assume that general–purpose register 4 is being used as the base register, as assigned at
the beginning of the CSECT. Assume also that the following statements hold.
1. General purpose register 4 contains the value X‘8002’.
2. The label PRINT represents an address represented in base/offset form as 401A; that
is it is at offset X‘01A’ from the value stored in the base register, which is R4.
The address then is X‘8002’ + X‘01A’ = X‘801C’.
3. Given that the decimal number 60 is represented in hexadecimal as X‘3C’,
the address PRINT+60 must then be at offset X‘01A’ + X‘3C’ = X‘56’ from
the address in the base register. X‘A’ + X‘C’, in decimal, is 10 + 12 = 16 + 6.
Note that this gives the address of PRINT+60 as X‘8002’ + X‘056’ = X‘8058’,
which is the same as X‘801C’ + X‘03C’. The sum X‘C’ + X‘C’, in decimal, is
represented as 12 + 12 = 24 = 16 + 8.
4. The label ASTERS is associated with an offset of X‘09F’ from the value in the
base register; thus it is located at address X‘80A1’. This label references a storage
of two asterisks. As a decimal value, the offset is 159.
5. That only two characters are to be moved by the MVC instruction examples to be
discussed. Since the length of the move destination is greater than 2, and since the
length of the destination is the default for the number of characters to be moved, this
implies that the number of characters to be moved must be stated explicitly.
The first example to be considered has the simplest appearance. It is as follows:
MVC PRINT+60(2),ASTERS
The operands here are of the form Destination(Length),Source.
The destination is the address PRINT+60. The length (number of characters
to move) is 2. This will be encoded in the length byte as X‘01’, as the length
byte stores one less than the length. The source is the address ASTERS.
As the MVC instruction is encoded with opcode X‘D2’, the object code here is as follows:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 40 56 40 9F
The next few examples are given to remind the reader of other ways to encode
what is essentially the same instruction.

Page 157 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

These examples are based on the true nature of the source code for a MVC instruction, which
is MVC D1(L,B1),D2(B2). In this format, we have the following.
1. The destination address is given by displacement D1 from the address stored in
the base register indicated by B1.
2. The number of characters to move is denoted by L.
3. The source address is given by displacement D2 from the address stored in
the base register indicated by B2.
The second example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT+60 GET ADDRESS PRINT+60 INTO R8
MVC 0(2,8),ASTERS MOVE THE CHARACTERS
Note the structure in the destination part of the source code, which is 0(2,8).

The displacement is 0 from the address X‘8058’, which is stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 00 40 9F
The instruction could have been written as MVC 0(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.
The third example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT GET ADDRESS PRINT INTO R8
MVC 60(2,8),ASTERS SPECIFY A DISPLACEMENT
Note the structure in the destination part of the source code, which is 60(2,8).

The displacement is 60 from the address X‘801C’, stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 3C 40 9F
The instruction could have been written as MVC 60(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.

Page 158 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

Explicit Base Addressing for Packed Decimal Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 273 & 274].
Consider the following source code, taken from Abel. This is based on a conversion of a
weight expressed in kilograms to its equivalent in pounds; assuming 1kg. = 2.2 lb. Physics
students will please ignore the fact that the kilogram measures mass and not weight.
ZAP POUNDS,KGS MOVE KGS TO POUNDS
MP POUNDS,FACTOR MULTIPLY BY THE FACTOR
SRP POUNDS,63,5 ROUND TO ONE DECIMAL PLACE

KGS DC PL3‘12.53’ LENGTH 3 BYTES


FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
The value produced is 12.532.2 = 27.566, which is rounded to 27.57.
The instructions we want to examine in some detail are the MP and ZAP, each of which
is a type SS instruction with source code format OP D1(L1,B1),D2(L2,B2). Each of
the two operands in these instructions has a length specifier.
In the first example of the use of explicit base registers, we assign a base register to
represent the address of each of the arguments. The above code becomes the following:
LA R6,KGS ADDRESS OF LABEL KGS
LA R7,FACTOR ADDRESS
LA R8,POUNDS
ZAP 0(5,8),0(3,6)
MP 0(5,8),0(2,7)
SRP 0(5,8),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 0(5,8),0(3,6) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 0(5,8),0(2,7) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R7. The source has length 2 bytes.

Page 159 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Addressing

But recall the order in which the labels are declared. The implicit assumption that the labels
are in consecutive memory locations will here be made explicit.
KGS DC PL3‘12.53’ LENGTH 3 BYTES
FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
In this version of the code, we use the label KGS as the base address and reference all other
addresses by displacement from that one. Here is the code.
LA R6,KGS ADDRESS OF LABEL KGS
ZAP 5(5,6),0(3,6)
MP 5(5,6),3(2,6)
SRP 5(5,6),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 5(5,6),0(3,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 5(5,6),3(2,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 3 from the address stored
in R6. The source has length 2 bytes.
In other words, the base/displacement 6000 refers to a displacement of 0 from the address
stored in register 6, which is being used as an explicit base register for this operation. As
the address in R6 is that of KGS, this value represents the address KGS. This is the object
code address generated in response to the source code fragment 0(3,6).
The base/displacement 6003 refers to a displacement of 3 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+3, which is the address FACTOR. This is
the object code address generated in response to the source code fragment 3(2,6).
The base/displacement 6005 refers to a displacement of 5 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+5, which is the address POUNDS. This is
the object code address generated in response to the source code fragment 5(5,6).
It is worth notice, even at this point, that the use of a single register as the base from which to
reference a block of data declarations is quite suggestive of what is done with a DSECT, also
called a “Dummy Section”.

Page 160 Chapter 8 Revised June 27, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 9: Instruction Formats

One of the major design decisions undertaken by computer architects is the choice of formats
for the binary machine language instructions. The basic question revolves around the length
of the instruction. Should all instructions have the same length, or should a variety of
instruction lengths be allowed. This question is essentially a trade–off between complexity
of the control unit and efficient use of memory space.
More bluntly, the big issue is the cost of random access memory for a computer. In the early
1960’s, memory was quite expensive. As an example, consider that a fully equipped NCR
mainframe, shipped in 1966, had only 256 KB of memory, which cost $100,000 ($400,000
per megabyte). As late as 1979, memory cost was $75,000 per megabyte. As a result, a
small System/360 might ship with only 16 KB to 64 KB installed. Within that context, the
design emphasis was on an instruction set that made the most efficient use of memory.
For this reason, the S/360 instruction set provides for instruction lengths of 2 bytes, 4 bytes,
and 6 bytes. This resulted in six instruction classes, each with an encoding scheme that
allowed the maximum amount of information to be specified in a small number of bytes.
These formats are classified by length in bytes, use of the base registers, and object code
format. The five instruction classes of use to the general user are listed below.
Format Length Use
Name in bytes
RR 2 Register to register transfers.
RS 4 Register to storage and register from storage
RX 4 Register to indexed storage and register from indexed storage
SI 4 Storage immediate
SS 6 Storage–to–Storage. These have two variants,
each of which we shall discuss soon.
Before we launch on a formal description of these formats, it might be helpful to give some
informal comments. We begin by noting that the opcode (machine code representation) of
each instruction has a length of exactly one byte. With 8 bits to represent the opcode, this
allows for 256 different operations, more if an extra encoding scheme is used.
Consider the register–to–register instructions. Since there are only 16 registers, each register
can be fully specified by a 4–bit hexadecimal digit, and one byte will suffice to specify the
two registers. Thus, the specification of one operation and two registers would require only 2
bytes. For this reason, the type RR instructions are encoded into two bytes of memory.
Consider now the mechanism used to specify an address. It calls for a base register (encoded
in 4 bits) and a 12–bit address offset (encoded in 12 bits), for a total of 16 bits or two bytes.
Given that the operation must specify a source or destination register, the sum grows to 20
bits. With the addition of an 8–bit opcode, the total grows to 28 bits, or 3.5 bytes. As
fractional bytes cannot be accommodated in memory, the total is increased to four bytes and
the instruction expanded to include two registers. The encoding is then 8 bits for the opcode,
8 bits for two source/destination registers, and 16 bits for the address: 4 bytes in all.

Page 161 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

Branch Instructions
One of the encodings used to minimize the instruction size is to use the idea of a condition
mask to extend two basic branch instructions into fourteen equivalent branch instructions.
This device is often called “syntactic sugar” or extended mnemonics. There are two basic
branch instructions in the IBM instruction set.
BC MASK,TARGET A TYPE RX INSTRUCTON
BCR MASK,REGISTER A TYPE RR INSTRUCTION
In the Type RX instruction, the target address is computed using the base register and
displacement method, with an optional index register: D2(X2,B2). In the Type RR
instruction, the target address is found as the contents of the register.
Each of these instruction formats uses a four–bit mask, with bit numbers based on the 2–bit
value of the condition code in the PSW, to determine the conditions under which the branch
will be taken. The mask should be considered as having bits numbered left to right as 0 – 3.
Bit 0 is the equal/zero bit. Bit 2 is the high/plus bit.
Bit 1 is the low/minus bit. Bit 3 is the overflow bit.

The Standard Combinations


The following table shows the standard conditional branch instructions and their translation
to the BC (Branch on Condition). The same table applies to BCR (Branch on Condition,
Register), so that there is another complete set of mnemonics for that set.
Bit Mask Flags Condition Extended instructions
0 1 2 3 Sort Arithmetic
0 0 0 0 No branch BC 0,XX NOP
0 0 0 1 Bit 3: Overflow BC 1,XX BO XX
0 0 1 0 Bit 2: High/Plus BC 2,XX BH XX BP
0 1 0 0 Bit 1: Low/Minus BC 4,XX BL XX BM
0 1 1 1 1, 2, 3: Not Equal BC 7,XX BNE XX BNZ
1 0 0 0 Bit 0: Equal/Zero BC 8,XX BE XX BZ
1 0 1 1 0, 2, 3: Not Low BC 11.XX BNL XX BNM
1 1 0 1 0, 1, 3: Not high BC 13,XX BNH XX BNP
1 1 1 1 0, 1, 2, 3: Any BC 15,XX B XX

Note the two sets of extended mnemonics: one for comparisons and an equivalent
set for the results of arithmetic operations.
These equivalent sets are provided to allow the assembler code to read more naturally.

Page 162 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

The Idea of a Sort Order


Two data items of a specific data type are said to be “comparable” if they can be subjected to
some sort of comparison operator with well defined results. The order used depends on the
data type of the operands being compared. Note that it is not a valid operation to attempt
comparison of operands of different data types. The basic comparison types are character
(using EBCDIC code order), packed decimal, integer, and floating point.
One common operator that can be applied to many operations is that of equality, denoted
“=”. The negation of equality is inequality, denoted “”. Remember that the assembler
language syntax includes none of these algebraic symbols.
We also are interested in other comparisons, implied by what is called a “sort order”.
Given two data items of the same type, it is convenient to define three operators.
A > B if A follows B in the sort order.
A = B if A and B occupy the same place in the sort order.
A < B if A precedes B in the sort order.
Remember that each of these operators has an “opposite”.
If A > B then not A  B. Assembler pair: BH and BNH
If A = B then not A  B. Assembler pair: BE and BNE
If A < B then not A  B. Assembler pair: BL and BNL
Overflow: “Busting the Arithmetic”
Consider the half–word integer arithmetic in the IBM System/360. Integers in this format are
16–bit two’s complement integers with a range of – 32,768 to 32,767
Consider the following addition problem: 24576 + 24576.
Now + 24,576 (binary 0110 0000 0000 0000) is well within the range.
0110 0000 0000 0000 24576
0110 0000 0000 0000 24576
1100 0000 0000 0000 – 16384
What happened? We had a carry into the sign bit. This is “overflow”. The binary
representation being used cannot handle the result. On the System/360, such an invalid
operation will set the overflow bit.
Note that this sum will work very well in both 32–bit fullword arithmetic, as the true result is
well within the range. It would also work in unsigned 16–bit arithmetic, except that the
S/360 does not support that mode. Note that 24,576 + 24,576 = 49,152 = 32768 + 16384.
This is the origin of the strange result from 16–bit signed arithmetic.
In mathematical terms, we would note that computers do not represent integers, but only a
finite subset of the infinite set of integers.
Having discussed the branch instructions, let us now discuss the instruction formats.

Page 163 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

The Object Code Format


Here is a table summarizing the formats of the five instruction types. Note that the fifth type
has two variants, each of which will be explored in due turn.
Format Length Explicit operand
form
1 2 3 4 5 6
RR 2 R1,R2 OP R1 R2
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
SI 4 D1(B1),I2 OP I2 B1 D1 D1D1
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
SS(2) 6 D1(L1,B1),D2(L2,B2) OP L1 L2 B1 D1 D1D1 B2 D2 D2D2
NOTES: OP is the 8–bit operation code.
R1 R2 and R1 X2 each denote two 4–bit fields to specify two registers.
The two byte entry of the form B D D D denotes a 4–bit field to specify a
base register and three 4–bit fields (12 bits) to denote a 12–bit displacement.
L denotes an 8–bit field for operand length (256 bytes maximum).
L1 and L2 each denote a 4–bit field for an operand length (16 bytes max.).
I denotes an 8–bit (one byte) immediate operand. These are useful.

RR (Register–to–Register) Format
This is a two–byte instruction of the form OP R1,R2.
Type Bytes Operands
RR 2 R1,R2 OP R1 R2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number.
This instruction format is used to process data between registers.
Here are some examples.
AR 6,8 1A 68 Adds the contents of register 8 to register 6.
AR 10,11 1A AB Adds the contents of register 11 to register 10.
AR R6,R8 1A 68 Due to the standard Equate statements we use
in our program assignments,
R6 stands for 6 and R8 for 8.

Page 164 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

RR (Register–to–Register) Format: Branch Instructions


There are two formats used with conditional branching instructions.
The BCR (Branch on Condition Register) instruction uses a modified form of the RR format.
The BC (Branch on Condition) uses the RX format.
The BCR instruction is a two–byte instruction of the form OP M1,R2.
Type Bytes Operands
RR 2 M1,R2 07 M1 R2
The first byte contains the 8–bit instruction code, which is X‘07’.
The second byte contains two 4–bit fields.
The first 4–bit field encodes a branch condition
The second 4–bit fields encodes the number of the register containing
the target address for the branch instruction.
For example, the instruction BR R8 is the same as BCR 15,R8.
The object code is 07 F8. Branch unconditionally to the address in register 8.
We shall discuss the BC and BCR instructions in more detail at a later lecture.

RS (Register–Storage) Format
This is a four–byte instruction of the form OP R1,R3,D2(B2).
Type Bytes Operands 1 2 3 4
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number.
Note that some RS format instructions use only one register, here R3 is set to 0.
In this instruction format, “0” is taken as no register, rather than register R0.
The third and fourth byte contain a 4–bit register number and 12–bit displacement,
used to specify the memory address for the operand in storage.
Recall that each label in the assembly language program references an address,
which must be expressed in the form of a base register with displacement.
Any address in the format of base register and displacement will appear in the form.
B D1 D2 D3
B is the hexadecimal digit representing the base register.
The three hexadecimal digits D1 D2 D3 form the 12–bit displacement.

Page 165 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

RS (Register–Storage) Format Examples


These are four–byte instructions of the form OP R1,R3,D2(B2).
Type Bytes Operands 1 2 3 4
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2
1. Load Multiple Operation code = X‘98’.
Suppose the label FW3 (supposedly holding three 32–bit full–words) is at an
address specified by offset X‘100’ from base register R7. Then we have
LM R5,R7,FW3 98 57 71 00
Unpacking the object code, we again find the parts.
The operation code is X‘98’, which indicates a multiple register load.
The next byte has value X‘57’, which indicates two registers: R5 and R7.
Here it is used to represent a range of three registers: R5, R6, and R7.
The last two bytes contain the address of the label FW3. The two bytes 71 00 indicate
1) that the base address is contained in register R7, and
2) that the displacement from the base address is X‘100’.
2. The above example with an explicit base register.
LA R4,FW3 Load the address FW3 into R4
LM R5,R7,0(4) The address is displaced 0 from the
value in R4, the explicit base register
One might have an instruction of the following form, which is not equivalent to the above.
LM R5,R7,12(4) The address is displaced 12 (X‘C’) from
the value in R4

3. Shift Left Logical Operation code = X‘89’


This is also a type RS instruction, though the appearance of a typical use seems to deny
this. Consider the following instruction which shifts R6 left by 12 bits.
SLL R6, 12 Again, I assume we have set R6 EQU 6
The deceptive part concerns the value 12, used for the shift count. Where is that stored?
The answer is that it is not stored, but assembled in the form of a displacement of 12
to a base register of 0, indicating that no base register is used.
The above would be assembled as 89 60 00 0C Decimal 12 is X‘C’
Here are three lines from a working program I wrote on 2/23/2009.
000014 5840 C302 00308 47 L R4,=F'1'
000018 8940 0001 00001 48 SLL R4,1
00001C 8940 0002 00002 49 SLL R4,2

Page 166 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

RX (Register–Indexed Storage) Format


This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number.
In order to illustrate this, consider the following data layout.
FW1 DC F‘31’
DC F‘100’ Note that this full word is not labeled
Suppose that FW1 is at an address defined as offset X‘123’ from register 12.
As hexadecimal C is equal to decimal 12, the address would be specified as C1 23.
The next full word might have an address specified as C1 27, but we shall show
another way to do the same thing. The code we shall consider is
L R4,FW1 Load register 4 from the full word at FW1.
The operation code is X‘58’.
AL R4,FW1+4 Add the value at the next full word address.
The operation code is X‘5E’.
The load instruction, remembering that the address of FW1 is specified as C1 23.
The base register is R12, the displacement is X‘123’, and there is no index register;
so we have 58 40 C1 23
The next instruction is similar, except for its operation code, which is 5E 40 C1 27.
In each of the examples above, the 4–bit value X2 = 0. When a 0 is found in the index
position, that indicates that indexed addressing is not used. Register 0 cannot be used as
either a base register or an index register.

RX Format (Using an Index Register)


Here we shall suppose that we want register 7 to be an index register. Consider the three line
sequence of instructions, in which R7 is given the value 4 to index from address FW1.
L R7,=F‘4’ Register 7 gets the value 4.
L R4,FW1 Operation code is X‘58’.
AL R4,FW1(R7) Operation code is X‘5E’.
The object code for the last two instructions is now.
58 40 C1 23 This address is at displacement 123
from the base address, which is in R12.
Note X2 = 0, indicating no indexing.
5E 47 C1 23 R7 contains the value 4.
The address is at displacement 123 + 4
or 127 from the base address, in R12.

Page 167 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

More on “Index Register 0”


Consider the instruction
L R4,FW1 Operation code is X‘58’.
The object code for this instruction is of the form
58 40 C1 23
The second byte of the instruction has the destination register set as 4 (either decimal
or hexadecimal; you choose), and the “index register” set to 0.
The intent of the instruction is that indexed addressing not be invoked.
There are two common ways to handle this addressing procedure.
1. The solution chosen by IBM is that the 0 indicates “do not index”, and
that the value of register R0 is not used or changed.
2. Another common solution, tried as early as the CDC–6600, is to specify
that register R0 stores the constant 0; R0  0.
The 0 in the index register position would then indicate “index by R0”, that is
to add 0 to the base–displacement address; in other words, no indexing.
Each method has its advantages. The second simplifies design of the control unit.

RX (Register–Indexed Storage): Explicit Base Register


This is a four–byte instruction of the form OP R1,D2(X2,B2).
The second byte contains two 4–bit fields, each of which encodes a register number. The
first hexadecimal digit, denoted R1, identifies the register to be used as either the source or
destination for the data. The second hexadecimal digit, denoted X2, identifies the register to
be used as the index. If the value is 0, indexed addressing is not used.
The third and fourth bytes contain a standard address in base/displacement format. We now
consider the source code formats that use an explicit base register.
As an examples of this type, we consider the two following instructions:
L Load Fullword Opcode is X‘58’
A Add Fullword Opcode is X‘5A’
We consider a number of examples based on the following data declarations. Note that the
data are defined in consecutive fullwords in memory, so that fixed offset addressing can be
employed. Each fullword has a length of four bytes.
DAT1 DC F‘1111’
DAT2 DC F‘2222’ AT ADDRESS (DAT1 + 4)
DAT3 DC F‘3333’ AT ADDRESS (DAT2 + 4) OR (DAT1 + 8)
A standard code block might appear as follows.
L R5,DAT1
A R5,DAT2
A R5,DAT3 NOW HAVE THE SUM.

Page 168 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

One variant of this code might be the following. See page 92 of R_17.
LA R3,DAT1 GET ADDRESS INTO R3
L R5,0(,3) LOAD DAT1 INTO R5
A R5,4(,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,8(,3) ADD DAT3, AT ADDRESS DAT1+8.
Note the leading comma in the construct (,3), which is of the form (Index, Base). This
indicates that no index register is being used, but that R3 is being used as a base register. It is
synonymous with (0,3), which might be a preferable usage.
Here is another variant of the above code.
LA R3,DAT1 GET ADDRESS INTO R3
LA R8,4 VALUE 4 INTO REGISTER 8
LA R9,8 VALUE 8 INTO REGISTER 9
L R5,0(0,3) LOAD DAT1 INTO R5
A R5,0(8,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,0(9,3) ADD DAT3, AT ADDRESS DAT1+8.
Here is yet another variant of the above code.
LA R3,DAT1 GET ADDRESS INTO R3
LA R8,4 VALUE 4 INTO REGISTER 8
L R5,0(0,3) LOAD DAT1 INTO R5
A R5,0(8,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,4(8,3) ADD DAT3, AT ADDRESS DAT1+4+4.
The last line uses a displacement (the integer 4) from an indexed address (R8 is the index
register) formed with an explicit base register (R3). It is a rather strange construct.

RX Format (Branch on Condition)


The BC (Branch on Condition) is a 4–byte instruction of the form
OP M1,D2(X2,B2). Its operation code is X‘47’. Once again, the format is as follows.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) 47 M1 X2 B2 D2 D2D2

The first byte contains the 8–bit instruction code, which is X‘47’.
The second byte contains two 4–bit fields.
The first four bits contain the mask for the branch condition codes
The second four bits contain the number of the index register used
in computing the address of the jump target.
The next two bytes contain the 4–bit number of the base register and the
12–bit displacement used to form the unindexed address of the branch target.
Suppose that address TARGET is formed by offset X‘666’ using base register 8.
No index is used and the instruction is BNE TARGET, equivalent to BC 7,TARGET,
as the condition mask for “Not Equal” is the 4–bit number 0111, or decimal 7.
The object code for this is 47 70 86 66.

Page 169 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

SI (Storage Immediate) Format


This is a four–byte instruction of the form OP D1(B1),I2.
Type Bytes Operands 1 2 3 4
SI 4 D1(B1), I2 OP I2 B1 D1 D1D1
The first byte contains the 8–bit instruction code.
The second byte contains the 8–bit value of the second operand, which is treated as an
immediate operand. The instruction contains the value of the operand, not its address.
The first operand is an address, specified in standard base register and displacement form.
Two instances of the instruction are :
MVI Move Immediate
CLI Compare Immediate
Suppose that the label ASTER is associated with an address that is specified using
register R3 as a base register, with X‘6C4’ as offset.
The operation code for MVI is X‘92’ and the EBCDIC for ‘*” is X‘5C’.
MVI ASTER,C ‘*’ is assembled as 92 5C 36 64.

The Storage–to–Storage Instructions


There are two formats for the SS (Storage–to–Storage) instructions. Each of the formats
requires six bytes for the instruction object code. The two types of the SS are as follows:
1. The Character Instructions
These are of the form OP D1(L,B1),D2(B2), which provide a length
for only operand 1. The length is specified as an 8–bit byte.
Examples: MVC Move Characters
CLC Compare Characters

2. The Packed Decimal Instructions


These are of the form OP D1(L1,B1),D2(L2,B2), which provide
a length for each of the two operands. Each length is specified as a
4–bit hexadecimal digit.
Examples: ZAP Zero and Add Packed (Move Packed)
AP Add Packed
CP Compare Packed

Storage–to–Storage: Length Fields


Consider the two formats used to store a length in bytes. These are a four–bit hexadecimal
digit and an eight–bit byte. Four bits will store an unsigned integer in the range 0 through 15.
Eight bits will store an unsigned integer in the range 0 through 255. However, a length of 0
bytes is not reasonable for an operand. For this reason, the value stored is the one less than
the length of the operand.

Page 170 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

Field Value Operand


Size Stored Length
Four bits 0 – 15 1 – 16 bytes
Eight bits 0 – 255 1 – 256 bytes
By examination of all instruction formats, we can show that only the SS
(Storage–to–Storage) format instructions require length codes.

Storage–to–Storage: Character Instructions


These are of the form OP D1(L,B1),D2(B2), which provide a length for only operand 1.
The length is specified as an 8–bit byte.
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code, say X‘D2’ for MVC or X‘D5’ for CLC.
The second byte contains a value storing one less than the length of the first operand,
which is the destination for any move. Bytes 3 and 4 specify the address of the first operand,
using the standard base register and displacement format. Bytes 5 and 6 specify the address
of the second operand, using the standard base register and displacement format.
It is quite common for both operands to use the same base register.

Example of Character Instructions


Consider the example assembly language statement, which moves the string of characters at
label CONAME to the location associated with the label TITLE.
MVC TITLE,CONAME
Suppose that: 1. There are fourteen bytes associated with TITLE, say that it was
declared as TITLE DS CL14. Decimal 14 is hexadecimal E.
2. The label TITLE is referenced by displacement X‘40A’
from the value stored in register R3, used as a base register.
3. The label CONAME is referenced by displacement X‘42C’
from the value stored in register R3, used as a base register.
Given that the operation code for MVC is X‘D2’, the instruction assembles as
D2 0D 34 0A 34 2C Length is 14 or X‘0E’; L – 1 is X‘0D’

Page 171 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

Explicit Base Addressing for Character Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 271 – 273].
Assume that general–purpose register 4 is being used as the base register, as assigned at
the beginning of the CSECT. Assume also that the following statements hold.
1. General purpose register 4 contains the value X‘8002’.
2. The label PRINT represents an address represented in base/offset form as 401A; that
is it is at offset X‘01A’ from the value stored in the base register, which is R4.
The address then is X‘8002’ + X‘01A’ = X‘801C’.
3. Given that the decimal number 60 is represented in hexadecimal as X‘3C’,
the address PRINT+60 must then be at offset X‘01A’ + X‘3C’ = X‘56’ from
the address in the base register. X‘A’ + X‘C’, in decimal, is 10 + 12 = 16 + 6.
Note that this gives the address of PRINT+60 as X‘8002’ + X‘056’ = X‘8058’,
which is the same as X‘801C’ + X‘03C’. The sum X‘C’ + X‘C’, in decimal, is
represented as 12 + 12 = 24 = 16 + 8.
4. The label ASTERS is associated with an offset of X‘09F’ from the value in the
base register; thus it is located at address X‘80A1’. This label references a storage
of two asterisks. As a decimal value, the offset is 159.
5. That only two characters are to be moved by the MVC instruction examples to be
discussed. Since the length of the move destination is greater than 2, and since the
length of the destination is the default for the number of characters to be moved, this
implies that the number of characters to be moved must be stated explicitly.
The first example to be considered has the simplest appearance. It is as follows:
MVC PRINT+60(2),ASTERS
The operands here are of the form Destination(Length),Source.
The destination is the address PRINT+60. The length (number of characters
to move) is 2. This will be encoded in the length byte as X‘01’, as the length
byte stores one less than the length. The source is the address ASTERS.
As the MVC instruction is encoded with opcode X‘D2’, the object code here is as follows:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 40 56 40 9F
The next few examples are given to remind the reader of other ways to encode
what is essentially the same instruction.

Page 172 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

These examples are based on the true nature of the source code for a MVC instruction, which
is MVC D1(L,B1),D2(B2). In this format, we have the following.
1. The destination address is given by displacement D1 from the address stored in
the base register indicated by B1.
2. The number of characters to move is denoted by L.
3. The source address is given by displacement D2 from the address stored in
the base register indicated by B2.
The second example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT+60 GET ADDRESS PRINT+60 INTO R8
MVC 0(2,8),ASTERS MOVE THE CHARACTERS
Note the structure in the destination part of the source code, which is 0(2,8).

The displacement is 0 from the address X‘8058’, which is stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 00 40 9F
The instruction could have been written as MVC 0(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.
The third example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT GET ADDRESS PRINT INTO R8
MVC 60(2,8),ASTERS SPECIFY A DISPLACEMENT
Note the structure in the destination part of the source code, which is 60(2,8).

The displacement is 60 from the address X‘801C’, stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 3C 40 9F
The instruction could have been written as MVC 60(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.

Page 173 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

Storage–to–Storage: Packed Decimal Instructions


These are of the form OP D1(L1,B1),D2(L2,B2), which provide a 4–bit number
representing the length for each of the two operands.
Type Bytes Operands 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) OP L1 L2 B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code, say X‘FA’ for AP or X‘F9’ for CP.
The second byte contains a two values, each a 4–bit binary number (one hex digit).
L1 A value that is one less than the length of the first operand.
L2 A value that is one less than the length of the second operand.
Bytes 3 and 4 specify the address of the first operand, using the standard base register and
displacement format. Bytes 5 and 6 specify the address of the second operand, using the
standard base register and displacement format. IBM will frequently call these decimal
instructions. Here are two lines from the standard reference card, officially called FORM
GX20–1850.
AP Decimal Add CP Compare Decimal

Example of Packed Decimal Instructions


Consider the assembly language statement below, which adds AMOUNT to TOTAL.
AP TOTAL,AMOUNT
Assume: 1. TOTAL is 4 bytes long, so it can hold at most 7 digits.
2. AMOUNT is 3 bytes long, so it can hold at most 5 digits.
3. The label TOTAL is at an address specified by a displacement
of X‘50A’ from the value in register R3, used as a base register.
4. The label AMOUNT is at an address specified by a displacement
of X‘52C’ from the value in register R3, used as a base register.
The object code looks like this: FA 32 35 0A 35 2C
Consider FA 32 35 0A 35 2C. The operation code X‘FA’ is that for the Add Packed
(Add Decimal) instruction, which is a type SS(2). The above format applies.
The field 32 is of the form L1 L2.
The first value is X‘3’, or 3 decimal. The first operand is 4 bytes long.
The second value is X‘2’, or 2 decimal. The second operand is 3 bytes long.
The two–byte field 35 0A indicates that register 3 is used as the base register for the first
operand, which is at displacement X‘50A’. The two–byte field 35 2C indicates that
register 3 is used as the base register for the second operand, which is at displacement
X‘52C’. It is quite common for both operands to use the same base register.

Page 174 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

Explicit Base Addressing for Packed Decimal Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 273 & 274].
Consider the following source code, taken from Abel. This is based on a conversion of a
weight expressed in kilograms to its equivalent in pounds; assuming 1kg. = 2.2 lb. Physics
students will please ignore the fact that the kilogram measures mass and not weight.
ZAP POUNDS,KGS MOVE KGS TO POUNDS
MP POUNDS,FACTOR MULTIPLY BY THE FACTOR
SRP POUNDS,63,5 ROUND TO ONE DECIMAL PLACE

KGS DC PL3‘12.53’ LENGTH 3 BYTES


FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
The value produced is 12.532.2 = 27.566, which is rounded to 27.57.
The instructions we want to examine in some detail are the MP and ZAP, each of which
is a type SS instruction with source code format OP D1(L1,B1),D2(L2,B2). Each of
the two operands in these instructions has a length specifier.
In the first example of the use of explicit base registers, we assign a base register to
represent the address of each of the arguments. The above code becomes the following:
LA R6,KGS ADDRESS OF LABEL KGS
LA R7,FACTOR ADDRESS
LA R8,POUNDS
ZAP 0(5,8),0(3,6)
MP 0(5,8),0(2,7)
SRP 0(5,8),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 0(5,8),0(3,6) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 0(5,8),0(2,7) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R7. The source has length 2 bytes.

Page 175 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Instruction Formats

But recall the order in which the labels are declared. The implicit assumption that the labels
are in consecutive memory locations will here be made explicit.
KGS DC PL3‘12.53’ LENGTH 3 BYTES
FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
In this version of the code, we use the label KGS as the base address and reference all other
addresses by displacement from that one. Here is the code.
LA R6,KGS ADDRESS OF LABEL KGS
ZAP 5(5,6),0(3,6)
MP 5(5,6),3(2,6)
SRP 5(5,6),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 5(5,6),0(3,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 5(5,6),3(2,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 3 from the address stored
in R6. The source has length 2 bytes.
In other words, the base/displacement 6000 refers to a displacement of 0 from the address
stored in register 6, which is being used as an explicit base register for this operation. As
the address in R6 is that of KGS, this value represents the address KGS. This is the object
code address generated in response to the source code fragment 0(3,6).
The base/displacement 6003 refers to a displacement of 3 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+3, which is the address FACTOR. This is
the object code address generated in response to the source code fragment 3(2,6).
The base/displacement 6005 refers to a displacement of 5 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+5, which is the address POUNDS. This is
the object code address generated in response to the source code fragment 5(5,6).
It is worth notice, even at this point, that the use of a single register as the base from which to
reference a block of data declarations is quite suggestive of what is done with a DSECT, also
called a “Dummy Section”.

Page 176 Chapter 9 Revised June 28, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 10: Handling Character Data

Processing Character Data


We now discuss the definitions and uses of character data in an IBM Mainframe computer.
By extension, we shall also be discussing zoned decimal data. Character data and zoned
decimal data are stored as eight–bit bytes. These eight–bit bytes are seen by IBM as being
organized into two parts. This division is shown in the following table.
Portion Zone Numeric
Bit 0 1 2 3 4 5 6 7

There are two things to note about this table. The first is the bit numbering scheme used by
IBM, in which the leftmost bit in an item is always bit 0. IBM seems to be unique in this bit
numbering scheme; almost all others label the rightmost bit as bit 0.
One might wonder about the nomenclature “zone” and “numeric”. In order to understand
why these names are given, we must recall the format of an IBM 026 punch card. The point
here is that the EBCDIC (Extended Binary Coded Decimal Interchange Code) encoding was
designed for compatibility with the IBM 029 punch card codes which evolved from the IBM
026 punch card code illustrated below.

Note the structure of the column punches for the alphabetic character set. Each letter is
represented by a punch in either column 11 or 12 (the zone punch) and a punch in one of the
columns numbered 0 through 9 (the numeric punch). While the digits are represented by a
single punch, the requirement to have a full–byte representation in the character code has
lead to their being assigned a zone code as well.
As noted in a previous chapter, the EBCDIC coding scheme was designed with the specific
goal of easy translation from IBM 029 punched card codes, with the names “zone” and
“numeric” being retained from those days. Why not keep a bit of history?

Page 177 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

The EBCDIC Character Set


Here is the set of important EBCDIC codes.

Character Punch Code EBCDIC


‘0’ 0 F0
‘1’ 1 F1
‘9’ 9 F9
‘A’ 12 – 1 C1
‘B’ 12 – 2 C2
‘I’ 12 – 9 C9
‘J’ 11 – 1 D1
‘K’ 11 – 2 D2
‘R’ 11 – 9 D9
‘S’ 0–2 E2
‘T’ 0–8 E3
‘Z’ 0–9 E9
Note that the EBCDIC codes for the digits ‘0’ through ‘9’ are exactly the zoned decimal
representation of those digits. (But see below).
The DS declarative is used to reserve storage for character data, while the DC declarative is
used to reserve initialized storage for character data. There are constraints on character
declarations, which apply to both the DS and DC declaratives.
1. Their length may be defined from 1 to 256 characters.
As a practical matter, long character constants should be avoided.
2. They may contain any character. Characters not available in the standard
set may be introduced by hexadecimal definitions.
3. The length may be defined either explicitly or implicitly.
It is usually a good idea not to do both, as this can lead to mistakes.
Consider the case in which a DC declarative is used to define a character constant. If the
length attribute is specified, it overrides the length implied by the constant itself. Remember
that the length is really a byte count, which is the same as a character count. The following
examples will illustrate the issues of both explicit and implicit length definitions.
MONTH1 DC CL6‘SEPTEMBER’ STORED AS ‘SEPTEM’
MONTH2 DC CL6‘MAY’ STORED AS ‘MAY ’
MONTH3 DC CL6‘AUGUST’ STORED AS ‘AUGUST’
In the first case, the explicit length is less than the actual length of the constant, so that the
value stored is truncated after the explicit length is stored. The rightmost characters are lost.
In the second case, the explicit length is greater than the actual length of the constant. The
value stored is padded with blanks out to the specified explicit length; here 3 are added.
It should be obvious that nothing special happens when the explicit length is exactly the same
as the length of the constant. There may be reasons to do this, possibly for documentation.

Page 178 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Defining Character Strings


While the term “string” is not exactly appropriate in this context, we need some way to speak
of a sequence of characters such as defined above. In the IBM parlance, the sequence
defined by the declarative DC CL6‘AUGUST’ is viewed as character data. Strictly
speaking, this is a sequence of six characters.
We shall speak of general string handling in a later chapter. The issue at this point is how the
assembler determines the length of the string when executing an instruction such as MVC.
The answer is that each such instruction specifically encodes the length of the string to be
processed. Again, it is the instruction that really defines the length and not the declaration.
Examination of the object code for these character instructions will show that the length is
stored in modified form as an 8–bit unsigned integer. Actually, the length is decremented by
one before it is stored. The range of an 8–bit unsigned integer is 0 through 255 inclusive, so
that the length that can be stored ranges from 1 through 256. There seems to be no provision
for zero length sequences of characters. Zero length strings will be discussed in a later
chapter in which the entire idea of a string will be fully developed.
First, let’s recall one major difference between the DS and DC declaratives. The DS may
appear to initialize storage, but it does not. Only the DC initializes storage. The difference is
illustrated by considering the following two declarations.
V1 DS CL4‘0000’ Define four bytes of uninitialized
storage. The ‘0000’ is just a comment.
The four bytes allocated will have some
value, but that is unpredictable.
V2 DC CL4‘0000’ Define four bytes of storage, initialized
to the four bytes F0 F0 F0 F0, which
represent the four characters.
One should use the DS declaration only for fields that will be initialized by some other
means, such as the MVC instruction that is discussed below. It is always possible to move
values into an area of memory initialized with a DC declarative. In the above example, it is
possible to move the character constant ‘2222’ to V2, which would then contain that value.
The student should also note that it is very easy to write the above declarations in a form that
might cause assembly errors. Consider the following two declarations.
V3 DS CL4 ‘0000’ Define four bytes of uninitialized
storage. Note the blank after ‘CL4’.
Since everything after the ‘CL4’ is a
comment, this does not cause a problem.
V4 DC CL4 ‘0000’ This causes an assembly error. The DC
declarative exists to initialize the
storage area, but the blank after the
‘CL4’ introduces a comment. The ‘0000’
is not recognized as a value.
Note that no declaration above actually defines a number, but just a sequence of characters
that happen to be digits.

Page 179 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Explicit Base Addressing for Character Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 271 – 273].
Assume that general–purpose register 4 is being used as the base register, as assigned at
the beginning of the CSECT. Assume also that the following statements hold.
1. General purpose register 4 contains the value X‘8002’.
2. The label PRINT represents an address represented in base/offset form as 401A; that
is it is at offset X‘01A’ from the value stored in the base register, which is R4.
The address then is X‘8002’ + X‘01A’ = X‘801C’.
3. Given that the decimal number 60 is represented in hexadecimal as X‘3C’,
the address PRINT+60 must then be at offset X‘01A’ + X‘3C’ = X‘56’ from
the address in the base register. X‘A’ + X‘C’, in decimal, is 10 + 12 = 16 + 6.
Note that this gives the address of PRINT+60 as X‘8002’ + X‘056’ = X‘8058’,
which is the same as X‘801C’ + X‘03C’. The sum X‘C’ + X‘C’, in decimal, is
represented as 12 + 12 = 24 = 16 + 8.
4. The label ASTERS is associated with an offset of X‘09F’ from the value in the
base register; thus it is located at address X‘80A1’. This label references a storage
of two asterisks. As a decimal value, the offset is 159.
5. That only two characters are to be moved by the MVC instruction examples to be
discussed. Since the length of the move destination is greater than 2, and since the
length of the destination is the default for the number of characters to be moved, this
implies that the number of characters to be moved must be stated explicitly.
The first example to be considered has the simplest appearance. It is as follows:
MVC PRINT+60(2),ASTERS
The operands here are of the form Destination(Length),Source.
The destination is the address PRINT+60. The length (number of characters
to move) is 2. This will be encoded in the length byte as X‘01’, as the length
byte stores one less than the length. The source is the address ASTERS.
As the MVC instruction is encoded with opcode X‘D2’, the object code here is as follows:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 40 56 40 9F
The next few examples are given to remind the reader of other ways to encode
what is essentially the same instruction.

Page 180 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

These examples are based on the true nature of the source code for a MVC instruction, which
is MVC D1(L,B1),D2(B2). In this format, we have the following.
1. The destination address is given by displacement D1 from the address stored in
the base register indicated by B1.
2. The number of characters to move is denoted by L.
3. The source address is given by displacement D2 from the address stored in
the base register indicated by B2.
The second example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT+60 GET ADDRESS PRINT+60 INTO R8
MVC 0(2,8),ASTERS MOVE THE CHARACTERS
Note the structure in the destination part of the source code, which is 0(2,8).

The displacement is 0 from the address X‘8058’, which is stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 00 40 9F
The instruction could have been written as MVC 0(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.
The third example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT GET ADDRESS PRINT INTO R8
MVC 60(2,8),ASTERS SPECIFY A DISPLACEMENT
Note the structure in the destination part of the source code, which is 60(2,8).

The displacement is 60 from the address X‘801C’, stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 3C 40 9F
The instruction could have been written as MVC 60(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.

Page 181 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Sample Declarations
We now give a few examples of declarations of character constants. These examples will
appear in the form of an assembler listing. Each line will have four parts: a location, the
object code (EBCDIC characters) that would be generated, the declaration itself, and then
some comments in the field that the assembler would reserve for comments.
LOC Obj. Code Source Code Comments
005200 40404040 B1 DC CL4‘ ’ FOUR BLANKS
005204 40404040 B2 DC 4CL1‘ ’ FOUR SINGLE BLANKS. NOTE
THE IDENTICAL OBJECT CODE.
005208 F0F0F0F0 Z1 DC C‘0000’ FOUR DIGITS
00520C F2F2F2F2 N2 DC 4CL1‘2’ FOUR MORE DIGITS

The MVC Instruction


The MVC (Move Character) instruction is designed to move character data, but it can be
used to move data in any format, one byte at a time. As we shall see later, the MVC can be
used to move packed decimal data, but this is not advised as strange errors can occur.
The MCV instruction is a storage–to–storage (type SS) instruction. The opcode is X‘D2’.
The instruction may be written as MVC DESTINATION,SOURCE
An example of the instruction is MVC F1,F2
The format of the instruction is MVC D1(L,B1),D2(B2). This format reflects
the fact that each of the source and destination addresses is specified by a base register (often
the default base register) and a displacement. Here is the format of the object code.
Type Bytes Form 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) X‘D2’ L B1 D1 D1 D1 B2 D2 D2 D2

Here are a few comments on MVC.


1. It may move from 1 to 256 bytes, determined by the use of an 8–bit number
as a length field in the machine language instruction.
The destination length is first decremented by 1 and then stored in the length byte,
which can store an unsigned integer representing values between 0 and 255.
This disallows a length of 0, and allows 8 bits to store the value 256.
2. Data beginning in the byte specified by the source operand are moved one
byte at a time to the field beginning with the byte in the destination operand.
One of the reasons for complexity of the implementation is that the source
and destination regions may overlap.
3. The length of the destination field determines the number of bytes moved.

Page 182 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Example of the MVC Instruction


Consider the example assembly language statement, which moves the string of
characters at label CONAME to the location associated with the label TITLE.
MVC TITLE,CONAME
Suppose that: 1. There are fourteen bytes associated with TITLE, say that it was
declared as TITLE DS CL14. Decimal 14 is hexadecimal E.
2. The label TITLE is referenced by displacement X‘40A’
from the value stored in register R3, used as a base register.
3. The label CONAME is referenced by displacement X‘42C’
from the value stored in register R3, used as a base register.
Given that the operation code for MVC is X‘D2’, the instruction assembles as
D2 0D 34 0A 34 2C Length is 14 or X‘0E’; L – 1 is X‘0D’
To be totally obvious with this example, let us disassemble the object code that we have just
created by manual assembly. The only assumption at the start is that the byte with value
X‘D2’ contains the opcode for the instruction. Here again is the object code format.
Type Bytes Form 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) X‘D2’ L B1 D1 D1 D1 B2 D2 D2 D2

The opcode X‘D2’ is that for the MVC instruction (surprise!). This is a type SS instruction
which has a total of six bytes: the opcode byte and five bytes following.
The second byte contains the length field. Its value is X‘0D’, representing the decimal
value 13. This is one less than the length of the destination field, which must have length 14.
Bytes 3 and 4 represents an address, expressed in base/displacement format, as do bytes
5 and 6. The value in bytes 3 and 4 is a 16–bit number, in hexadecimal it is X‘340A’.
This indicates that general purpose register 3 is being used as the base for this address and
that the offset is given by X‘40A’. Suppose that register 3 contains the value X‘1700’.
The address represented would then be X‘1700’ + X‘40A = X‘1B0A’.

MVC: Explicit Register Usage


The instruction may be written explicitly in the form MVC D1(L,B1),D2(B2)
Consider the following example: MVC 32(5,7),NAME. In this example, suppose that
general–purpose register 7 has the value X‘22400’. We note that the label NAME
represents an address that will be converted to the form D2(B2); that is, a displacement
from a base register. This base register might be register 7 or any of the ten registers (R3 –
R12) available for general use.
We examine the specification of the first argument, which is the destination address.
It is of the form D1(L,B1). The length is L = 5. This indicates that five characters are to
be moved. The displacement is decimal 32, or X‘20’.

Page 183 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

The address of the first character in the destination is given by adding this displacement
to the contents of the base register: X‘22400’ + X‘20’ = X‘22420’. Five characters are
moved to the destination. The fifth character is moved to a location that is four bytes
displaced from the first character; its address is X‘22424’.
Suppose that the label NAME corresponds to an address given by offset X‘250’(592 in
decimal) from general–purpose register 10 (denoted in object code by X‘A’).
When the instruction is written in the form MVC D1(L,B1),D2(B2), we see that it has
the form MVC 32(5,7),592(10). ALL NUMBERS ARE DECIMAL.
In the object code format, the value stored for the length attribute is one less than
the actual length. The length is 5, so the stored value is 4, or X‘04’.
The object code format is D2 04 70 20 A2 50.
Again, recall the object code format for this instruction.
Op Code Length Base Displacement Base Displacement
D 2 0 4 7 0 2 0 A 2 5 0

MVC: Example of Length Mismatch


The number of bytes (characters) to move may be explicitly stated in the source statement.
However if it is not explicitly stated, the number is taken as the length (in bytes or characters)
of the destination field. Consider the following program fragment.
MVC F1,F2
F1 DC CL4‘JUNE’
F2 DC CL5‘APRIL’
What happens is shown in the next figure.

The assembler recognizes F1 as a four–byte field from its declaration by the DC


statement. This implicitly sets the number of characters to be moved. The character ‘L’ is
not moved, as it is the fifth character in F2. It is at address F2+4.
MVC: Another Example of Length Mismatch
The number of bytes (characters) to move may be explicitly stated in the source code. While
the explicit length may exceed that of the destination field, your instructor (but not many
textbook authors) considers that bad programming practice.

Page 184 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Consider the following program fragment, in which an explicit length of 3 is set. Recall the
form of the instruction: MVC D1(L,B1),D2(B2).
MVC F1(3),F2 The (3) says move three characters
F1 DC CL4‘JUNE’
F2 DC CL5‘APRIL’
What happens is shown in the next figure.

Note that only “APR” is moved. The last character of F1, which is an “E”, is not changed.
This last character is at address F1+3.
MVC: Example 3
We may use relative addressing as well as an explicit length declaration. Consider the
following program fragment.
MVC F1+1(2),F2+2
F1 DC CL4‘JUNE’
F2 DC CL5‘APRIL’
This calls for moving two characters from address F2+2 to address F1+1. The two
characters at address F2+2 are “RI”. The two characters at the destination address F1+1
are “UN”. What happens is shown in the next figure.

The other two characters in F1, at addresses F1 and F1+3, are not changed.

Page 185 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

MVC: Example 4
We now consider the explicit use of base registers.
Recall the form of the instruction: MVC D1(L,B1),D2(B2).
In the following three examples, we suppose that PRINT is a label associated with
an output field of length 80 bytes. In reality, it only must be “big enough”.
FRAG01 MVC PRINT+60(2),=C‘**’
FRAG02 LA R8,PRINT+60 LOAD THE ADDRESS.
MVC 0(2,8),=C‘**’ DEST ADDRESS IS PRINT+60
FRAG03 LA R8,PRINT LOAD THE ADDRESS.
MVC 60(2,8),=C‘**’ NOTE OFFSET IS 60
Suppose that the address of PRINT is given by base register 12 and displacement X‘200’.
Suppose register 12 contains a value of X‘1000’. The label PRINT references address
X‘1200’. The value of PRINT+60 is then X‘1200’ + X‘60’ = X‘1260’.
As an aside, note that it appears more natural to write the first instruction in the form.
FRAG01 MVC PRINT+60(2), =C‘**’
Note that there is a space following the comma. This space turns whatever fallows it into a
comment, thus rendering the instruction incomplete and erroneous.

Describing Input Fields


Consider the following block that declares area for an 80–column input (corresponding to an
80–column punch card) that is divided into fields.
Here is a declaration of an 80–byte input area that will be divided into fields.
CARDIN DS 0CL80 The record has 80 bytes.
NAME DS CL30 The first field has the name.
YEAR DS CL10 The second field.
DOB DS CL8 The third field.
GPA DS CL3 The fourth field.
DS CL29 The last 29 chars are not used.
The address corresponding to the label NAME is the same as that for the label CARDIN. The
field NAME corresponds to addresses NAME through NAME+29, inclusive.
The address corresponding to the label YEAR is the same as the address CARDIN+30. The
field YEAR corresponds to addresses YEAR through YEAR+9, inclusive. Equivalently, the
field corresponds to addresses CARDIN+30 through CARDIN+39, inclusive.
Relative addressing will often be used to extract fields from an input record or place fields
into an output record.

Page 186 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Character Comparison: CLC


The CLC (Compare Logical Character) instruction is one of the two used to compare
character fields, one byte at a time, left to right.
Comparison is based on the binary contents (EBCDIC code) contents of the bytes.
The sort order is from X’00’ through X’FF’.
The instruction may be written as CLC Operand1,Operand2
The format of the instruction is CLC D1(L,B1),D2(B2)
An example of the instruction is CLC NAME1,NAME2
This instruction sets the condition code that is used by the conditional branch instructions.
The condition code is set as follows:
If Operand1 is equal Operand2 Condition Code = 0
If Operand1 is lower than Operand2 Condition Code = 1
If Operand1 is higher than Operand2 Condition Code = 2
The operation moves, byte by byte, from left to right and terminates as soon as an unequal
comparison is found or one of the operands runs out.
Using the Condition Codes
The character comparison operators, CLC and CLI, set the condition codes. These codes are
used by the branching instructions in their non–numeric form. Here are the standard
comparisons.
BE Branch Equal Condition Code = 0
BNE Branch Not Equal Condition Code  0
BL Branch Low Condition Code = 1
BNL Branch Not Low Condition Code  1
BH Branch High Condition Code = 2
BNH Branch Not High Condition Code  2.
Here are two equivalent examples.
CLC X,Y
BL J20LOEQ X sorts less than Y
BE J20LOEQ Y is equal to Y

CLC X,Y
BNH J20LOEQ X does not sort higher than Y

Page 187 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

CLC: An Example
Consider the following code fragment. Note that the comparison value is given
as the seven EBCDIC characters ‘0200000’.
Presumably, this would be converted into seven Packed Decimal digits and held to
represent the fixed point number 2000.00, presumably $2,000.00.
C20 CLC SALPR,=C‘0200000’ COMPARE TO 2,000.00
BNH C30 NOT ABOVE 2,000.00
BL C40 LESS THAN 2,000.00
* EQUAL TO 2,000.00
Again, this is presented as representing Packed Decimal data, which it probably
does represent. The comparison, however, is an EBCDIC character comparison.
Here is another example, built around the first one. It represents an important
special case that we shall consider when discussing Packed Decimal format.
C20 CLC SALPR,=C‘ ’ IS THE FIELD BLANK?
BNE NOTBLNK
MVC SALPR,=C‘0000000’ CONVERT BLANKS TO 0’S
NOTBLANK PACK SALNUM,SALPR

MVI and CLI


These two operations are similar to their more general “cousins”, except
that the second operand is a one–byte immediate constant.
The immediate constant may be of any of the following formats:
B binary
C character
X hexadecimal
The format of these instructions are: MVI Operand1,ImmediateOperand
CLI Operand1,ImmediateOperand
Examples of these instructions are: MVI CONTROL,C’$’ Character ‘$’
CLI CODE,C’5’ Character ‘5’
Character Literals vs. Immediate Operands
The main characteristic of an immediate operation is that the operand, called the“immediate
operand” is contained within the instruction. The main characteristic of a literal operand is
that it is stored separately from the operand, in a literal pool generated by the assembler.
Here are two equivalent instructions to set the currency sign.
Use of a literal: MVC DOLLAR,=C’$’
Use of immediate operand MVI DOLLAR,C’$’
Note the “=” in front of the literal. It is not present in the immediate operand.

Page 188 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Insert Character (IC) and Store Character (STC)


The IC instruction moves a single byte (8 bits) from storage into a register and the STC
moves a byte from the register to storage. Each access only the rightmost 8 bits of the
general purpose register, denoted as bits 24 through 31.
Each of the instructions is a type RX instruction of the form OP REG,MEMORY. Note that:
1. The first operand denotes a general purpose register, of which only the rightmost
8 bits (24 – 31) will be used.
2. The second operand references one byte in storage, as each EBCDIC
character is stored in a single byte. As this is a byte address, there are no
restrictions on its value; it can be an even or odd number.
The opcode for IC is X‘43’, while that for STC is X‘42’. The object code is of the form
OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code, either X‘42’ or X‘43’.
The second byte contains two 4–bit fields, each of which encodes a register number. The
field R1 denotes the general purpose register that is either the source or destination of the
transfer. The field X2 denotes the optional index register to be used in address calculation.
The third and fourth bytes hold the standard base/displacement address.
The IC instruction does not change the three leftmost bytes (bits 0 – 23) of the register being
loaded. The STC instruction does not use these three bytes.

Case Conversion
We now present an interesting use for these two instructions. This is the conversion of
alphabetical characters from upper case to lower case and back again. In order to do this, we
need a few instructions that have yet to be discussed.
The three instructions are here given in their immediate format, though there are other forms
that will be discussed later. These are logical AND, logical OR, and logical XOR. Each of
these operations is a bitwise operation, defined as follows.
AND 00 = 0 OR 0+0 = 0 XOR 00 = 0
01 = 0 0+1 = 1 01 = 1
10 = 0 1+0 = 1 10 = 1
11 = 1 1+1 = 1 11 = 0
The three instructions, as implemented in the S/370 architecture, are as follows:
NI Logical AND Immediate Opcode X‘92’
OI Logical OR Immediate Opcode X‘96’
XI Logical XOR Immediate Opcode X‘97’
Each instruction is type SI, and is written as source code in the form OP TARGET,MASK.
The indicated operation is applied to the TARGET and the result stored in the TARGET.

Page 189 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Character Data

Another Look at Part of the EBCDIC Table


In order to investigate the difference between upper case and lower case letters, we here
present a slightly different version of the EBCDIC table.
Zone 8 C 9 D A E
Numeric
1 “a” “A” “j” “J”
2 “b” “B” “k” “K” “s” “S”
3 “c” “C” “l” “L” “t” “T”
4 “d” “D” “m” “M” “u” “U”
5 “e” “E” “n” “N” “v” “V”
6 “f” “F” “o” “O” “w” “W”
7 “g” “G” “p” “P” “x” “X”
8 “h” “H” “q” “Q” “y” “Y”
9 “i” “I” “r” “R” “z” “Z”
The structure implicit in the above table will become more obvious when we compare
the binary forms of the hexadecimal digits used for the zone part of the code.
Upper Case C = 1100 D = 1101 E = 1110
Lower Case 8 = 1000 9 = 1001 A = 1010
Note that it is only one bit in the zone that differentiates upper case from lower case.
In binary, this would be noted as 0100 or X‘4’. As this will operate on the zone field of a
character field, we extend this to the two hexadecimal digits X‘40’. The student should
verify that the one’s–complement of this value is X‘BF’. Consider the following operations.
UPPER CASE
‘A’ X’1100 0001’ X’1100 0001’
OR X ‘40’ X‘0100 0000’ AND X ‘BF’ X‘1011 1111’
X’1100 0001’ X’1000 0001’
Converted to ‘A’ ‘a’

Lower case
‘a’ X’1000 0001’ X’1000 0001’
OR X ‘40’ X‘0100 0000’ AND X ‘BF’ X‘1011 1111’
X’1100 0001’ X’1000 0001’
Converted to ‘A’ ‘a’

We now have a general method for changing the case of a character, if need be.
Assume that the character is in a one byte field at address LETTER.
Convert a character to upper case. OI,LETTER,=X‘40’
This leaves upper case characters unchanged.
Convert a character to lower case. NI,LETTER,=X‘BF’
This leaves lower case characters unchanged.
Change the case of the character. XI,LETTER,=X‘40’
This changes upper case to lower case and lower case to upper case.

Page 190 Chapter 10 Last Revised July 8, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 11: Handling Decimal Data

This chapter covers decimal data, which refers to numeric data that are handled one digit at a
time as opposed to binary integer arithmetic or floating point arithmetic. As will be soon
noticed, the decimal format is particularly well adapted to the accounting and other business
computation that predominates in the companies which represent IBM’s primary markets.
In the IBM S/370 architecture, there are two primary types of decimal data: zoned decimal
data and packed decimal data. As far as your author can determine, the zoned format serves
mostly as an intermediate form between digital character data in EBCDIC form and the
packed decimal format that is used for many computations.
Zoned Decimal Data
The zoned decimal format is a modification of the EBCDIC format. It seems not to be used
in any numeric processing and might best be viewed as an intermediate form in the process
of translating digits in EBCDIC form into the internal representation of a number. The
format seems to be a modification to facilitate processing decimal strings of variable length.
The length of zoned data may be from 1 to 16 digits, stored in 1 to 16 bytes. Note that, as in
the character representation, this format calls for one byte per digit.
We have the address of the first byte for the decimal data, but need some “tag” to denote the
last (rightmost) byte, as the format is not fixed length. The assembler places a “sign zone”
for the rightmost byte of the zoned data.
The common standard is X‘C’ for non–negative numbers, and
X‘D’ for negative numbers.
Other than the placing of a hexadecimal digit X‘C’ or X‘D’ for the zone part of the last
digit, the zoned decimal format is rather similar to the EBCDIC format.
Consider the negative number –12345, and its various representations in which the spaces
are inserted for readability only. Note that X‘60’ is the EBCDIC representation of the “–”.
As a string of EBCDIC characters it is hexadecimal 60 F1 F2 F3 F4 F5.
In the zoned decimal representation it is hexadecimal F1 F2 F3 F4 D5.
As packed decimal format (to be discussed soon) it is stored as 12 34 5D.
There are a few more things that might be said about the zoned format, such as how to
declare a zoned decimal constant (the format type is Z). As your author views the zoned
format as an intermediate format, we shall discuss it further only in the context of conversion
between EBCDIC characters and packed decimal digits.

Packed Decimal Data


The preferred use of packed decimal data format was introduced in Chapter 4, where it was
shown not to have the round–off problem that is commonly found in all floating–point
formats. The standard floating–point formats can guarantee either seven digits of accuracy or
fifteen digits of accuracy. People in business want all digits to be accurate. If a sales total
takes 17 digits to represent, all 17 digits in the number must be correct.

Page 191 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Packed Decimal Format


Here, we discuss the packed decimal format, beginning with packed decimal constants.
A packed decimal constant is a signed integer, with between 1 and 31 digits (inclusive).
The number of digits is always odd, with a 0 being prefixed to a constant of even length.
A sign “half byte” or hexadecimal digit is appended to the representation. The common
sign–representing hexadecimal digits are as follows:
C non–negative
D negative
F non–negative, seen in the results of a PACK instruction.
If a DC (Define Constant) declarative is used to initialize storage with a packed decimal
value, one may use the length attribute. Possibly the only good use for this would be to
produce a right–adjusted value with a number of leading zeroes.
For example DC PL6’1234’ becomes
00 00 00 01 23 4C

Remember that each of these bytes holds two hexadecimal digits, not the value
indicated in decimal, so 23 is stored as 0010 0011 and 4C as 0100 1100.

Some Examples and Cautions


Here are some examples of numbers being represented in packed decimal format.
DC P‘+370’ becomes 370C
DC P‘–500’ becomes 500D
DC P‘+92’ becomes 092C
Here are some uses that, while completely logical, might best be avoided. The problem with
the first example is that the length in bytes is not sufficient to store the packed decimal
number, so that the five leftmost digits are truncated. The second example shows the use of a
DC declarative to define three constants in a manner that is difficult to read.
P1 DC PL2‘12345678’ is truncated to become 678C.
Why give a value only to remove most of it?
PCON DC PL2‘123’,‘–456’,‘789’
This creates three constants, stored as 123C, 456D, and 789C.
Only the first constant can be addressed directly.
I would prefer the following sequence, with the labels P2 and P3 being optional.
P1 DC PL2‘123’
P2 DC PL2‘–456’
P3 DC PL2‘789’

Page 192 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

More Examples
The packed decimal format is normally considered as a fixed point format, with
a specified number of digits to the right of the decimal point. It is important to note that
decimal points are ignored when declaring a packed value. When such are found in a
constant, they are treated by the assembler as comments.
Consider the following examples and the assembly of each. Note that spaces have been
inserted between the bytes for readability only. They do not occur in the object code.
Statement Object Code Comments
P1 DC P‘1234’ 01 23 4C Standard expansion to 5 digits
P2 DC P‘12.34’ 01 23 4C The decimal is ignored.
P3 DC PL4‘-12.34’ 00 01 23 4D Negative and lengthened to 4
bytes. Leading zeroes added.
P4 DC PL5’12.34’ 00 00 01 23 4C Five bytes in length. This gives
2 bytes of leading zeroes.
P5 DC 3PL2‘0’ 00 0C 00 0C 00 0C Three values, each 2 bytes.

Explicit Base Addressing for Packed Decimal Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 273 & 274]. Consider the following source code,
taken from Abel. This is based on a conversion of a weight expressed in kilograms to its
equivalent in pounds; assuming 1kg. = 2.2 lb. Physics students will please ignore the fact
that the kilogram measures mass and not weight.
ZAP POUNDS,KGS MOVE KGS TO POUNDS
MP POUNDS,FACTOR MULTIPLY BY THE FACTOR
SRP POUNDS,63,5 ROUND TO ONE DECIMAL PLACE

KGS DC PL3‘12.53’ LENGTH 3 BYTES


FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
The value produced is 12.532.2 = 27.566, which is rounded to 27.57.
The instructions we want to examine in some detail are the MP and ZAP, each of which
is a type SS instruction with source code format OP D1(L1,B1),D2(L2,B2). Each of
the two operands in these instructions has a length specifier. In the first example of the use
of explicit base registers, we assign a base register to represent the address of each of the
arguments. The above code becomes the following:
LA R6,KGS ADDRESS OF LABEL KGS
LA R7,FACTOR ADDRESS
LA R8,POUNDS
ZAP 0(5,8),0(3,6)
MP 0(5,8),0(2,7)
SRP 0(5,8),63,5

Page 193 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 0(5,8),0(3,6) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 0(5,8),0(2,7) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R7. The source has length 2 bytes.
But recall the order in which the labels are declared. The implicit assumption that the labels
are in consecutive memory locations will here be made explicit.
KGS DC PL3‘12.53’ LENGTH 3 BYTES
FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
In this version of the code, we use the label KGS as the base address and reference all other
addresses by displacement from that one. Here is the code.
LA R6,KGS ADDRESS OF LABEL KGS
ZAP 5(5,6),0(3,6)
MP 5(5,6),3(2,6)
SRP 5(5,6),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 5(5,6),0(3,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 5(5,6),3(2,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 3 from the address stored
in R6. The source has length 2 bytes.

Page 194 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

In other words, the base/displacement 6000 refers to a displacement of 0 from the address
stored in register 6, which is being used as an explicit base register for this operation. As
the address in R6 is that of KGS, this value represents the address KGS. This is the object
code address generated in response to the source code fragment 0(3,6).
The base/displacement 6003 refers to a displacement of 3 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+3, which is the address FACTOR. This is
the object code address generated in response to the source code fragment 3(2,6).
The base/displacement 6005 refers to a displacement of 5 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+5, which is the address POUNDS. This is
the object code address generated in response to the source code fragment 5(5,6).
It is worth notice, even at this point, that the use of a single register as the base from which to
reference a block of data declarations is quite suggestive of what is done with a DSECT, also
called a “Dummy Section”.

Packed Decimal: Moving Data


There are two instructions that might be used to move packed decimal data from one memory
location to another. The preferred instruction is ZAP (Zero and Add Packed).
MVC S1,S2 Copy characters from location S2 to location S1
ZAP S1,S2 Copy the numeric value from location S2 to location S1.
Each of the two instructions can lead to truncation if the length of the receiving area, S1, is
less than the source memory area, S2. If the lengths of the receiving field and the sending
field are equal, either instruction can be used and produce correct results.
The real reason for preferring the ZAP instruction for moving packed decimal data comes
when the length of the receiving field is larger than that of the sending field. The ZAP
instruction copies the contents of the sending field right to left and then pads the receiving
field with zeroes, producing a correct result.
The MVC instruction will copy extra bytes if the receiving field is longer than the sending
field. The MVC instruction makes a left–to–right copy and will copy the required number of
bytes, probably copying garbage. Consider the following example.
F1 DC P‘0000000’ stored as 0000 000C, this takes 4 bytes,
F2 DC P‘123’ stored as 12 3C, this takes 2 bytes.
F3 DC P‘4567’ stored as 04 56 7C, this takes 3 bytes.
Executing ZAP F1, F2 will cause F1 to be set to 0000 123C, which is correct.
Executing MVC F1, F2 will set F1 to 123C 0456, which not only is the wrong answer,
but also fails to be in any recognizable packed decimal format.
Bottom line: Use the ZAP instruction to move packed decimal data.

Page 195 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Packed Decimal Data: ZAP, AP, CP, and SP


We have four instructions with similar format.
ZAP S1,S2 Zero S1 and add packed S2 (This is the move discussed above)
AP S1,S2 Add packed S2 to S1
CP S1,S2 Compare S1 to S2, assuming the packed decimal format.
SP S1,S2 Subtract packed S2 from S1.
These are of the form OP D1(L1,B1),D2(L2,B2), which provide a 4–bit number
representing the length for each of the two operands. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) OP L1 L2 B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code, which is X‘F8’ for ZAP, X‘F9’ for CP,
X‘FA’ for AP, X‘FB’ for SP.
The second byte contains two hexadecimal digits, each representing an operand length.
Each of L1 and L2 encodes one less than the length of the associated operand. This
allows 4 bits to encode the numbers 1 through 16, but disallows arguments of length 0.
The next four bytes contain two addresses in base register/displacement format.

Packed Decimal Data: Additional Considerations


For all four instructions, the second operand must be a valid packed field terminated with a
valid sign. The usual values are ‘C’, ‘D’, and occasionally ‘F’, though the hexadecimal digits
‘A’, ‘B’, and ‘E’ are legal. As noted above, the sign digit ‘D’ is standard for negative
numbers, while the sign digit ‘C’ is standard for non–negative numbers. The sign digit ‘F’
will be seen in data converted from Zoned Decimal by the PACK instruction.
For AP, CP, and SP, the first operand must be a valid packed field terminated with a valid
sign. For ZAP, the only consideration is that the destination field be large enough.
If either the sending field or the destination field (AP and SP) have just been created by a
PACK instruction, the sign half–byte may be represented by the sign digit ‘F’.
This is changed by the processing to ‘C’ or ‘D’ as necessary.
Some textbook hint that using ZAP to transfer a packed decimal number with ‘F’ as the sign
half–byte will convert that to ‘C’. This seems reasonable.
Any packed decimal value with a sign half–byte of D (for negative) is considered to sort less
than any packed decimal value with a sign half–byte of C or F (positive). This follows the
standard arithmetic in which any negative number is less than any positive number.
The number 0 is always represented as 0C (possibly with more leading zeroes), but
is never validly represented as 0D. There is no negative zero.

Page 196 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Example of Packed Decimal Instructions


The form is OP D1(L1,B1),D2(L2,B2). The object code format is as follows:
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) OP L1 L2 B1 D1 D1D1 B2 D2 D2D2
Consider the assembly language statement below, which adds AMOUNT to TOTAL.
AP TOTAL,AMOUNT
Assume: 1. TOTAL is 4 bytes long, so it can hold at most 7 digits.
2. AMOUNT is 3 bytes long, so it can hold at most 5 digits.
3. The label TOTAL is at an address specified by a displacement
of X‘50A’ from the value in register R3, used as a base register.
4. The label AMOUNT is at an address specified by a displacement
of X‘52C’ from the value in register R3, used as a base register.
The object code looks like this: FA 32 35 0A 35 2C

The Disassembly of the Above Example


Consider FA 32 35 0A 35 2C. The operation code X‘FA’ is that for the
Add Packed (Add Decimal) instruction, which is a type SS(2). The above format applies.
The field 32 is of the form L1 L2.
The first value is X‘3’, or 3 decimal. The first operand is 4 bytes long.
The second value is X‘2’, or 2 decimal. The second operand is 3 bytes long.
The two–byte field 35 0A indicates that register 3 is used as the base register
for the first operand, which is at displacement X‘50A’.
The two–byte field 35 2C indicates that register 3 is used as the base register
for the second operand, which is at displacement X‘52C’.
It is quite common for both operands to use the same base register.
Condition Codes
Each of the ZAP, AP, and SP instructions will set the condition codes. As a result,
one may execute conditional branches based on these operations. The branches are:
BZ Branch Zero BNZ Branch Not Zero
BM Branch if negative BNM Branch if not negative
BP Brach if positive BNP Branch if not positive
BO Branch on overflow BNO Branch if overflow has not occurred.
An overflow will occur if the receiving field is not large enough to accept the result.
My guess is that leading zeroes are not considered in this; so that the seven–digit packed
decimal number 0000123 can be moved to a field accepting four digit packed numbers.

Page 197 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Additional Rules for ZAP, AP, and SP


These rules are as follows:
1. The maximum length for each field is 16 bytes, allowing for a maximum of
31 digits. Either field, or both, may have an explicit length operand with
a maximum value of 16. Remember that this operand is a byte length.
2. If the operand 1 (destination) field is shorter than the operand 2 (source) field,
a program interrupt may occur. The length of the first field should be sized for
the expected result of the operation and not just based on the length associated
with the first value. For addition, the operand 1 field should be one digit larger
than the lengths of either of the values to be added.
3. The CPU extends the shorter field (presumably that associated with the second
operand) to that of the longer field by left padding with zeroes. This is necessary
for the results to be in accordance with standard arithmetic.
Examples of ZAP, AP, and SP
Here are a few examples of the use of the three instructions AP, SP, and ZAP. The examples
are to be viewed as independent executions of code, so that the values associated with the
data labels are always the same at the beginning of each.
Suppose that we start with definitions as follows.
P0 DC P‘666’ Stored as 66 6C
P1 DC P‘222’ Stored as 22 2C
P2 DC P‘1234’ Stored as 01 23 4C
P3 DC P‘1234567’ Stored as 12 34 56 7C
For these examples, we assume that the data stored represent integer values, and that none
has an implied decimal or “digits to the right of the decimal”.
CASE1 ZAP P3,P1 RESULTS IN P3 = 00 00 22 2C
CASE2 ZAP P2,P1 RESULTS IN P2 = 00 22 2C
CASE3 AP P2,P1 RESULTS IN P2 = 01 45 6C.
Recall this starts with P2 = 01 23 4C.
CASE4 SP P2,P1 RESULTS IN P2 = 01 01 2C
CASE5 SP P3,P1 RESULTS IN P3 = 12 34 34 5C.
In other words, the arithmetic is not blindly done left to right, but with the digits “lined up”
as one would expect in standard arithmetic.
CASE6 AP P1,P1 RESULTS IN P1 = 44 4C.
CASE7 AP P0,P0 This causes an overflow.
Here we see the importance of design so that the first argument can store not just its initial
value, but also the result of any reasonably contemplated arithmetic operation.
CASE8 SP P0,P0 RESULT IS 0, PRESUMABLY STORED AS 0C.

Page 198 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Comparing Packed Decimal Values


The rules for the CP instruction are the same as those for the AP and SP instructions.
1. Both operands must contain valid packed data, with maximum length of 16 bytes.
Either operand or both may contain an explicit length indicator.
2. If the fields are not of the same length, the CPU extends the shorter field by padding
with left zeroes to the length of the longer field. The comparison remains valid.
3. All comparisons are as in standard algebra. +0 is considered equal to –0, but
otherwise any positive value is larger than any negative value.
The CP (Compare Packed) instruction is used to compare packed decimal values. This sets
the condition codes that can be used in a conditional branch instruction, as just discussed. Is
there any reason to compare and not then have a conditional branch?
In some sense, the CLC (Compare Character) instruction is similar and may be used to
compare packed decimal data. However, this use is dangerous, as the CLC does not allow
for many of the standards of standard algebra.
Consider the two values 123C (representing +123) and 123D (representing –123).
CP will correctly state that 123D < 123C; indeed –123 is less than +123.
CLC will state that 123D > 123C, as 12 = 12, but 3D > 3C. Remember that
these are being compared as sequences of characters without numeric values.
Consider the two values 123C (representing +123) and 123F (also representing +123).
CP will correctly state that 123C = 123F; as 123 = 123.
CLC will state that 123F > 123C, as 12 = 12, but 3F > 3C.
Consider the two values 125C (representing +123) and 12345C (representing +12345).
CP will work correctly, noting that 12345 > 00125. CLC will compare
character by character. As ‘5C’ > ‘34’, it will conclude that 125 > 12345
The best way to understand the results of this last comparison is to line up the two constants,
and note that the comparison is left to right.
12 5C
12 34 5C
Examples of CP
Here are some examples. Consider the following data definitions.
P1 DC P‘6’ STORED AS 6C
P2 DC P‘42’ STORED AS 04 2C
P3 DC P‘122’ STORED AS 12 2C
P4 DC P‘-56’ STORED AS 05 6D
Here are some comparisons.
CP P1,P2 P1 < P2. Compared as 00 6C to 04 2C
CP P1,P3 P1 < P3 BRANCH ON LOW (BL or BM)
CP P1,P4 P1 > P4 BRANCH ON HIGH (BH or BP)
CP P2,P3 P2 < P3
CP P2,P4 P2 > P4
CP P4,P4 P4 = P4 BRANCH ON EQUAL (BE or BZ)

Page 199 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Handling Decimal Precision


There is a small problem that arises due to the fact that the decimal point is not explicitly
stored in the packed decimal format. Consider the following addition.
The positive number 234.12, represented as 23 41 2C
is added to the positive number 4.5678, represented as 45 67 8C.
The sum might be represented as 69 09 0C, which
is not correct. We must keep better track of the decimal.
It seems that the best approach is to store all values to be used in a given computation in the
same format, with the same number of implied decimal digits. Assume that the above values
are used in computations in which the most precise data have five decimal digits. Then we
would be required to have the following.
The value 234.12 would be treated as 234.12000, and stored as 02 34 12 00 0C.
The value 4.5678 would be treated as 4.56780, and stored as 04 56 78 0C.
The sum will then be correctly stored as 02 38 68 78 0C.

MP: Multiply Packed


This is of the form OP D1(L1,B1),D2(L2,B2), which provide a 4–bit number
representing the length for each of the two operands. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) X ‘FC’ L1 L2 B1 D1 D1D1 B2 D2 D2D2

A typical source code example would be MP S1, S2. Before the multiplication, field
S1 holds the multiplicand and field S2 holds the multiplier. After the multiplication, field
S1 holds the product. The rules for the MP instruction are as follows.
1. Both fields must contain valid packed data.
2. The maximum length of the first operand is 16 bytes, or 31 digits. However, this
is the maximum length of the product, not of the multiplicand. See below.
3. The maximum length of the second operand is 8 bytes, or 15 digits.
4. Either operand or both may contain an explicit length specifier.
5. The standard rules of algebra apply: Like signs yield a positive product and
unlike signs yield a negative product.
6. The number of digits in the product is usually equal to the sum of the count of
digits in the multiplicand and the count of digits in the multiplier.
Put another way, prior to multiplication, for each byte in the multiplier, the field to hold the
product must contain one byte of zero digits to the left of the significant digits that represent
the multiplicand. One preferred use would be to use the ZAP instruction to move a smaller
multiplicand into the product field, as shown in the illustration below.

Page 200 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Consider the following sequence, which might be typical of the use.


ZAP PAY, HOURS
MP PAY, RATE
PAY DC PL7‘0000000’ STANDARD IS 980.00 OR 98 00 0C
HOURS DC PL3‘400’ 40.0 HOURS PER WEEK
RATE DC PL3‘245’ PAY RATE $24.50 PER HOUR
Handling Decimal Precision
Recall that the assembler does not track the position of the decimal point in any packed
decimal representation. That is the responsibility of the programmer, who must write
assembly language instructions specifically to correct the product. Consider the example
above. A simplistic product might be expressed as 09 80 00 0C. Is this read as
$9,800.00 (a bonus for the worker) or $980.000 (too many decimal places).
In general, the number of decimal positions in the product is equal to the sum of the number
of decimal places in the multiplier and the number of decimal places in the multiplicand. If
either of these is zero (or both are zero), no adjustment is required. Otherwise, the number of
decimal places in the product must be adjusted.
The reason that this adjustment is required is that the number of decimal places is never
tracked, but is always explicit. The only way to be able to assume the number of decimal
places in a numeric representation that does not indicate that number is to have every
arithmetic operation adjust the result to the correct count.
As an aside, one could write code to track the decimal position explicitly. One might store
the above results as pairs of numbers, such as (1, 400) for hours, (2, 2450) for the rate, etc.
However, this is not the standard approach. What is needed is a way to truncate a product to
the correct number of decimal places; the SRP instruction does exactly that.

SRP: Shift and Round Packed


The SRP instruction was designed to shift packed data to the left or right, effectively dividing
or multiplying by a power of ten, and then rounding the number so produced. The standard
use seems to be a way to round decimal data in the usual fashion; the value 2.416 is rounded
to either 2.42 or 2.4 depending on the number of decimals required. The instruction seems to
support the other option, possibly called “un–rounding”, of extending 2.416 to 2.4160, etc.
While the SRP instruction can be used with the results of AP, SP, and ZAP; we discuss it
here within the more natural context of MP (multiplication of packed decimal data). The
reason for this choice should be obvious. The addition of two numbers with equal counts of
decimal places produces a similar result; thus 2.32 + 4.56 = 6.88. On the other hand, if we
multiply 2.32 by 4.56, the result is 10.5792. Depending on the application, it is common to
round the result to something like 10.58, preserving the count of decimal places.
While on the subject of addition and subtraction, we do not want to overlook an obvious
application of SRP. Consider the sum 2.416 + 7.32. While this is not likely to be seen in a
standard assembly language program, as the programmer surely will have been careful to
keep all decimal points consistent, it is a theoretical possibility. In this case, it would be
necessary to use the SRP instruction to convert this to one of the two equivalent forms: either
2.416 + 7.320 = 9.736 or 2.42 + 7.32 = 9.74.

Page 201 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The SRP instruction is a storage–to–storage (type SS) instruction, with opcode X‘F0’.
Although the SRP is a type SS instruction, it has three operands. The source code is
commonly written in the form SRP PACKVAL,SHIFTCNT,ROUNDVAL.
Operand 1, here PACKVAL, denotes a packed field to shifted and possibly rounded.
Operand 2, here SHIFTCNT, indicates the count of digits to shift. The maximum
shift count is 31, which is the maximum size of a packed decimal field.
Operand 3, here ROUNDVAL, contains a single digit (0 – 9) which is to be added to
the original value before shifting. This converts a shift operation into a rounding.
Normally, the values are 0 for left shifts and 5 for right shifts.
The use of the rounding value can be seen by an attempt to round the number 2.416 by
shifting right one place. A pure shift would change 2.416 to 2.41, which does have one less
decimal place. Use of SRP with a rounding value of 5 would first convert 2.416 to 2.421 and
then shift right to obtain the value 2.42, considered as a proper rounding of 2.416.
The SRP operation sets the condition codes to indicate zero, minus, or plus.
The SRP instruction was not a part of the original S/360 architecture, but was added with the
introduction of the S/370 to replace the MVO (Move with Offset) instruction. We shall not
discuss the MVO instruction here; the reader is directed to reference R_02 for details.
The format of the instruction is SRP D1(L,B1),D2(B2),I3.
The object code format for the SRP instruction is represented in the figure below.
Type Bytes Form 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2),I3 X‘F0’ L I3 B1 D1 D1 D1 B2 D2 D2 D2

L is the length indicator for the field to be shifted, denoted by PACKVAL in the example
above. Remember that the length is a byte count that is one more than the value stored.
Thus, the single hexadecimal digit can represent a value between 0 and 15 inclusive, to
represent a field length between 1 and 16 inclusive.
I3 is the decimal digit to be added before shifting.
The two bytes B1 D1 D1 D1 represent the address of the field to be shifted (PACKVAL ),
denoted in the standard base/displacement form.
The two bytes B2 D2 D2 D2 represent the shift count, using the standard base/displacement
format to represent a count and not an address. The normal use would be either to use a
register to hold the count, or to set the register field to 0 (indicating no base register) and use
the displacement field to hold the constant value of the shift count.
There is an interesting feature of this part of the instruction that arises from the inability of
the assembler to process a negative displacement. Recall that the amount shifted is given by
a count in the range 0 through 31. Left shifts are denoted by positive numbers. It should be
obvious that these shift counts can be represented by a five–bit binary number.
Conceptually, the right shifts used as a part of rounding are represented by negative numbers
in the range from –1 through –31 inclusive. The actual format of the shift count is dictated
by the need to find another way to represent these negative numbers.
Page 202 Chapter 11 Last Revised July 1, 2009
Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The best way to view this shift count is as a six–bit two’s–complement signed integer.
Such a format can represent integers in the range from –32 to +31 inclusive. Some of the
more common shift values would then be stored as follows.
Shift Description Hexadecimal Value Decimal Value
1 left 01 1
2 left 02 2
3 left 03 3
4 left 04 4
1 right 3F 63
2 right 3E 62
3 right 3D 61
4 right 3C 60
Each of the values for right shifts can be obtained by calculating the representation as a
six–bit two’s–complement integer. Consider the value for “3 right”.
The value +3 as a six–bit binary number 00 0011 or X’03’.
The one’s complement of this number 11 1100 or X‘3C’.
Add one to this value to get 11 1101 or X‘3D’.
The default format for the source code is based on decimal values and not hexadecimal.
Hexadecimal values can be specifically indicated; e.g., X‘3D’. The easier way is to use a
formula: N digits left encode with the decimal number N.
N digits right encode with the decimal number (64 – N).

Examples of the SRP Instruction


In each of the following examples the value in AMNT2 is being rounded by adding the value
5 and shifting right two places. The field AMNT2 is assumed to be at an address specified by
the offset 0B2 from the value in base register 12 (X‘C’). The first example, showing the use
of register 10 (X‘A’) to specify the shift count, uses an instruction that will be defined later.
48E030 C2 SHIFT01 LH 10,=H‘-2’ R14 GETS NEGATIVE 2
F045 C0B2 A000 SRP AMNT2,0(10),5
F045 C0B2 003E SHIFT02 SRP AMNT2,X‘3E’,5
F045 C0B2 003E SHIFT03 SRP AMNT2,62,5
AMNT2 DS PL5 LENGTH IS FIVE BYTES
Disassembly of the above
In each of the above instructions (except the first, which is a load register from halfword), the
opcode is X‘F0’, indicating a SRP instruction. The second byte is to be viewed as two
independent hexadecimal digits. The first digit, with value 4, indicates that the length of the
field to be shifted (AMNT2) is five bytes. The second digit, with value 5, is the value to be
added to the field before it is shifted. The next two bytes (C0 B2) specify the address of the
field to be shifted. The last two bytes specify the count for the shift.
In the first example, the count is specified by adding 0 to the value stored in a register. In the
other two, the count is specified by a constant with no base register. One might use a
combination of the two (as in A0 04), but this usage seems a bit strange.

Page 203 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

DP: Divide Packed


The DP (Divide Packed) instruction divides one packed field (the dividend) by another (the
divisor), producing a quotient and a remainder. The DP instruction is a storage–to–storage
instruction, with opcode X‘FD’. The form is OP D1(L1,B1),D2(L2,B2), which
provide a 4–bit number for the length for operand. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) X ‘FD’ L1 L2 B1 D1 D1D1 B2 D2 D2D2

The lengths and address calculations are just as in the other packed decimal instructions. The
rules for the DP instruction are as follows.
1. Each operand must contain data in valid packed decimal format.
2. The maximum length of the first operand (the dividend) is 16 bytes (31 digits).
The maximum length of the second operand (the divisor) is 8 bytes (15 digits).
3. Either operand may specify an explicit length.
4. A zero divisor will cause a program interrupt.
5. DP uses the normal rules of algebra. Like signs in the dividend and divisor
produce a positive quotient; unlike signs produce a negative quotient.
6. After the division, the field that first contained the dividend now contains
the quotient and remainder, each with a sign half–byte.
Before division Dividend
After division Quotient Remainder
The remainder field has a size equal to that of the divisor. Together, the quotient and
remainder occupy the entire dividend field. The address of the quotient is the same as that
for the dividend. The address of the remainder must be computed.
In the original operands, the dividend had length (L1 + 1) and the divisor a length (L2 + 1).
In the results of the operation, the length of the remainder is also (L2 + 1), the same as that
for the divisor. Thus, the length of the quotient is (L1 + 1) – (L2 + 1) = (L1 – L2), and its
length code would be one less: (L1 – L2 – 1). As a result, the address of the remainder is
given by A(Quotient) + (L1 – L2).
As is the case with packed decimal multiplication, the program should use the SRP
instruction to adjust the number of decimal places in both the quotient and remainder. As a
general rule the number of decimal places in the remainder is the same as the number in the
divisor, and the number of decimal places in the quotient is the difference between the count
in the dividend and that in the divisor. If the dividend does not already contain a sufficient
number of decimal places, it is necessary to use the SRP instruction to generate additional
positions by left shifting the dividend. In this case, the value for rounding would be 0.
This brief discussion of the DP instruction concludes our list of instructions for decimal
arithmetic operations.

Page 204 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Conversion between EBCDIC and Packed Decimal


We have now examined a number of packed decimal arithmetic instructions. It is now time
to face the problem of conversion of digits between EBCDIC format and packed decimal
format. At a later time we shall address the problem of conversion between packed decimal
format and two’s–complement fullword format.
When a number is read from input, it is presented as a sequence of EBCDIC characters.
Arithmetic based on this input must be done in one of the standard numeric formats, unless
one wants to write an extraordinary amount of support code. The results must then be
converted back to EBCDIC and formatted for output. We now present a number of
instructions used for this purpose.
Along the way, we shall note the inability of the standard instructions to handle signed data
as input. The digits ‘0’ through ‘9’ can be processed, but the signs ‘+’ and ‘–’ cannot be.
We shall comment on a number of standard tricks that older assembly language programs use
to get around this problem and then write some procedures to handle the issue.
The main issue in the conversion between EBCDIC and packed decimal format is suggested
by the names of the operations that can be used for those conversions PACK and UNPACK.
In the EBCDIC and zoned decimal format, each decimal digit requires an 8–bit byte for its
representation. In the packed decimal format, each digit requires a 4–bit hexadecimal digit.
This representation introduces an amusing, but totally unimportant, ambiguity. In a value
such as represented by X‘789D’, are the numeric values decimal or hexadecimal? The
answer is that it does not matter, each digit requires four bits for encoding.
One of the key ideas in understanding the zoned decimal format is the division of the byte
into two “half bytes” or hexadecimal digits. The most significant is called the zone part and
the least significant is called the numeric part. The figure below illustrates this division.
Portion Zone Numeric
Bit 0 1 2 3 4 5 6 7

There are two instructions specifically designed to process these half–byte fields. These are:
MVZ Move the zone half byte, and
MVN Move the numeric half byte.
Each of these instructions is a type SS instruction, more properly classified as character
instructions than packed decimal instructions. The two are included here because their sole
use seems to involve translation to and from packed decimal format.
The format of each instruction is OP D1(L,B1),D2(B2). This format reflects the
fact that each of the source and destination addresses is specified by a base register (often the
default base register) and a displacement. Here is the format of the object code.
Type Bytes Form 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1 D1 B2 D2 D2 D2

Page 205 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The opcode for MVZ is X‘D3’, that for MVN is X‘D1’. The instruction is commonly
written in source code in the form OP S1, S2. Characteristics of the two instructions include
the following.
1. Each moves half bytes from the address specified by the second operand
to an address specified by the first operand.
2. Each may move from 1 to 256 half–bytes, as specified by the length byte
in the object code representation.
3. Neither move affects the contents of the second operand.
4. All of the addressing conventions used by the character instruction MVC
may be used with either of these instructions.
5. Each instruction moves the half–byte associated with it and does
not affect the other half byte.
6. The MVZ (Move Zones) moves the zone portion of each source byte to
the zone portion of the corresponding destination byte. It does not
change the numeric portion of the destination byte.
The MVN (Move Numeric) moves the numeric portion of each source byte to
the numeric portion of the corresponding destination byte. It does not
change the zone portion of the destination byte.
As we shall soon see, the MVZ instruction is of more immediate interest to this course,
which nevertheless covers both as important. As always, we shall illustrate the operation of
the instructions by considering two fields defined by the DC directives.
Assume that we have the following two data fields defined with initialized storage.
S1 DC C‘123’ Stored as F1 F2 F3
S2 DC X‘45 67 C8’ Stored as 45 67 C8
Execute the instruction MVN S2, S1. This moves the numeric portion of each byte in
S1 to the numeric portion of the corresponding byte in S2.
F1 F2 F3 becomes F1 F2 F3
45 67 C8 41 62 C3
Independently, execute the instruction MVZ S2, S1. This moves the zone portion of each
byte in S1 to the zone portion of the corresponding byte in S2.
F1 F2 F3 becomes F1 F2 F3
45 67 C8 F5 F7 F8
We shall jump ahead to mention one good use of the MVZ instruction, as it applies to the
process of unpacking data using the UNPK instruction. The goal of the unpacking process is
to turn packed decimal data into EBCDIC format suitable for printing. However, the UNPK
instruction converts from packed decimal format to zoned decimal format.
Consider the positive decimal number 1234, represented in packed decimal format as
01 23 4C. The result of an unpack instruction will be represented in zoned decimal format
as F0 F1 F2 F3 C4, which will print as the string 123D, as X‘C4’ is EBCDIC for ‘D’.

Page 206 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The use of the MVZ instruction is illustrated by the following. Consider the following
declaration, given in hexadecimal just to make it easier to read.
S3 DC X‘F0F1F2F3C4’ Stored as F0 F1 F2 F3 C4
The byte X‘C4’ is at location S3 + 4. The following instruction is executed.
MVZ S3+4(1),=X‘F0’
In the above instruction, the source operand is specified as a literal. Note that the second
hexadecimal digit is unimportant. It is the hexadecimal digit F that occupies the zone part of
the byte, and it is only that part that is moved.
The address associated with the destination is given by the relative address S3+4; it is four
bytes offset from the address S3. In other words, it is the fifth byte of the five–byte string.
The (1) part of the instruction indicates that only one zone in the destination is to be
changed. Here it is the zone part of the byte at the address S3+4.
The zoned decimal data stored as F0 F1 F2 F3 C4
is changed to data stored as F0 F1 F2 F3 F4
which is the proper EBCDIC for the digit string “01234”.

PACK
The pack instruction is designed to convert data in zoned decimal format, one digit per byte,
to packed decimal format, with approximately two digits per byte. Due to the similarity of
EBCDIC format to zoned decimal format, the instruction is commonly used to convert from
EBCDIC format into packed decimal format.
The PACK instruction is a storage–to–storage (type SS) instruction, with opcode X‘F2’.
The instruction may be written in source code as PACK PACKED,ZONED. The affect of this
instruction is to take the zoned data in the field represented by the second operand, translate
it to packed format, and place the data into the field represented by the first operand.
The instruction is of the form PACK D1(L1,B1),D2(L2,B2), which uses the standard
base/displacement addressing form for each of the two operands. Note that the length of
each operand (in bytes) is also encoded. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) X ‘F2’ L1 L2 B1 D1 D1D1 B2 D2 D2D2

The following are the rules for PACK:


1. Operand 2 must hold data representing digits or blanks, and the rightmost byte must
hold the code for a digit. The coding may be EBCDIC or zoned decimal.
2. The maximum length for each operand is 16 bytes.
3. Bytes referenced by operand 2 are packed one byte at a time from right to left.
4. other than the rightmost byte, all zones are ignored and only the numeric part of the
code is copied. For the rightmost byte, the half bytes are reversed. The zone part of
the last byte in zoned decimal becomes the sign half byte in packed decimal.

Page 207 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Consider the following two representations of the positive number 123.


As a string of EBCDIC characters, it is the three bytes F1 F2 F3.
As stored in zoned decimal format, it is the three bytes F1 F2 C3.
When executed according to its original design, the PACK instruction operates on
data in the zoned decimal format. Its action on this example is shown below.

When the instruction operates on digital data in EBCDIC form, it functions identically.

Note that the zone part of the last byte has become the sign half–byte in the packed decimal
format. It is for this reason that X‘F’ is recognized as a valid sign indicator.
We now focus on conversions of decimal data between the two formats that may
be used to represent them:
1. The EBCDIC character encoding used for input and output.
2. The packed decimal format used for decimal arithmetic.

Packing Blanks
While the PACK instruction can handle leading blanks, a serious problem can arise if the
field to be packed contains all blanks (EBCDIC code 0x40). Consider first an acceptable
input. Suppose that the five character string “ 2” or EBCDIC 40 40 40 40 F2
is input. What happens here? Note that the numeric part of the EBCDIC code for the blank
is the same as the numeric part of the EBCDIC code for the digit “0”. This works, producing
the packed string “00002F”, as illustrated below.

Now consider the five character input “ ” or EBCDIC 40 40 40 40 40. This


will pack to the string “000004”, which lacks a valid sign, as shown below. This invalid
packed input cannot be processed by any packed decimal instruction.

Page 208 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Some authors suggest checking all input fields and replacing those that are blank
with all zeroes. This suggests a very common meaning of blanks as equivalent to 0.
Here is the code, directly from Abel’s textbook. The input field, RATEIN, is
supposed to contain one to five digits, but no more than five.
CLC RATEIN,=CL5‘ ’ Is this a field of five blanks
BNE D50 No, it is not all blanks
MVC RATEIN,=CL5‘00000’ Replace 5 blanks with 5 zeroes
D50 PACK RATEPK,RATEIN Store packed value in RATEPK

More on Input of Digits to be Formatted as Packed Data


Recall that the input of packed data is a two–step procedure.
1. Input the digits as a string of EBCDIC characters.
2. Convert the digits to packed format.
The format of the input is dictated by the appropriate data declarations.
In this example, we consider the following declaration of the form of the input, which is best
viewed as an 80–column card. Here is a part of a program to read numbers, one per line.
RECORDIN DS 0CL80 80 CHARACTER CARD IMAGE
DIGITS DS CL5 FIRST FIVE COLUMNS ARE INPUT
FILLER DS CL75 THE OTHER 75 ARE IGNORED
Here is a properly formatted input sequence.
1 Four blanks before the “1”.
3
13 Three blanks before the “13”.
In order to see that this is the proper format for the digits, we look at a representation that
emphasizes the column placement of the digits.

Reading from right to left: Column 5 is the units column


Column 4 is the tens column
Column 3 is the hundreds column, etc.
Note that each digit is properly placed; the first line is really 00001.

Page 209 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

One Error: Assuming Free–Formatted Input


Here is some input from the same program. Recall that it was designed to read numbers, one
per line, and to output the sum.. It did not work.
1
3
13
17
The student expected free–form input and assumed that this would be interpreted as the sum
1 + 3 + 13 + 17 = 34. But free–form input is an artifact of a well–written run time system,
with particular attention to the user interface.
Here is the way that the input was interpreted.

To me this looks like 10000 + 30000 + 13000 + 17000. I had expected the above input
to give a sum of 70000. It did not. Here is the code loop for the processing routine.
B10DOIT MVC DATAPR,RECORDIN FILL THE PRINT AREA
PUT PRINTER,PRINT START THE PRINT
PACK PACKIN,DIGITSIN CONVERT INPUT TO DECIMAL
AP PACKSUM,PACKIN ADD IT UP
BR R8 RETURN FROM SUBROUTINE
Here is the actual output. All we get is the header line and a print echo of the first line input.
The header line had been printed by an earlier part of the program.
***PROGRAM FOUR CSU SPRING 2009 ***********
1
A Diagnostic
Here is the code that isolated the problem. Note the one line commented out.
B10DOIT MVC DATAPR,RECORDIN FILL THE PRINT AREA
PUT PRINTER,PRINT START THE PRINT
PACK PACKIN,DIGITSIN CONVERT INPUT TO DECIMAL
*** AP PACKSUM,PACKIN ADD IT UP
BR R8 RETURN FROM SUBROUTINE

Page 210 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The program ran to completion. Here is the output for the code fragment above.
************** TOP OF DATA *****************************
***PROGRAM FOUR CSU SPRING 2009 ***********
1
3
13
17
THE SUM = 000000
************ BOTTOM OF DATA ****************************

The Diagnosis
Look again at the input.

The first line, as EBCDIC characters is read as follows. F1 40 40 40 40


The PACK command processes right to left. It will process any kind of data, even data that
do not make sense as digits. This input will pack to X‘10004’, an invalid packed format.
With no valid sign indicator, the AP instruction fails and the program terminates.

Printing Packed Data


In order to print packed decimal data, it must be converted back to a string of EBCDIC
characters. The UNPK command is a part of this conversion. It converts digital data from
the packed decimal form to the zoned decimal form, which must be processed further.
The UNPK instruction is a storage–to–storage (type SS) instruction, with opcode X‘F3’.
The instruction may be written in source code as UNPK ZONED,PACKED. The affect of this
instruction is to take the packed data in the field represented by the second operand, translate
it to zoned decimal format, and place the data into the field represented by the first operand.
The instruction is of the form UNPK D1(L1,B1),D2(L2,B2), which uses the standard
base/displacement addressing form for each of the two operands. Note that the length of
each operand (in bytes) is also encoded. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) X ‘F3’ L1 L2 B1 D1 D1D1 B2 D2 D2D2

Page 211 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The following are the rules for PACK:


1. The maximum length for each field is 16 bytes, which implies a maximum length
of 8 bytes for the field holding the packed data. Suppose that the packed data is
stored in 9 bytes, which would represent 17 digits. This would unpack to 17 bytes.
2. Bytes referenced by operand 2 are unpacked right to left, one byte at a time.
3. For all but the rightmost byte of the packed data, each hexadecimal digit is handled
separately, being inserted into the numeric zone of the zoned data format.
4. The rightmost byte of the packed data has its half bytes reversed, with its sign
half byte being moved to the zone part of the zoned data and the left half byte
being moved to the numeric part of the zoned data. Consider the number 47,
which would be represented internally as 04 7C.
When this is unpacked, we might want it to become F0 F4 F7, which would print as the
three–digit string “047” or perhaps as the two–digit string “47”. However, UNPK just
swaps the sign half byte to produce F0 F4 C7.
This prints as “04G”, because X‘C7’ is the EBCDIC code for the letter ‘G’.
We have to correct the zone part of the last byte. The problem occurs when handling the sign
code, “C” or “D” in the Packed Decimal format. This occurs in the rightmost byte of a
packed decimal value.
Printing Packed Data (Part 2)
Here is the code that works for five digit numbers. It is written as a subroutine, that is called
as BALR R8,NUMOUT.
NUMOUT CP QTYPACK, =P‘0’ IS THE NUMBER NEGATIVE
BNM NOTNEG NO, IT IS NOT.
MVI QTYOUT+5,C‘-’ YES, IT IS. PLACE SIGN AT QTYOUT+5
NOTNEG UNPK QTYOUT,QTYPACK PRODUCE FORMATTED NUMBER
MVZ QTYOUT+4(1),=X’F0’ MOVE 1 BYTE TO ADDRESS QTYOUT+4
* THIS SETS THE ZONE PART CORRECTLY
BR 8 RETURN ADDRESS IN REGISTER 8
QTYPACK DS PL3 HOLDS FIVE DIGITS IN THREE BYTES
QTYOUT DS 0CL6
DIGITS DS CL5 THE FIVE DIGITS
DC CL1’ ’ THE SIGN
Again, the expression QTYOUT+4 is an address, not a value.
If QTYOUT holds C‘01234’, then QTYOUT+4 holds C ‘4’.
Here, we have accidentally introduced the standard simplistic way of representing negative
numbers in the printout of an assembly language program. This is done because it is far
simpler than formatting the output in the standard manner, in which the minus sign is to the
left of the most significant digit in the output. The table below will illustrate the two output
options as might be seen for a five–digit number.
Internal Value Standard Print Format Simple Print Format
01 23 4C 1234 01234
01 23 4D -1234 01234-
Page 212 Chapter 11 Last Revised July 1, 2009
Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

Unpacking and Editing Packed Decimal Data


Each of the UNPK (Unpack) and the ED (Edit) instruction will convert packed decimal data
into a form suitable for printing. The ED and EDMK instructions seem to be more useful
than the UNPK. In addition to producing the correct print representation of all digits, each
allows for the standard output formats.
The ED instruction is a storage–to–storage (type SS) instruction, with opcode X‘DE’.
The instruction may be written in source code as ED PRNTREP,PACKED.
The EDMK instruction is also a storage–to–storage (type SS) instruction, with opcode
X‘DF’. It may be written in source code as EDMK PRNTREP,PACKED.
Each instruction is of the form OP D1(L1,B1),D2(L2,B2), which uses the standard
base/displacement addressing form for each of the two operands. Note that the length of
each operand (in bytes) is also encoded. The object code format is as follows.
Type Bytes Form 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) OP L1 L2 B1 D1 D1D1 B2 D2 D2D2

The use of the ED instruction is a two–step process.


1. Define an edit pattern to represent the punctuation, sign, and handling of leading
zeroes that is required. Use the MVC instruction to move this into the output
position, which is PRNTREP in the above example.
2. Use the ED instruction to overwrite the output position with the output string that will
be formatted as specified by the edit pattern. The first character in the edit
pattern is a fill character that is not overwritten.
The EDMK instruction is identical to the ED instruction, except that it “marks” the leftmost
significant digit by returning its address as the contents of general–purpose register 1. Think
of the print output being scanned left to right, towards increasing byte addresses. The most
significant digit is the leftmost. We shall discuss this more thoroughly in just a bit.
Here is an example. Note that there are a number of length constraints, specifically that the
length of the edit pattern match the length of the output area.
MVC COUNPR,=X‘40202020’ Four bytes of pattern
ED COUNPR,COUNT
More code here
COUNT DC PL‘001’
COUNPR DS CL4
Note the sequence of events in these two lines of code.
1. The edit pattern is moved into the output field. The leading pair of hexadecimal
digits, 0x40, state that a blank,‘ ’, will replace all leading zeroes.
2. The decimal value is edited into the output field COUNPR, overwriting
the edit pattern.
The result is printed as the four character sequence “ 1”, represented in EBCDIC
as X‘4040 40F1’.

Page 213 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

ED: Basic Rules


The basic form of the instruction is ED S1,S2
The first operand, S1, references the leftmost byte of the edit word, which has been placed in
the output area. This field will be filled with the formatted output.
The second operand, S2, references a packed field to be edited.
One key concept in the editing for output is called “significance”. In many uses, leading
zeroes are not treated as significant and are replaced by the fill character.
Thus, the number represented in packed decimal format as 001C might print as “ 1” or as
“001” depending on whether or not leading zeroes are required.
There are times in which one wants one or more leading zeroes to be printed. As an
example, consider the real number 0.25, which is stored as 025C. It might best be
printed as “0.25” with at least one leading zero. This leads to the concept called
“forcing significance”, in which leading zeroes are printed.

The Fill Character


The leftmost hexadecimal byte in the output area before the execution of the instruction
begins represents the fill character to use when replacing non–significant leading zeroes.
Two standard values are: X‘40’ a blank ‘ ’
X‘5C’ an asterisk ‘*’ Often used in check printing.
Consider the three digit number 172, stored internally as 172C. For now, assume that
the field from which it will be printed allows for five digits. With a fill character of X‘40’
(blank), this would normally be printed as 172.
We can force significance to cause either 0172 or 00172 to be printed. For this number,
with a fill character of X‘40’, our options would be one of the three following.
172
0172
00172
With a fill character of X‘5C’, we might have one of the three following. Note that the
function of the leading “*” is to prevent other digits from being inserted at the left.
**172
*0172
00172
By itself, the leading asterisk is an inadequate security feature. However, when combined
with other printing conventions (noted below), it can prevent many obvious ways of altering
the amount of a check.
An amount on a properly printed check might appear as $**1,234.00.

Page 214 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

The Edit Word: Encountering Significance


Here are some of the commonly used edit characters. Note that it is more convenient
to represent these by their hexadecimal EBCDIC.
One key idea is the encounter of significance. The instruction generates digits for possible
printing from left (most significant) to right (least significant). Two events cause this
encounter: 1) a non–zero digit is generated, and 2) a digit is encountered that is associated
with the 0x21 edit pattern. As noted above, the first character in the edit word is the fill
character. The codes that are used for the digit positions are as follows:
0x20 Digit selector. This represents a digit to be printed, unless it
happens to be a leading non–significant zero.
In that case, the fill character is printed.
0x21 Digit selector and significance starter. This not only represents a
digit to be printed, but it also forces significance. Each digit
to the right will be printed, even if a leading zero.
Unless one is careful, ED might result in an output field that is all blanks. For printing
integer values, one might seriously consider ending the edit pattern with the values 0x2120.
Significance is forced after the next–to–last digit, forcing at least one digit to be printed.
As noted above, the EDMK instruction will insert the address (not the offset) of the leftmost
significant digit into general–purpose register 1. This address can be decremented by 1 and
then used to place a currency sign or other prefix. Please see the example below.

The Edit Word: Formatting the Output


Part of the function of the ED and EDMK commands is to allow standard formatting of the
output, including decimal points and commas. Handling of negative numbers is a bit strange.
Here are the standard formatting patterns.
0x4B The decimal point. If significance has been encountered, the decimal
point is printed. Otherwise, the fill character is printed.
0x6B The comma. If significance has been encountered, the comma is
printed. Otherwise, the fill character is printed.
0x60 The minus sign, “–”. This is used in an unexpected way.
The standard for use of the minus sign arises from conventions found in commercial use.
The minus sign is placed at the end of the number.
Thus the three digit positive number 172 would be printed as 172
and the three digit negative number –172 would be printed as 172–.
The edit pattern for this output (ignoring the significance issue) would be as follows:
0x4020202060. The fill character is a blank. There are three digits followed by
a sign field, which is printed as either “–” or the fill character.

Page 215 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

ED: An Example with Formatting


In this example, it is desired to print a seven digit number, formatted as follows.
1. It is a fixed point number, with two digits to the right of the decimal.
2. It has five digits to the left of the decimal and places a comma in the
standard location if significance has been encountered.
3. It will be printed with a terminating “–” if the number is negative.
This situation is illustrated in the following graphic.

The edit pattern for this example would be as follows:


1 2 3 4 5 6 7
40 20 20 6B 20 21 20 4B 20 20 60

Note: The significance forcer at digit 4 will insure that digit 5 is printed,
even if it is a zero.

EDMK: An Example
Here we shall give an example of the use of the Edit and Mark instruction, using the
edit word that we have just discussed. Here is the sample code:
MVC AMTPR,EDPAT MOVE EDIT PATTERN TO PRINT FIELD
EDMK AMTPR,AMTPAK FORMAT THE PACKED FOR PRINTING
*
* HERE REGISTER 1 CONTAINS THE BYTE ADDRESS OF THE MOST
* SIGNIFICANT DIGIT. THE ADDRESS IS NOT LESS THAN
* (AMTPR + 1), THE ADDRESS OF “DIGIT 1” IN THE PATTERN ABOVE.
*
SH R1,=H‘1’ DECREMENT ADDRESS BY 1
MVI 0(1),C‘$’ PLACE THE DOLLAR SIGN
EDPAT DC X‘4020206B2021204B202060’ THE PATTERN ABOVE
AMTPAK DC P‘12345’ THE AMOUNT TO DISPLAY
AMTPR DS CL11 THE PRINT REPRESENTATION
If the value in AMTPAK were formatted with the ED instruction, we would not be able to
use the code above to place the “$” character. Here are the two outputs.
With the ED operator, the output is $ 123.45
With the EDMK instruction, the output is $123.45

Page 216 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

ED: More on the “*” Fill Character


One option for the fill character is 0x5C, the asterisk. Why is this used? Consider the above
seven–digit example, in which the number is to be viewed as a money amount. We shall use
the dollar sign, “$”, in the amount.
Consider the amount $123.45. We would like to print it in this fashion, but placing the
dollar sign in this way presents difficulties. Standard coding practice would have been to
place the dollar sign in a column just prior to that for the digits. The format would have been
as follows.
Column 0 1 2 3 4 5 6 7 8 9 10
$ Digits , Digits . Digits –

If the blank fill character were chosen, this would print as $ 123.45.
Note the spaces before the first digit. To prevent fraud, we print $***123.45
ED: A More Complete Example
We now show the complete code for producing a printable output from the seven digit
packed number considered above. We shall use “*” as a fill character. Note that the output
will be eleven EBCDIC characters. Here is the code.
PRINTAMT MVC AMNTPR,EDITWD
ED AMTPR,AMTPACK
* The fill character is “*”. Also punctuation as follows
, . -
EDITWD DC X‘5C20206B2021204B202060’
*
AMTPACK DS PL4 FOUR BYTES TO STORE SEVEN DIGITS.
AMTPR DS CL11 THE FORMATTED PRINT OUTPUT
ED: Another Example Using an Edit Pattern
This example is adapted from Abel’s textbook. Suppose that we have the following.
The packed value to be printed is represented by
DC PL3‘7’ This is represented as 00 00 7C.
The edit pattern, when placed in the output area beginning at byte address 90,
is as shown below.
Address 90 91 92 93 94 95 96 97
Code 40 20 21 20 4B 20 20 60

Note the structure here: 3 digits to the left of the decimal (at least one will be printed),
the decimal point, and
two digits to the right of the decimal.
This might lead one to expect something like “000.07” to be printed.

Page 217 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

At address 90 the contents are 0x40, assumed to be the fill character.


This location is not altered.
Address 90 91 92 93 94 95 96 97
Code 40 20 21 20 4B 20 20 60

At address 91 the contents 0x20 is a digit selector. The first digit


of the packed amount is examined. It is a 0. 00007C
ED replaces the 0x20 with the fill character, 0x40.
Address 90 91 92 93 94 95 96 97
Code 40 40 21 20 4B 20 20 60

At address 92 the contents 0x21 is a digit selector and a significance forcer


for what follows. The second digit 00007C
of the packed amount is of the packed amount is examined.
It is a 0. ED replaces the 0x21 with the fill character, 0x40.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 20 4B 20 20 60

At address 93 the contents 0x20 is a digit selector. Significance has been


encountered. The third digit of the packed 00007C
amount is of the packed amount is examined.
It is a 0. ED replaces the 0x20 with 0xF0, the code for ‘0’.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 F0 4B 20 20 60

At address 94 the contents 0x4B indicate that a decimal point is to be printed


if significance has been encountered. It has been, so the pattern
is not changed. Had significance not been encountered, this
would have been replaced by the fill character.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 F0 4B 20 20 60

At address 95 the contents 0x20 is a digit selector. Significance has been


encountered. The fourth digit of the packed 00007C
amount is of the packed amount is examined.
It is a 0. ED replaces the 0x20 with 0xF0, the code for ‘0’.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 F0 4B F0 20 60

Page 218 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Decimal Data

At address 96 the contents 0x20 is a digit selector. Significance has been


encountered. The fourth digit of the packed 00007C
amount is of the packed amount is examined.
It is a 7. ED replaces the 0x20 with 0xF7, the code for ‘7’.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 F0 4B F0 F7 60

At address 97 the contents 0x60 indicate to place a minus sign if the number
to be printed is found to be negative. It is not, so the instruction
replaces the negative sign with the fill character.
Address 90 91 92 93 94 95 96 97
Code 40 40 40 F0 4B F0 F7 40

At this point, the process terminates. We have the EBCDIC representation of


the string to be printed. As characters, this would be “ 0.07 ”. Note that there is a
trailing space in this printout; it occupies a column in the listing.
Note that additional code would be required to print something like “ $ 0.07 ”.
This would involve a scan of the output of the ED instruction and placing the dollar
sign at a place deemed appropriate.
Suppose now that the packed value to be printed is represented by
DC PL3‘7’ This is represented as 00 00 7D.
Suppose that the edit pattern is specified as follows:
Address 90 91 92 93 94 95 96 97
Code 5C 20 21 20 4B 20 20 60

The reader should verify that the print representation would be “***0.07-”.

Page 219 Chapter 11 Last Revised July 1, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 12: Handling Binary Integer Data

This chapter covers binary data, which refers to integer data that are stored in the form of
two’s–complement numbers of either 2 bytes (16 bits) or 4 bytes (32 bits). Later versions of
the IBM mainframe, certainly the zSeries, also include 8 byte (64 bit) integers.
While it is true that all data in a stored–program computer are stored in binary form, it is the
interpretation of those data by the CPU that determines the format to be used. Consider the
following ambiguous declaration.
DATA DC X‘81 6C’
If this field is processed as a character string, say using MVC, it will be interpreted as the two
printable characters “a%”. If the field is processed as a packed decimal, say using ZAP, it
will be interpreted as the three–digit positive number with value equal to +816.
This field contains four hexadecimal digits, or 16–bits. It can be viewed as a 16–bit signed
integer in two’s–complement format. A bit of reflection will show that, interpreted in this
format, the field represents a negative number. We now convert it to the decimal value.
The value itself is X‘81 6C’ or binary 1000 0001 0110 1100.
Take the one’s complement to get 0111 1110 1001 0011.
Add one to get 0111 1110 1001 0100.
Convert this back to hexadecimal X‘7E 94’.
The decimal value for the last is 32,404. The data field, interpreted as an 8–bit integer
stored in two’s–complement form is an integer with the negative value –32,404.
The two standard binary formats are as follows.
F The fullword format is a 32–bit integer, requiring four bytes of storage.
H The halfword format is a 16–bit integer, requiring two bytes of storage.
The ranges are what would be expected for standard two’s–complement arithmetic.
Type Bits Minimum Maximum Minimum Maximum
Half–word 16 –(215) (215) – 1 –32,768 32,767
Full–word 32 –(231) (231) – 1 –2,147,483,648 2,147,483,647
Those of us trained on computers other than IBM mainframes will unconsciously equate
integer data with one of the standard two’s–complement formats. The 16–bit and 32–bit
forms were rather popular when the System/360 was first designed. These two formats
were continued into the System/370 and later models. As noted above, newer models
include a 64–bit integer format.
Those programmers trained primarily on IBM mainframes might consider the packed
decimal format as an equally good way to handle integers. Recall that the packed format can
handle integers of lengths up to 31 digits, as opposed to the 11 digit maximum on the 32–bit
two’s–complement format. In this view, binary arithmetic is done only in the registers and
usually is applied only for address computations. Your author’s opinion is that each integer
representation has its strengths; pay your money and take your choice.

Page 220 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Declaring Binary Storage


There are many ways to declare binary storage. The four most useful are
1. B Ordinary binary,
2. F Full–word (32–bit binary two’s–complement integer),
3. H Half–word (16–bit) binary two’s–complement integer), and
4. X Hexadecimal.
Each of the B and X declarations may declare a storage area with length from 1 through 256
bytes. The lengths of the F and H declarations are fixed at 4 and 2 bytes respectively.
Apparently, it is possible to assign a length in bytes to either type, but this is strange.
Note that the two declarations below have an identical effect. Each defines a 32–bit binary
integer with value equal to 14,336 in decimal.
F1 DC F‘14336’ DEFAULT SIZE IS FOUR BYTES.
X1 DC XL4‘00003800’ SIZE SPECIFIED AS FOUR BYTES.
While the second declaration is unusual for a full–word, it makes some examples easier.

More On DC (Define Constant)


The general format of the DC statement is as follows.
Name DC dTLn ‘constant’

The name is an optional entry, but required if the program is to refer to the field by name.
The standard column positions apply here.
The declarative, DC, comes next in its standard position.
The entry “dTLn” is read as follows.
d is the optional duplication factor. If not specified, it defaults to 1.
T is the required type specification. The types for binary are B, F, H, and X.
Note that the data actually stored at the location does not need to be
of this type, but it is a good idea to restrict it to that type.
L is an optional length of the data field in bytes.
The ‘constant’ entry is required and is used to specify a value. If the length attribute is
omitted, the length is specified implicitly by this entry. Again, it is rarely desirable
to specify a length for the F and H data types.

Alignment and Value Ranges


Remember that the System/360 is a byte–addressable machine. The type F declares a full–
word, which is a four–byte field aligned on a full–word boundary; i.e., its address is a
multiple of four. The type H declares a half–word, which is a two–byte field aligned on a
half–word boundary; i.e., its address is a multiple of two.
If the value declared in either a type F or type H constant is greater than that
allowed by the data type, the assembler merely truncates the leftmost digits.

Page 221 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Consider the following example


BAD DC H‘73728’ IN HEXADECIMAL, X‘12000’
This is truncated to a value of 8,192, which is X‘2000’. The leading 1 is dropped
from the hexadecimal representation, because only the last four digits fit into the
half–word storage allocation; 4 hexadecimal digits = 2 bytes = 1 half–word.

Sequential Memory
Consider the following two declarations which are sequential. Each is a half–word,
which is declared using the hexadecimal construct to make the example clear.
H1 DC XL2‘0102’ DECIMAL 258
H2 DC XL2‘0304’ DECIMAL 772 At address H1+2
The half–word value stored at address H1 is hexadecimal 0102 or decimal 258.
The full–word value stored at address H1 is hexadecimal 01020304, or
16, 909, 060 in decimal. This fact can present problems for the incautious coder.
To load the value of the half–word at address H1 into a register, one uses the Load
Half–word instruction; e.g., LH R4,H1. Register R4 gets 258. But if I accidentally write a
full–word load instruction, as in L R4,H1, then register R4 will get the decimal value
16, 909, 060. This is due to the fact that the four bytes beginning at address H1 have the
value X‘0102 0304’. The fact that H1 and H2 are defined separately matters not at all.
Similarly, suppose I declare a full–word as follows.
F1 DC XL4 ‘11121314’ DECIMAL 17,899,828
If the code says LH R4,F1, then F1 gets hexadecimal X‘1112’ or decimal 4370.

Binary Constants and Hexadecimal Constants


The type B declaration uses binary numbers (0 or 1) to define a string of bits. The type X
declaration uses hexadecimal digits to define what is also just a string of bits.
Consider the following pairs of declarations.
B1 DC B‘10101110’
X1 DC XL1‘AE’ READ AS 1010 1110
B2 DC B‘0001001000010011’
X2 DC XL2‘1213’ READ AS 0001 0010 0001 0011
B1 and X1 each declare the same bit pattern.
B2 and X2 each declare the same bit pattern.
Personally, I find the hexadecimal constants much easier to read, and would suggest not
using the B declaration. The most common use for the binary declaration would be to set bit
patterns to be sent to registers that control Input/Output devices. In standard programming,
we do not have access to those registers on a System/360 or later mainframe..

Page 222 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Input and Output of Binary Data


All data are input originally as EBCDIC characters.
All data printed must be output as EBCDIC characters.
The standard input process for binary data is a two–step one, in which the character
data are first packed to form decimal data and then converted to binary.
The standard process to output binary data from a register is also a two–step one.
First convert the binary to decimal data and then use unpack or the edit instruction
to produce the printable EBCDIC characters.

Conversion between Packed Decimal and Binary


These two conversion instructions are each a type RX instruction.
CVB (Convert to Binary) converts packed decimal data from storage into binary form in a
general–purpose register. This is a type RX instruction with opcode X‘4F’.
CVD (Convert to Decimal) converts binary data in a general–purpose register into packed
decimal form in storage. This is a type RX instruction with opcode X‘4E’.
The format of each is OP R1,D2(X2,B2).
Template for the instructions: CVB Register,Storage_Location
CVD Register,Storage_Location
For the CVB instruction, the Storage Location contains the packed decimal value that
is to be converted to binary and placed in the register.
For the CVD instruction, the Storage Location is the field that will receive the packed
decimal value resulting from the conversion of the value in the register.
It is standard practice to use the floating point data type D (double word) to
declare the storage location.

Page 223 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Why A Floating Point Type Here?


The D data type declares a double precision floating point value, which occupies eight bytes
(64 bits) and is automatically aligned on a double–word boundary. In other words, its
address is a multiple of 8. The true requirement for the operand is that it be exactly eight
bytes long and begin on a double–word boundary. The D declaration fills the bill.
Consider the following code, which is rather standard.
CVB R6,D1
D1 DS D DOUBLE WORD OR 8 BYTES
One might also write the following, if one is careful.
CVB R6,D2
D2 DS PL8 EIGHT BYTES FOR UP TO 15 DIGITS
The difficulty here is insuring that D2 is properly aligned on a double–word boundary.
While this can be done, it is less error–prone to use the D type and have the assembler
automatically do the alignment for you.

Example and Comments


How many digits do I really need? The biggest value storable as a 32–bit binary number is
2,147,483,647. This number has 10 digits, which will be converted to 11 digits for storage in
Packed Decimal format. A 4–byte full–word will store only seven digits. It takes a six–byte
packed decimal field to store 11 digits. There is no data size that automatically takes 6 bytes
and no provision for aligning an address on a multiple of six. The obvious choice for the
packed decimal intermediary form is storage as a double–word.
Input example
ZAP D1,AMTPACK TRANSFER TO THE DOUBLE WORD
CVB R5,D1 CONVERT TO BINARY
D1 DS D THIS RESERVES EIGHT BYTES
Output example
CVD R5,D2 PLACE INTO A DOUBLE WORD
ZAP AMTPACK,D2 TRANSFER TO THE PACKED WORD
D2 DS D THIS ALSO RESERVES EIGHT BYTES
Each of these examples assumes that a field, AMTPACK in each, has been properly declared
with the proper length. Recall that each example is a part of a larger process.
The input process has several steps:
1. Read in the sequence of digits as EBCDIC characters.
2. Use the PACK command to place the result in the field AMTPACK.
3. Use the above sequence to convert the number to binary form in the register.
The output process has several steps:
1. Use the above sequence to convert the binary number in the register to
a packed form in the field AMTPACK.
2. Use UNPK or ED, preferably the latter, to generate the EBCDIC characters
that form the printable output.

Page 224 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

RX (Register–Indexed Storage): Explicit Base Register Usage


This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number. The
first hexadecimal digit, denoted R1, identifies the register to be used as either the source or
destination for the data. The second hexadecimal digit, denoted X2, identifies the register to
be used as the index. If the value is 0, indexed addressing is not used.
The third and fourth bytes contain a standard address in base/displacement format.
As an examples of this type, we consider the two following instructions:
L Load Fullword Opcode is X‘58’
A Add Fullword Opcode is X‘5A’
We consider a number of examples based on the following data declarations. Note that the
data are defined in consecutive fullwords in memory, so that fixed offset addressing can be
employed. Each fullword has a length of four bytes.
DAT1 DC F‘1111’
DAT2 DC F‘2222’ AT ADDRESS (DAT1 + 4)
DAT3 DC F‘3333’ AT ADDRESS (DAT2 + 4) OR (DAT1 + 8)
A standard code block might appear as follows.
L R5,DAT1
A R5,DAT2
A R5,DAT3 NOW HAVE THE SUM.
One variant of this code might be the following. See page 92 of R_17.
LA R3,DAT1 GET ADDRESS INTO R3
L R5,0(,3) LOAD DAT1 INTO R5
A R5,4(,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,8(,3) ADD DAT3, AT ADDRESS DAT1+8.
Note the leading comma in the construct (,3), which is of the form (Index, Base). This
indicates that no index register is being used, but that R3 is being used as a base register. It is
equivalent to the construct (0,3), which might be preferred.
Here is another variant of the above code.
LA R3,DAT1 GET ADDRESS INTO R3
LA R8,4 VALUE 4 INTO REGISTER 8
LA R9,8 VALUE 8 INTO REGISTER 9
L R5,0(0,3) LOAD DAT1 INTO R5
A R5,0(8,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,0(9,3) ADD DAT3, AT ADDRESS DAT1+8.

Page 225 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Loading Values: L, LH, LR, and LCR


The general–purpose registers are designed to store and manipulate binary data that are
stored in the form of 32–bit two’s–complement integers. As an aside, remember two facts
about such numbers.
1. The IBM standard is to number the bits from left to right as 0 through 31.
The sign bit is called “Bit 0” and the units bit on the right “Bit 31”.
2. IBM will often call this “31 bit data”, as the value has a 31–bit magnitude
(stored in bits 1 – 31) and a sign bit.
We first discuss three of the standard instructions used to load values into a register.
L Load a full–word value into the register.
LH Load a half–word value into the register.
The 16–bit value is sign extended into 32–bits for the register.
LR Copy a value from one register to another register.
LCR Load the first register with the two’s–complement of the value in the second.
Note: None of these instructions will set a condition code.
Do not load a register and expect a condition code to reflect the value loaded.

L (Load 32–bit Full–word)


The instruction is a type RX, with format L R1,D2(X2,B2). The opcode is X‘58’. The
object code format is as follows.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘58’ R1 X2 B2 D2 D2D2
The first operand specifies any general–purpose register. This is indicated by the first
hexadecimal digit in the second byte of the object code.
The second operand references a full–word in storage, usually aligned on a full–word
boundary. If the second operand is a literal, the assembler will align it properly. The address
of this second word is computed from the standard base/displacement form (B2 D2 D2 D2 in
bytes 3 and 4) with an index register (the second hexadecimal digit in byte 2).
Here is a template for the instruction: L Reg,Full_Word
Here are some examples of common usage. Other examples will be discussed later.
L1 L R2,=F‘4000’ R2 GETS DECIMAL 4000
L2 L R3,F1 R3 ALSO GETS DECIMAL 4000
L3 L R4,H1 THIS IS PROBABLY A MISTAKE.
L4 L R5,=A(H1) LOAD THE ADDRESS INTO R5.
F1 DC F‘4000’
H1 DC H‘2000’ Stored as X‘07 D0’
H2 DC H‘3000’ Stored as X‘0B B8’
Note again, it is usually a mistake to attempt to use a full–word load to place a half–word
value into a register. What will happen when the instruction at address L3 is executed is that
register R4 will be loaded with the value X‘07 D0 0B B8’, or decimal 131, 075, 000.

Page 226 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

The execution of the instruction at address L4 causes the address of the halfword H1, not its
value, to be loaded into register R5. For the System/370, the address is a 24–bit unsigned
integer that is extended to a 32–bit value for storage in the register.

LH (Load 16–bit Half–word)


The instruction is a type RX, with format LH R1,D2(X2,B2). The opcode is X‘48’.
The object code format is as follows.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘48’ R1 X2 B2 D2 D2D2
The first operand specifies any general–purpose register. This is indicated by the first
hexadecimal digit in the second byte of the object code.
The second operand references a full–word in storage, usually aligned on a half–word
boundary. If the second operand is a literal, the assembler will align it properly. The address
of this second word is computed from the standard base/displacement form (B2 D2 D2 D2 in
bytes 3 and 4) with an index register (the second hexadecimal digit in byte 2).
The assembler loads the half–word into the rightmost 16 bits of the register (16 – 31)
and then propagates the half–word’s sign bit through the left 16 bits of the register.
Here is a template for the instruction: LH Reg,Half_Word
Here are some examples of common usage. Other examples will be discussed later.
L1 LH R2,=H‘4000’ R2 GETS DECIMAL 4000
L2 LH R3,H1 R3 GETS DECIMAL 2000
L3 LH R4,F1 THIS IS PROBABLY A MISTAKE.
F1 DC F‘4000’ Stored as X‘00 00 0F A0’
H1 DC H‘2000’
The difficulty with the instruction at address L3 is that it will access the two bytes at the
addresses F1 and F1+1. The halfword stored there has value X‘00 00’, or just 0.

Sign Extension for LH


Consider two 16–bit integers that are stored as half–words in two’s–complement form.
The positive number + 100 is stored as 0000 0000 0110 0100, or X‘0064’.
The negative number –100 is stored as 1111 1111 1001 1100 or X‘FF9C’
The LH sign extends the halfword data into fullword data with the proper sign. This it does
by copying bits 0 through 15 of the halfword into bits 16 through 31 of the register and then
copying the sign bit (now in register bit 16) into bits 0 through 15 of the register.

Page 227 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Consider the code fragment below.


LH R7,=H‘100’
After this, register R7 contains the full–word value +100, as shown below.
Left half–word Right half–word
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
0000 0000 0000 0000 0000 0000 0110 0100
Now consider the code fragment.
LH R8,=H‘-100’
After this, register R8 contains the full–word value –100, as shown below.
Left half–word Right half–word
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
1111 1111 1111 1111 1111 1111 1001 1100

LR (Load Register) and LCR (Load Complement Register)


Each instruction is a type RR, with format LR R1,R2. The opcode for LR is X‘18’.
The opcode for LCR is X‘13’. The object code format for each is as follows.
Type Bytes Operands
RR 2 R1,R2 OP R1 R2
Each operand specifies any general–purpose register. The contents of the register specified
as the second operand are copied into the register specified as the first operand.
Consider the code fragment below.
L R9,=H‘200’ REGISTER 9 GETS DECIMAL 200
LR R7,R9 REGISTER 7 ALSO GETS 200
THIS TIME IT IS COPIED FROM R9
LCR R8,R9 REGISTER 8 GETS DECIMAL -200, STORED
IN PROPER 2’S-COMPLEMENT FORMAT.

LM (Load Multiple Registers)


The LM instruction loads data from main storage into more than one register.
The instruction is a type RS with format LM R1,R3,D2(B2). The opcode is X‘98’.
This is a four–byte instruction with object code format as follows:
Type Bytes Operands 1 2 3 4
RS 4 R1,R3,D2(B2) X‘98’ R1 R3 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number. These
two bytes specify the range of registers to be loaded.
The third and fourth bytes together contain a 4–bit register number and 12–bit displacement
used to specify the memory address of the operand in storage. This operand is considered as
the first fullword a block of fullwords; the size of the block is determined by the number of
registers specified in byte 2. This is a type RS instruction; indexed addressing is not used.

Page 228 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Recall that each label in the assembly language program references an address,
which must be expressed in the form of a base register with displacement.
Any address in the format of base register and displacement will appear in the form.
B D1 D2 D3
B is the hexadecimal digit representing the base register.
The register numbers “wrap around”, so that 15,1 specifies the three registers 15, 0, 1.
Example code:
LM R6,R8,F1 LOAD R6, R7, R8 FROM F1, F2, F3
LM R15,R2,F1 LOAD R15, R0, R1, R2 FROM F1 TO F4
F1 DC F‘1111’
F2 DC F‘2222’
F3 DC F‘3333’
F4 DC F‘4444’

LM and the Standard Closing Code


Look again at part of the standard closing code for our programs.
******************* END LOGIC **************************
L R13,SAVEAREA+4 POINT AT OLD SAVE AREA
LM R14,R12,12(R13) RESTORE THE REGISTERS
LA R15,0 RETURN CODE = 0
BR R14 RETURN TO OPERATING SYSTEM

The label SAVEAREA references a sequence of full words used to save information
used when returning to the operating system.
The second full–word in this area, at address SAVEAREA+4, holds the address of
the block of memory used to save the register information.
The instruction LM R14,R12,12(R13) loads the 15 registers R14 through R12, omitting
only R13, with the 15 full–word values beginning at the specified address. More
specifically, the old register values are saved in a block beginning with the fourth full–word
(at offset 12) in the block with address now in R13. The address 12(R13) is specified in
base/displacement format and references the start address of the 60–byte part of the save area
that is used to store the values of the registers.
The instruction LA R15,0 is a use of a Load Address instruction that we shall discuss
very shortly. I would prefer something like LH R15,=H‘0’, which appears to be
equivalent, but can lead to addressability issues. The LA format is safer.

Page 229 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Loading Addresses
Up to now, we have discussed “value loaders”, such as the following example.
L R3,FW1
This finds the full–word at address FW1 and loads its value into register R3.
At times, we shall need not the value stored at an address but the address itself.
One possibility would be to store a return address to be used by a subroutine.
There are two common ways to access the address and store it into a register.
1. Use the L (Load full–word) instruction and use an address literal
2. Use the LA (Load Address) instruction and use the label.
The following two statements are equivalent. Each loads R1 with the address FW1.
L R1,=A(FW1)
LA R1,FW1
In the System/360 and System/370 the address is treated as a 24–bit unsigned integer,
which can be represented by six hexadecimal digits.
If the address of FW1 is X‘112233’, register R1 gets X‘00112233’.

LA (Load Address)
The instruction is a type RX, with format LA R1,D2(X2,B2). The opcode is X‘41’.
The object code format is as follows.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘41’ R1 X2 B2 D2 D2D2
Here is a template for the instruction: LA Reg,Address
The first operand specifies any general–purpose register. This is indicated in the
object code by the first hexadecimal digit in the second byte.
The second operand references a storage address in the form D2(X2,B2). The index
register is specified by the second hexadecimal digit in the second byte. Bytes 3 and 4
together contain an address in base/displacement form, to which the index value is added.
Consider the following fragment of code, which indicates one use of the instruction.
LA R9,A10
A10 DC F‘100’
Suppose that label A10 is subject to base register 3 containing value X‘9800’
with a displacement of X‘260’. The object code for the LA instruction is as follows.
41 90 32 60
The code for the LA instruction is X‘41’. The second byte “90” is of the form R1X2,
where R1 is the target register and X2 is the index register. As is standard, a value of 0
indicates that indexing is not used in this address; it is pure base/displacement form.
The LA instruction causes register R9 to be get value X‘9800’ + X‘260’ = X‘9A60’.

Page 230 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

LA: A Second Look


The instruction is a type RX, with format LA R1,D2(X2,B2).
Consider the example above, coded as LA R9,X‘260’(0,3).
Again, the object code for this is 41 90 32 60.
Let’s analyze this object code. What it says is the following:
1) Take the contents of register 3 X‘9800’
2) Add the value of the offset X‘260’
3) Add the contents of the index X‘000’
(here no index register is used)
4) Get the value X‘9A60’
5) Place that value into register R9, which now contains X‘0000 9A60’.
But note: While we call this an address, it is really just an unsigned binary number.
This gives rise to a common use of the LA instruction to load a constant
value into a general–purpose register.

LA: Load Register with Explicit Value


Consider the instruction LA R8,4(0,0).
The object code for this is 41 80 00 04.
The code is executed assuming no base register and no index register.
The number 4 is computed and loaded into register 8.
The following instruction is considered identical: LA R8,4.
Note that the second operand in this form of the instruction is a non–negative
integer that is treated by the assembler as a displacement.
This implies that the value must be in a form that can be represented as a 12–bit unsigned
integer, specifically that it must be a non–negative integer not larger than 4,095 (decimal).
Consider now the line from the standard ending code of our programs.
LA R15,0 RETURN CODE = 0
This places the value 0 into the destination register.

Instructions: Surface Meaning and Uses


In the previous example, we see a trick that is commonly used by assembly language
programmers: find what the instruction really does and exploit it. The surface meaning of the
LA instruction is simple: load the address of a label or symbolic address into a given register.
The usage to load a register with a small non–negative constant value is an immediate and
logical result of the way the object code is executed. The goals of such tricks seem to be:
1) To gain coding efficiency, and
2) To avoid addressing problems that sometimes arise in the use of literals.

Page 231 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Storing Register Values: ST, STH, and STM


ST (Store Full Word) is a type RX instruction, with format ST R1,D2(X2,B2).
STH (Store Half Word) is a type RX instruction, with format STH R1,D2(X2,B2).
STM (Store Multiple) is a type RS instruction, with format STM R1,R3,D2(B2).
The ST instruction stores the full–word contents of the register, specified in the
first operand, into the full word at the address specified by the second operand.
The STH instruction stores the rightmost 16 bits of the register specified by the
first operand into the half word at the address specified by the second operand.
For STM (Store Multiple Registers), the first two operands specify a range of
registers to be stored. Remember that the register numbers “wrap around”
STM R7,R10,X2 STORE THE FOUR REGISTERS R7,R8,R9,AND R10
INTO FOUR FULL-WORDS BEGINNING AT X2
STM R10,R7,X4 STORE THE 14 REGISTERS R10 THROUGH R7
(ALL BUT R8 AND R9) INTO 14 FULL-WORDS
While each of these instructions is quite similar to its load register partner, we shall
spend a bit of time discussing the instructions. After all, this is a textbook.

ST: Store Fullword


The ST (Store Full Word) is a type RX instruction, with format ST R1,D2(X2,B2)
and opcode X‘50’. The object code format is as follows:
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘50’ R1 X2 B2 D2 D2D2
The first operand specifies any general–purpose register. This is indicated by the first
hexadecimal digit in the second byte of the object code.
The second operand references a full–word in storage, usually aligned on a full–word
boundary. The address of this second word is computed from the standard base/displacement
form (B2 D2 D2 D2 in bytes 3 and 4) with an index register (the second hexadecimal digit in
byte 2). Here is a template for the instruction: ST Reg,Full_Word
Here are some examples of common usage. Other examples will be discussed later.
Suppose that R3 contains the decimal value 163840, which is X‘0002 8000’.
ST1 ST R3,F1
ST2 ST R3,H1 NOTE THE TYPE MISMATCH.
F1 DC X‘0000 0000’
H1 DC X‘0000’
H2 DC X‘0000’
The instruction at address ST1 works as advertised, storing the register value into the
fullword at the given address. The instruction at address ST2 is almost certainly a mistake.
The register value is stored into the four bytes beginning at address H1. Halfword H1 is set
to the value X‘0002’ and halfword H2 is set to the value X‘8000’.

Page 232 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

STH: Store Halfword


The STH (Store Half Word) is a type RX instruction, with format ST R1,D2(X2,B2)
and opcode X‘40’. This instruction stores the rightmost 16 bits (bits 16 – 31) of the source
register into the halfword at the given address. The object code format is as follows:
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘40’ R1 X2 B2 D2 D2D2
The first operand specifies any general–purpose register. This is indicated by the first
hexadecimal digit in the second byte of the object code.
The second operand references a half–word in storage, usually aligned on a half–word
boundary. The address of this second word is computed from the standard base/displacement
form (B2 D2 D2 D2 in bytes 3 and 4) with an index register (the second hexadecimal digit in
byte 2). Here is a template for the instruction: ST Reg,Half_Word
Here are some examples of common usage. Other examples will be discussed later.
Suppose that R3 contains the decimal value 163840, which is X‘0002 8000’.
ST1 STH R3,F1 NOTE THE TYPE MISMATCH.
ST2 STH R3,H1
F1 DC X‘0000 0000’
H1 DC X‘0000’
H2 DC X‘0000’
The instruction at address ST2 works as advertised, though perhaps not as intended. The
rightmost 16 bits of register R3 contain a value represented in hexadecimal as X‘8000’.
This value is copied into the halfword at address H1, correctly setting its value.
The instruction at address ST1 is almost certainly a mistake. It loads the halfword at address
F1 with the hexadecimal value X‘8000’. Note that it does not matter that the assembly
listing defines F1 as a fullword. The halfword at address F1 comprises the two bytes, the
first at address F1 and the second at address F1+1. After this instruction is executed, F1
contains the value X‘8000 0000’; the rightmost 16 bits have been copied into the two
leftmost bytes associated with the address F1.

STM: Store Multiple Registers


The STM instruction stores data from one or more registers into main memory.
The instruction is a type RS with format STM R1,R3,D2(B2). The opcode is X‘98’.
This is a four–byte instruction with object code format as follows:
Type Bytes Operands 1 2 3 4
RS 4 R1,R3,D2(B2) X‘98’ R1 R3 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number. These
two bytes specify the range of registers to be loaded.

Page 233 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

The third and fourth bytes together contain a 4–bit register number and 12–bit displacement
used to specify the memory address of the operand in storage. This operand is considered as
the first fullword a block of fullwords; the size of the block is determined by the number of
registers specified in byte 2. This is a type RS instruction; indexed addressing is not used.
Since this is a type RS instruction, indexed addressing is not used.
Recall that each label in the assembly language program references an address,
which must be expressed in the form of a base register with displacement.
Any address in the format of base register and displacement will appear in the form.
B D1 D2 D3
B is the hexadecimal digit representing the base register.
The register numbers “wrap around”, so that 15,1 specifies the three registers 15, 0, 1.
Example code:
STM R6,R8,F1 STORE R6, R7, R8 INTO F1, F2, F3
STM R15,R2,F1 STORE R15, R0, R1, R2 INTO
F1, F2, F3, F4
F1 DC F‘1111’
F2 DC F‘2222’
F3 DC F‘3333’
F4 DC F‘4444’

Standard Boilerplate Code


Once again, we examine some of the standard code used in all of our programs.
The standard startup code includes the following fragment.
SAVE (14,12) SAVE THE CALLER’S REGISTERS
This macro generates the following code.
STM 14,12,12(13) STORE REGISTERS 14 THROUGH 12
(15 IN ALL) INTO THE ADDRESS
12 OFFSET FROM BASE REGISTER 13.
We might have concluded our code with the macro
RETURN (14,12)
This expands into the code we actually use in our programs.
LM 14,12,12(13)
LA R15,0 RETURN CODE = 0
BR R14 RETURN TO OPERATING SYSTEM

Page 234 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Binary Arithmetic: Addition and Subtraction


There are six instructions for addition and subtraction.
Mnemonic Description Type Format
A Add full–word to register RX A R1,D2(X2,B2)
S Subtract full–word from register RX S R1,D2(X2,B2)
AH Add half–word to register RX AH R1,D2(X2,B2)
SH Subtract half–word from register RX SH R1,D2(X2,B2)
AR Add register to register RR AR R1,R2
SR Subtract register from register RR SR R1,R2
In each of these, the first operand is a register. It is this register that has its
value changed by the addition or subtraction.
For the half–word instructions (AH and SH), the second operand references a half–word
storage location. The 16–bit contents of this location are sign extended to a full 32–bit word
before the arithmetic is performed.

Binary Arithmetic: Half–word arithmetic


Examples of the instructions
L R7,FW1 LOAD REGISTER FROM FW1
A R7,FW2 ADD FW2 TO REGISTER 7
S R7,=F‘2’ SUBTRACT 2 FROM R7
ST R7,FW3 STORE VALUE IN R7 INTO FW3
AR R7,R8 ADD CONTENTS OF R8 TO R7
SR R7,R9 SUBTRACT R9 FROM R7
SR R8,R8 SET R8 TO ZERO
FW1 DC F‘2’
FW2 DC F‘4’
FW3 DC F‘0’
As noted indirectly above, one has two options for operating on one register.
AR R7,R7 DOUBLE THE CONTENTS OF R7
(ADD R7 TO ITSELF)
SR R9,R9 SET R9 TO ZERO.

Page 235 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Comparing Binary Data: C, CH, and CR


There are three instructions for binary comparison with the value in a register.
Mnemonic Description Type Format
C Compare full–word RX C R1,D2(X2,B2)
CH Compare half–word RX CH R1,D2(X2,B2)
CR Compare register to register RR CR R1,R2
Each comparison sets the expected condition code.
Condition Condition Code Branch Taken
Operand 1 = Operand 2 0 (Equal/Zero) BE, BZ
Operand 1 < Operand 2 1 (Low/Minus) BL, BM
Operand 1 > Operand 2 2 (High/Plus) BH, BP
Don’t forget that literal arguments can be used with either C or CH, as in this example.
C R9,=F‘0’ COMPARE THE REGISTER TO ZERO
BH ISPOS IT IS POSITIVE
BL ISNEG NO, IT IS NEGATIVE.
If this line is reached, R9 contains the value 0.

An Extended Example
This example takes the value in HW1, makes it non–negative, and then sums
backwards N + (N – 1) + … + 2 + 1 + 0.
SR R6,R6 SET R6 TO ZERO
LH R5,HW1 GET THE VALUE INTO R5
SR R6,R5 SUBTRACT TO CHANGE THE SIGN
C R6,=F‘0’ IS R6 POSITIVE? (IF SO R5 IS NEGATIVE)
BH POS YES R6 IS POSITIVE.
LR R6,R5 R5 IS NOT NEGATIVE. COPY R5 INTO R6
* NOW R6 CONTAINS THE ABSOLUTE VALUE OF THE HALF-WORD
POS SR R5,R5 R5 WILL HOLD THE TOTAL. SET TO ZERO.
LOOP AR R5,R6 ADD R6 TO R5
S R6,=F‘1’ DECREMENT R5 BY 1
C R6,=F‘0’ IS THE VALUE STILL POSITIVE?
BH LOOP YES, GO BACK AND ADD AGAIN.
* THE SUM IS FOUND IN R5.

Page 236 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Register Shift Operations


We now discuss a number of shift operations performed on registers.
Mnemonic Description Type Format
SLA Shift left algebraic RS SLA R1,D2(B2)
SRA Shift right algebraic RS SRA R1,D2(B2)
SLL Shift left logical RS SLL R1,D2(B2)
SRL Shift right logical RS SRL R1,D2(B2)
SLDA Shift left double algebraic RS SLDA R1,D2(B2)
SRDA Shift left double algebraic RS SRDA R1,D2(B2)
SLDL Shift left double logical RS SLDL R1,D2(B2)
SRDL Shift right double logical RS SRDL R1,D2(B2)
The algebraic shifts preserve the sign bit in a register, and thus are useful for arithmetic.
The logical shifts do not preserve the sign bit.
The shift operations set the standard condition codes, for use by BC and BCR.
The register numbers for the double shift instructions must be an even number,
referencing the first of an even–odd register pair (see below).

Shift Instructions: Object Code Format


All shift instructions are four–byte instructions of the form OP R1,R3,D2(B2).
Type Bytes 1 2 3 4
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2

The first byte contains the 8–bit instruction code.


The second byte contains two 4–bit fields, each of which encodes a register number.
The first register number (R1) is the register to be shifted. The second register number
(R3) is not used and conventionally set to 0.
The third and fourth bytes contain a 4–bit register number and 12–bit value. In many
type RS instructions, these would indicate a base register and a displacement to be
used to specify the memory address for the operand in storage.
For the shift instructions, this field is considered as a value to indicate the shift count.
The value is in the form below. B is the number of the register to be used as a base
for the value. The next three hexadecimal digits are added to the value in that register.
B D1 D2 D3

Page 237 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

The sum is used as a shift count, not as an address. The two conventional uses are to specify
a constant shift count and to use a register to contain the shift count. Consider the following
two examples, each of which uses the SRA instruction with opcode X‘8A’.
Object Code Source Code
8A 90 00 0A SRA 9,10 BASE REGISTER = 0, DISPLACEMENT
= 10; THE SHIFT COUNT IS 10.
8A 90 B0 00 SRA 9,0(11) HERE REGISTER 11 (X‘B’) CONTAINS
THE SHIFT COUNT.

Example Object Code Analysis: SLL


Shift Left Logical Operation code = X‘89’
This is also a type RS instruction, though the appearance of a typical use seems to deny
this. Consider the following instruction which shifts R6 left by 12 bits.
SLL R6, 12 Again, I assume we have set R6 EQU 6
The above would be assembled as 89 60 00 0C, as decimal 12 is X‘C’.
The deceptive part concerns the value 12, used for the shift count. Where is that stored?
The answer is that it is not stored, but is used as a value for the shift count.
The object code 00 0C literally indicates the computation of a value that is an sum of
decimal 12 from the value in base register 0. But “0” indicates that no base register is
used, hence the value for the shift is decimal 12.
Here are three lines from a working program I wrote on 2/23/2009.
000014 5840 C302 00308 47 L R4,=F’1’
000018 8940 0001 00001 48 SLL R4,1
00001C 8940 0002 00002 49 SLL R4,2
Note that the load instruction makes use of a literal. The assembler will create an entry in the
literal pool and populate it with the value 1. Here, my code calls for register 12 (X‘C’) to
serve as the base register. The literal is stored at offset X‘302’ from the address stored
in that base register.
While it might seem plausible that the SLL instructions similarly generate literals, this is not
the case. In each, as noted above, the value is stored as a count in the base/displacement
format, which is here pressed into duty to store a value and not an address.

Page 238 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Single Shifts: Algebraic and Logical


Here are some diagrams describing shifts in a single register. These examples will
assume an 8–bit register with the IBM bit numbering scheme; 32 bits are hard to draw.
This figure illustrates logical shifts by 1 for these imaginary 8–bit registers.

This figure illustrates algebraic shifts by 1 for these imaginary 8–bit registers.

The actual IBM assembler shift instructions operate on 32–bit registers and can shift by
any number of bit positions. For single register shifts, the shift count should be a
non–negative integer less than 32. For double register shifts, the upper limit is 63.

Double Register Shifts


Each of these four instructions operates on an even–odd register pair.
The algebraic shifts preserve the sign bit of the even register; the logical shifts do not.
Here is a diagram illustrating a double algebraic right shift.

If the above example were a logical double right shift, a 0 would have been
inserted into the leftmost bit of the even register.
Remember to consider the shifts in register pairs, preferably even–odd pairs.
Consider the following code: SR R9,R9 This clears R9
SRDL R8,32
The double–register right shift moves the contents of R8 into R9 and clears R8,
as it is a logical shift.

Page 239 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Single Register Left Shifts: Another View


First consider the left shifts. There are two single–register variants: SLL and SLA.

For an N–bit logical left shift, bits 0 through (N – 1) are shifted out of the register
and discarded. Bits 31 through (32 – N) are filled with 0.
Bit 0 is not considered as a sign bit in a logical shift; it may change values.
For an N–bit arithmetic left shift, bits 1 through N are shifted out of the register
and discarded. Bits 31 through (32 – N) are filled with 0. Bit 0 (the sign bit)
is not changed.
The overflow bit can be set by an arithmetic left shift. This will occur if
the bit shifted out does not match the sign bit that is retained in bit 0.
We shall see later that setting the overflow bit indicates that the result of the
shift cannot be viewed as a valid result of an arithmetic operation.

Single Register Right Shifts: Another View


Now consider the left shifts. There are two single–register variants: SRL and SRA.

For either of these shift types, a shift by N bit will cause the N least significant bits
to be shifted out of the register and discarded.
For an N–bit logical right shift, the value 0 is shifted into the N most significant bits,
bits 0 through (N – 1) of the register. Bit 0 is not considered a sign bit and is
shifted into bit N of the register. The sign of the number may change.
For an N–bit arithmetic right shift, bit 0 is considered as a sign bit. Bit 0 is not changed,
but is shifted into bits 1 through N of the register. At the end, the (N + 1) most
significant bits of the register contain what used to be bit 0 (the sign bit).
For an arithmetic right shift, the sign of the shifted result is the same as that of the
original. If the sign bit originally is 0, the SRL and SRA produce identical results.

Page 240 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Double Register Shifts: Another View


The double register shifts are just generalizations of the single register shifts.

In these double register shifts, a pair of registers is viewed as a single 64–bit value.
The IBM coding convention (and possibly the CPU hardware) calls for this pair to be
what is called an even–odd pair, in which the odd number is one more than the even.
Examples of even–odd register pairs are: 4 and 5, 6 and 7, 8 and 9, 10 and 11.
Consider the two registers R5 and R6. While it is true that 5 is an odd number
and 6 is an even number; these two registers do not form an even–odd pair.
Each of these is a member of a distinct even–odd pair.

Shift Examples
Here are some typical shift examples, with comments.
SRA R9,2 Algebraic right shift by 2 bit positions, equivalent to division
by 4. SRA by N bit positions is equivalent to division by 2N.
SLA R8,3 Algebraic left shift by 3 bit positions, equivalent to multiplication
by 8. SLA by N bit positions is equivalent to multiply by 2N.
NOTE: Multiplication using the M, MH, or MR instructions is rather slow, as is
division with either D or DR. It is almost universal practice to use
arithmetic left shifts to replace multiplication by a power of 2 and
arithmetic right shifts to replace division by a power of 2.
Example: Consider the following three lines of code.
L R5,AVAL ASSUME AVAL IS THE LABEL FOR A FULL-WORD
LR R6,R5 COPY VALUE INTO R6
SRA R6,3 SAME AS MULTIPLY BY 8
AR R6,R5 R6 NOW HAS 9 TIMES THE VALUE IN R5.

Page 241 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

More on Shifting and Arithmetic


The association of arithmetic left shifting with multiplication, and arithmetic right
shifting with division is useful. However, there are limits to this interpretation.
To illustrate this for multiplication, I select an integer that is a simple power of 2,
4096 = 212. As a 16–bit integer, this would be stored in memory as follows.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0

Taking the two’s complement of the above, we find that –4096 is stored as follows.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0

We shall use each of these two integer values to illustrate the limits of the arithmetic
left shift. We shall then consider the following pair as subject to an arithmetic right shift.
+32 = 25 is stored as follows.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0

–32 is stored as follows.


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0

Arithmetic Left Shifts as Multiplication


We first consider some left shifts that can validly be interpreted as multiplication.
For each of these integers, consider a SLA 2 (Arithmetic Left Shift by 2 bit positions).
According to our interpretation, a SLA 2 should be equivalent to multiplication by 22 = 4.
The 4096 = 212 becomes 16384 = 214. This is as it should be.
40964 = 16384 and 21222 = 214.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0

The –4096 = –(212) becomes –16384 = –(214). This is as it should be.


(–4096)4 = –16384 and –(212)22 = –(214).
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Page 242 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Overflow on Shifting Left (Multiplication)


Consider again 4096 = 212, stored as a 16–bit integer.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0

Consider the result of SLA 3 (Arithmetic Left Shift by 3 bit positions).


According to our interpretation, a SLA 3 should be equivalent to multiplication by 23 = 8.
We note that 40968 = 32768 and 21223 = 215 = 32768.
But, the 4096 = 212 becomes –32768 = –(215). The sign has “gone bad”, as a result of
arithmetic overflow.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

But consider the same operation on –4096 = –(212).


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0

After the shift, we have the proper result; –40968 = –32768.


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

More on Overflow While Shifting Left


In this illustration we continue to focus on 16–bit two’s complement integers.
A 32–bit representation would show the same problem, only at larger values.
Suppose we have the valid integer –32,768 = –(215). This is stored as follows.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Suppose we attempt a SLA (Shift Left Arithmetic) by any positive bit count.
The result will remain the same. The sign bit is always preserved in an arithmetic shift.
In attempting a SLA as a substitute for multiplication by a power of two, we find that.
(–32,768)2 = –32,768.
(–32,768)4 = –32,768.
(–32,768)8 = –32,768.
In other words, once overflow has been hit, SLA ceases to serve as multiplication.

Page 243 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Arithmetic Right Sifting as Division


Here the results are a bit less strange. First consider our positive number, +32.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0

A SRA 4 (Arithmetic Right Shift by 4) should yield 32/16 = 2. It does.


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0

Further shifting this result by 1 bit position will give the value 1 (as expected).
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

However, any more SRA (Arithmetic Right Shifts) will give the value 0.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

This is as expected for integer division, and is not surprising.

More on Arithmetic Right Sifting as Division


Here the results are a bit less strange. Now consider our negative number, –32.
Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0

A SRA 3 (Arithmetic Right Shift by 3) should yield (–32)/8 = (–4). It does.


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0

A SRA 2 (Arithmetic Right Shift by 2) should yield (–4)/4 = (–1). It does.


Sign 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

But note that further Arithmetic Right Shifts continue to produce the result –1.
What we are saying is that (–1) / 2 = –1. If the above is acceptable, then the SRA works well
as a substitution for division by a power of two.

Page 244 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Register Pairs: Multiplication and Division


We now discuss two instructions that, in their full–word variants, demand the use of a
64–bit “double word”. Rather than use the type, we use a pair of registers.
The assembly language definition calls for “even–odd register pairs”.
Each pair of registers is referenced by its (lower numbered) even register.
The standard pairs from the general–purpose registers that are not reserved for other use are
shown in the following list.
R4 and R5 R8 and R9
R6 and R7 R10 and R11
When such a pair is referenced by a multiply or divide instruction, it is treated as
a 64–bit two’s–complement integer with the sign in bit 0 of the even register.
Remember that the bits of a register are numbered left to right, so that bit 0 is
the sign bit and bit 31 is the rightmost (least significant) bit.
Examples: M R4,F2 MULTIPLY VALUE IN R5 BY VALUE IN
FULL-WORD F2. RESULTS IN (R4, R5)
D R6,F3 DIVIDE 64-BIT NUMBER IN (R6, R7) BY F3

Full–Word Multiplication
This slide will cover the two multiplication instructions based on full words.
The half–word multiplication instruction will be discussed later.
The two instructions of interest here are:
Mnemonic Description Type Format
M Multiply full–word RX M R1,D2(X2,B2)
MR Multiply register RR MR R1,R2
For each of these, one uses a selected even–odd pair to hold the 64–bit product.
Here is the status of the registers in the selected pair; think (4, 5) or (8, 9), etc.
Even Register Odd Register
Before multiplication Not used: contents are ignored Multiplicand
After multiplication Product: high–order 32 bits Product: low–order 32 bits

If the product can be represented as a 32–bit number, the even register will contain
the extended sign bit, so that the 64–bit number in the register pair has the right sign.
Note that the multiplication overwrites the value of the multiplicand in the odd register.

Page 245 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Full–Word Multiplication: Examples


In the first fragment, the starting value in R4 is irrelevant, as it is ignored.
Each example assumes two full–words: MULTCAND and MULTPLER.
L R5,MULTCAND LOAD THE MULTIPLICAND INTO R5.
SR R4,R4 CLEAR R4. THIS IS REALY USELESS.
M R4,MULTPLER MULTIPLY BY A FULLWORD
* R4 NOW HAS BITS 0 – 31 OF THE 64-BIT PRODUCT
* R5 NOW HAS BITS 32 – 63 OF THE 64-BIT PRODUCT
Another code fragment:
L R9,MULTCAND LOAD THE MULTIPLICAND INTO R9.
L R5,MULTPLER LOAD MULTIPLIER INTO R5
MR R8,R5 MULTIPLY BY FULL-WORD VALUE IN R5
* R8 NOW HAS BITS 0 – 31 OF THE 64-BIT PRODUCT
* R9 NOW HAS BITS 32 – 63 OF THE 64-BIT PRODUCT

Half–Word Multiplication
Mnemonic Description Type Format
MH Multiply half–word RX MH R1,D2(X2,B2)
This instruction requires only one register. It is loaded with the multiplicand before the
multiplication, and receives the product.
Note that this is the product of a 32–bit number (in the register) and a 16–bit number
in the half–word in memory. This will result in a 48–bit product.
Of bits 0 – 47 of the product, only bits 16 – 47 are retained and kept in the 32–bit
register as the product. If the absolute value of the product is greater than 231, the sign
bit of the result (as found in the register) might not be the actual sign of the product.
Here is an example of a proper use of the instruction, which will give correct results.
LH R3,MULTCAND Each of these two arguments is a half–word
MH R3,MULTPLER with value in the range: –215  N  (215 – 1).
MULTCAND DC H‘222’
MULTPLER DC H‘44’
The magnitude of the product will not exceed (215)(215) = 230, an easy fit for a register.

Page 246 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Full–Word Division
This slide will cover the two division instructions based on full words.
The half–word division instruction will be discussed later.
The two instructions of interest here are:
Mnemonic Description Type Format
D Divide full–word RX D R1,D2(X2,B2)
DR Divide register RR DR R1,R2
For each of these, one uses a selected even–odd pair to hold the 64–bit dividend.
Here is the status of the registers in the selected pair; think (4, 5) or (8, 9), etc.
Even Register Odd Register
Before division Dividend: high–order 32 bits Dividend: low–order 32 bits
After division Remainder from division Quotient from division

In each of the full–word division operations, it is important to initialize the even register
of the pair correctly. There are two cases to consider.
1. The dividend is a full 64–bit number, possibly loaded with a LM instruction.
2. The dividend is a 32–bit number. In that case, we need to initialize both registers.

Full–Word Division: Example 1


In this example, I am assuming a full 64–bit dividend that is stored in two adjacent
full words in memory. I use this memory structure to avoid adding anything new.
LM R10,R11, DIVHI LOAD TWO FULLWORDS
D R10,DIVSR NOW DIVIDE
* R10 CONTAINS THE REMAINDER
* R11 CONTAINS THE QUOTIENT
DIVHI DC F‘1111’ ARBITRARY NUMBER THAT IS NOT TOO BIG
DIVLO DC F‘0003’ ANOTHER ARBITRARY NUMBER
DIVSR DC F‘19’ THE DIVISOR
Important Note: This process of assembling a 64–bit dividend from two full words
might run into problems if DIVLO is seen as negative.
Here, I choose to ignore that point.

Page 247 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Full–Word Division: Example 2


In this example, I am assuming a 32–bit dividend and using a more standard
approach. Please note that it works only for positive dividends.
SR R10,R10 SET R10 TO 0
L R11,DIVIDEND LOAD FULL–WORD DIVIDEND
D R10,DIVISOR DO THE DIVIDING
* R10 CONTAINS THE REMAINDER
* R11 CONTAINS THE QUOTIENT
DIVIDEND DC F‘812303 JUST SOME NUMBER.
DIVISOR DC F‘16384’ A POWER OF TWO, SEE NOTE BELOW
NOTES: 1. This works only for a positive dividend. The reason is that, by clearing
the even register of the even–odd pair, I have declared the 64–bit dividend
to be a positive number, even if R11 is loaded with a negative number.
2. There is a much faster way to divide any number by a power of two.
This method, using a shift instruction, will be discussed later.

Full–Word Division: Example 3


In this example, I am assuming a 32–bit dividend and using the standard approach
that will work correctly for all dividends. The dividend is first loaded into the even
register of the even–odd pair and then shifted into the odd register.
This shifting causes the sign bit of the 64–bit dividend to be set correctly.
L R10,DIVIDEND LOAD INTO THE EVEN REGISTER
SRDA R10,32 SHIFTING BY 32 BITS PLACES
* THE DIVIDEND INTO R11.
* R10 RETAINS THE SIGN BIT D
R10,DIVISOR DO THE DIVIDING
* R10 CONTAINS THE REMAINDER
* R11 CONTAINS THE QUOTIENT
DIVIDEND DC F‘812303 JUST SOME NUMBER.
DIVISOR DC F‘16384’ A POWER OF TWO, SEE NOTE BELOW
We shall discuss this a bit more after we have discussed the shift operations.

Page 248 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Full–Word Division: Example 4


Here is a more realistic example of the use of a full 64–bit dividend.
Code fragment 1: Create the 64–bit product and store in adjacent full words.
L R5,MCAND LOAD THE MULTIPLICAND INTO R5.
M R4,MPLER MULTIPLY BY A FULLWORD
* R4 NOW HAS BITS 0 – 31 OF THE 64-BIT PRODUCT
* R5 NOW HAS BITS 32 – 63 OF THE 64-BIT PRODUCT STM
R4,R5,PRODHI STORE THE 64-BIT PRODUCT
Code fragment 2: Some time later use the 64–bit product as a dividend for division.
LM R10,R11,PRODHI LOAD TWO FULLWORDS
D R10,DIVSR NOW DIVIDE
* R10 CONTAINS THE REMAINDER
* R11 CONTAINS THE QUOTIENT
PRODHI DC F‘0’ TWO FULL WORDS SET ASIDE
PRODLO DC F‘0’ 64 BITS (8 BYTES) OF STORAGE.

Diversion: Shifting the Dividend into Place


Consider two possible dividends: + 100 and – 100.
Consider the code fragment below.
LH R6,=H‘100’
SRDA R6,32
After the first instruction is executed, register R6 contains the full–word value +100, as
shown below.
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
0000 0000 0000 0000 0000 0000 0110 0100

After the shift in the second instruction, the contents of R6 have been shifted to R7,
leaving only the sign bit in R6.

R6
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
0000 0000 0000 0000 0000 0000 0000 0000

R7
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
0000 0000 0000 0000 0000 0000 0110 0100

Page 249 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Shifting the Dividend Into Place (Part 2)


Now consider the code fragment.
LH R8,=H‘-100’
SRDA R8,32
After the first instruction is executed, register R8 contains the full–word value –100,
as shown below.
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
1111 1111 1111 1111 1111 1111 1001 1100

After the shift in the second instruction, the contents of R8 have been shifted to R9,
leaving only the sign bit in R8.

R8
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
1111 1111 1111 1111 1111 1111 1111 1111

R9
0–3 4–7 8 – 11 12 – 15 16 – 19 20 – 23 24 – 27 28 – 31
1111 1111 1111 1111 1111 1111 1001 1100

Boolean Operators: AND, OR, XOR


We now conclude our investigation of binary integer data by examining the Boolean
operators, which treat binary data one bit at a time. We shall repeat the basic definitions,
discuss the implementation by IBM, and close by repeating a natural application. The three
Boolean operators directly supported by IBM are the logical AND, OR, and NOT.
Each of these operates on binary data, one bit at a time according to the following tables.
AND 00 = 0 OR 0+0 = 0 XOR 00 = 0
01 = 0 0+1 = 1 01 = 1
10 = 0 1+0 = 1 10 = 1
11 = 1 1+1 = 1 11 = 0
To show the bitwise nature of these operations, we consider a few examples as
applied to four–bit integers.
1010 1010 0101 0101 0101
 0111  1101 + 0000 + 1111  1111
0010 1010 0101 1111 1010
Note that the XOR function can be used to generate the Boolean not function. The Boolean
NOT, denoted by and defined by . As seen above, this can be extended
bitwise, so that the rightmost example takes the logical NOT of the digits 0101.

Page 250 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

One of the more natural uses of the Boolean operators is to do bitwise operations on data
represented in 8–bit bytes and denoted by two 4–bit hexadecimal digits. There are three
operations that will commonly be seen in assembly language programs.
1. Select a bit position in a byte and force that bit to have the value 1.
2. Select a bit position in a byte and force that bit to have the value 0.
3. Select a bit position in a byte and flip the value of that bit.
We shall examine the use of these operations on 4–bit fields, as longer data structures
can be analyzed one hexadecimal digit at a time. We use the IBM bit numbering.
Bit number 0 1 2 3
Bit value 8 4 2 1
Here are the basic masking operations that can be performed on a 4–bit hexadecimal digit.
Bits Affected To set the bit, use OR with To clear the bit, use AND with
None 0000 X‘0’ 1111 X‘F’
0 1000 X‘8’ 0111 X‘7’
1 0100 X‘4’ 1011 X‘B’
2 0010 X‘2’ 1101 X‘D’
3 0001 X‘1’ 1110 X‘E’
0 and 1 1100 X‘C’ 0011 X‘3’
0 and 2 1010 X‘A’ 0101 X‘5’
0 and 3 1001 X‘9’ 0110 X‘6’
1 and 2 0110 X‘6’ 1001 X‘9’
1 and 3 0101 X‘5’ 1010 X‘A’
2 and 3 0011 X‘3’ 1100 X‘C’
0, 1, and 2 1110 X‘E’ 0001 X‘1’
0, 1, and 3 1101 X‘D’ 0010 X‘2’
0, 2, and 3 1011 X‘B’ 0100 X‘4’
1, 2, and 3 0111 X‘7’ 1000 X‘8’
ALL 1111 X‘F’ 0000 X‘0’
System/370 architecture supports three Boolean functions, each in four formats.
Instruction Format Operands
Logical AND Logical OR Logical XOR
NR OR XR RR Two registers
N O X RX Register and storage
NI OI XI SI Register and immediate
NC OC XC SS Two storage locations
Each of these twelve instructions sets the condition codes used by the conditional branch
instructions in the same way. If every bit in the result is 0, the result is 0 and condition code
0 is set. If any bit in the result is 1, the result is not negative and condition code 1 is set, as if
the result were negative. Here are two equivalent ways to test results.
To determine Yes No
All target bits are 0 Use BZ Use BNZ
Any target bit is 1 Use BM Use BNM

Page 251 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Here are the logical instructions, grouped by type.


Type RR
This is a two–byte instruction of the form OP R1,R2.
Type Bytes Operands
RR 2 R1,R2 OP R1 R2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. This instruction format is used to process data
between registers.
Here are the three Boolean instructions of this type.
NR Logical AND Opcode is X‘14’
OR Logical OR Opcode is X‘16’
XR Logical Exclusive OR Opcode is X‘17’
Type RX
This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The first operand, encoded as R1, is the target
register for the instruction. The second register number, encoded as X2, is the optional index
register. Bytes 3 and 4 together contain the address of the second operand in base and
displacement form, which may be modified by indexing if the index register field is not zero.
Here are the three Boolean instructions of this type.
N Logical AND Opcode is X‘54’
O Logical OR Opcode is X‘56’
X Logical Exclusive OR Opcode is X‘57’
Type SI
This is a four–byte instruction of the form OP D1(B1),I2.
Type Bytes Operands 1 2 3 4
SI 4 D1(B1), I2 OP I2 B1 D1 D1D1
The first byte contains the 8–bit instruction code. The second byte contains the 8–bit value
of the second operand, which is treated as an immediate operand. The instruction contains
the value of the operand, not its address. The first operand is an address, specified in
standard base register and displacement form. Note that this first operand must reference the
address of a single byte, as this is a byte–oriented operation.
Here are the three Boolean instructions of this type.
NI Logical AND Opcode is X‘94’
OI Logical OR Opcode is X‘96’
XI Logical Exclusive OR Opcode is X‘97’

Page 252 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

Type SS
These are of the form OP D1(L,B1),D2(B2), which provide a length for only operand 1.
The length is specified as an 8–bit byte.
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code. The second byte contains a value storing one less
than the length of the first operand, which is the destination for the operation.
Bytes 3 and 4 specify the address of the first operand, using the standard base register and
displacement format. Bytes 5 and 6 specify the address of the second operand, using the
standard base register and displacement format.
Here are the three Boolean instructions of this type.
NC Logical AND Opcode is X‘D4’
OC Logical OR Opcode is X‘D6’
XC Logical Exclusive OR Opcode is X‘D7’
Another Look at Case Conversion
In order to investigate the difference between upper case and lower case letters, we here
present a slightly different version of the EBCDIC table. Admittedly, we have covered this
in a previous chapter, but cover it again within the context of the Boolean operators.
Zone 8 C 9 D A E
Numeric
1 “a” “A” “j” “J”
2 “b” “B” “k” “K” “s” “S”
3 “c” “C” “l” “L” “t” “T”
4 “d” “D” “m” “M” “u” “U”
5 “e” “E” “n” “N” “v” “V”
6 “f” “F” “o” “O” “w” “W”
7 “g” “G” “p” “P” “x” “X”
8 “h” “H” “q” “Q” “y” “Y”
9 “i” “I” “r” “R” “z” “Z”
The structure implicit in the above table will become more obvious when we compare
the binary forms of the hexadecimal digits used for the zone part of the code.
Upper Case C = 1100 D = 1101 E = 1110
Lower Case 8 = 1000 9 = 1001 A = 1010
Note that it is only one bit in the zone that differentiates upper case from lower case.
In binary, this would be noted as 0100 or X‘4’. As this will operate on the zone field of a
character field, we extend this to the two hexadecimal digits X‘40’. The student should
verify that the one’s–complement of this value is X‘BF’. Consider the following operations.

Page 253 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Binary Integer Data

UPPER CASE
‘A’ X’1100 0001’ X’1100 0001’
OR X ‘40’ X‘0100 0000’ AND X ‘BF’ X‘1011 1111’
X’1100 0001’ X’1000 0001’
Converted to ‘A’ ‘a’

Lower case
‘a’ X’1000 0001’ X’1000 0001’
OR X ‘40’ X‘0100 0000’ AND X ‘BF’ X‘1011 1111’
X’1100 0001’ X’1000 0001’
Converted to ‘A’ ‘a’

We now have a general method for changing the case of a character, if need be.
Assume that the character is in a one byte field at address LETTER.
Convert a character to upper case. OI,LETTER,=X‘40’
This leaves upper case characters unchanged.
Convert a character to lower case. NI,LETTER,=X‘BF’
This leaves lower case characters unchanged.
Change the case of the character. XI,LETTER,=X‘40’
This changes upper case to lower case and lower case to upper case.

Page 254 Chapter 12 Last Revised July 6, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 13: Handling Floating Point Data

This chapter presents a brief discussion of floating point data and arithmetic. There are a few
reasons to cover this topic, but none relate to the expectation that a programmer will actually
use this data format in an assembly language program.
The two primary reasons to cover floating point data and arithmetic are simple:
1) So that we can make a plausible claim of a complete coverage of assembler language.
2) So that the student will more fully appreciate some of the complexities (handled by
the run–time system of a HLL) of processing floating point data.
There is another reason for the study; this is one that is found in early texts on assembler
language. It used to be the case that an understanding of floating point format would allow
the programmer to write a High–Level–Language program that was considerably more
efficient. With modern compilers, this is rarely the case.
The first thing to note in this chapter is the difference between floating point data and fixed
point data. It is simple: in the first format the decimal point may be said to float in that it can
assume any position in the data. In the fixed point data, the decimal point is fixed at a
predefined position. The packed decimal format is a good example of a fixed–point format.
Consider the two packed decimal numbers defined as follows:
N1 DC P‘1234’ Stored as X‘01234C’
N2 DC P‘567’ Stored as X‘567C’
From the viewpoint of assembler language, each of these labels is simply a reference to data
in packed decimal format. There is more to the definition than what is stated above. One
must view each declaration in terms of a data type, which is a concept taken from a HLL. In
particular, the data are defined completely only if the number of decimal places is specified.
So, we must ask if the numbers represented by the labels N1 and N2 are of compatible data
type. Again, this cannot be determined from the simple definition. If both values are to be
interpreted with the same number of decimal points, the types are compatible.
Suppose that N1 represents the number 12.34.
Suppose that N2 represents the number 5.67.
The two definitions can be viewed as belonging to a single data type.
Suppose, however that N1 represents the number 1.234, while N2 represents 5.67. Then the
definitions belong to what might be called similar, but incompatible, data types. One of the
two must be modified by a SRP instruction before they are added, or the results will be silly.
One possible redefinition would be as follows:
N1A DC P‘1234’ Stored as X‘01234C’ for 1.234
N2A DC P‘5670’ Stored as X‘05670C’ for 5.670
In the above definition, each constant is defined with three implicit decimal places, and the
two can be said to be of a common data type. We must emphasize that the idea of a data type
is derived from the theory of high–level compiled languages and is somewhat foreign to
assembler language. However, it is very helpful in understanding fixed point arithmetic.

Page 255 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

The basic idea of floating point arithmetic is the explicit storage of a representation of the
position of the decimal point in each data item. That way, the CPU can automatically adjust
the two to the same basic representation, if that is necessary. As we shall see, this adjustment
is required for addition and subtraction, but not multiplication and division.
Consider the above two numbers at labels N1 and N2. Suppose that these are to be
interpreted as 1.234 and 56.7 respectively. In floating–point notation, these would be
represented as 1.234100 and 5.67101, respectively.
Addition might proceed by converting these to 1.234100 and 56.7100, then adding to get
57.934100, which might be converted to either 5.7934101 or 5.793101. Multiplication will
proceed without adjusting either value: 1.234100  5.67101 = 6.99678101, which might be
rounded to 7.00101 , 6.997101 , or some other value.
As noted before, the floating point format has an advantage, which is simultaneously its
disadvantage. The advantage is that the format handles the position of the decimal point
explicitly. The disadvantage is that it might round and thereby lose precision.
At this point, the reader should review the material on floating point formats that is found in
Chapter 4 (Data Representation) of this textbook. The topics for review should be:
1. Conversion between decimal format and hexadecimal representations,
2. Excess–64 representation of integers,
3. normalized and denormalized floating point numbers, and
4. the IBM Mainframe floating point formats.
For the readers convenience, the last topic will be summarized below.
The IBM Mainframe Floating–Point Formats
In this discussion, we shall adopt the bit numbering scheme used in the IBM documentation,
with the leftmost (sign) bit being number 0. The IBM Mainframe supports three formats;
those representations with more bits can be seen to afford more precision.
Single precision 32 bits numbered 0 through 31,
Double precision 64 bits numbered 0 through 63, and
Extended precision 128 bits numbered 0 through 127.
As in the IEEE–754 standard, each floating point number in this standard is specified by
three fields: the sign bit, the exponent, and the fraction. Unlike the IEEE–754 standard, the
IBM standard allocates the same number of bits for the exponent of each of its formats. The
bit numbers for each of the fields are shown below.
Format Sign bit Bits for exponent Bits for fraction
Single precision 0 1–7 8 – 31
Double precision 0 1–7 8 – 63
Extended precision 0 1–7 8 – 127
Note that each of the three formats uses eight bits to represent the exponent, in what is called
the characteristic field, and the sign bit. These two fields together will be represented by
two hexadecimal digits in a one–byte field. The size of the fraction field does depend on the
format. Single precision 24 bits 6 hexadecimal digits,
Double precision 56 bits 14 hexadecimal digits, and
Extended precision 120 bits 30 hexadecimal digits.

Page 256 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

The Characteristic Field


In IBM terminology, the field used to store the representation of the exponent is called the
“characteristic”. This is a 7–bit field, used to store the exponent in excess–64 format; if the
exponent is E, then the value (E + 64) is stored as an unsigned 7–bit number.
Recalling that the range for integers stored in 7–bit unsigned format is 0  N  127, we have
0  (E + 64)  127, or –64  E  63.
Range for the Standard
We now consider the range and precision associated with the IBM floating point formats.
The reader should remember that the range is identical for all of the three formats; only the
precision differs. The range is usually specified as that for positive numbers, from a very
small positive number to a large positive number. There is an equivalent range for negative
numbers. Recall that 0 is not a positive number, so that it is not included in either range.
Given that the base of the exponent is 16, the range for these IBM formats is impressive. It is
from somewhat less than 16–64 to a bit less than 1663. Note that 1663 = (24)63 = 2252, and
16–64 = (24)–64 = 2–256 = 1.0 / (2256) and recall that log10(2) = 0.30103. Using this, we compute
the maximum number storable at about (100.30103)252 = 1075.86  91075. We may approximate
the smallest positive number at 1.0 / (361075) or about 3.010–77. In summary, the following
real numbers can be represented in this standard: X = 0.0 and 3.010–77 < X < 91075.
One would not expect numbers outside of this range to appear in any realistic calculation.
Precision for the Standard
Unlike the range, which depends weakly on the format, the precision is very dependent on
the format used. More specifically, the precision is a direct function of the number of bits
used for the fraction. If the fraction uses F bits, the precision is 1 part in 2F.
We can summarize the precision for each format as follows.
Single precision F = 24 1 part in 224.
Double precision F = 56 1 part in 256.
Extended precision F = 120 1 part in 2120.
The first power of 2 is easily computed; we use logarithms to approximate the others.
224 = 16,777,216
2 56
 (10 0.30103 56
) = 1016.85
 91016.
2120  (100.30103)120 = 1036.12  1.21036.
The argument for precision is quite simple. Consider the single precision format, which is
more precise than 1 part in 10,000,000 and less precise than 1 part in 100,000,000. In other
words it is better than 1 part in 107, but not as good as 1 in 108; hence we say 7 digits.
Range and Precision
We now summarize the range and precision for the three IBM Mainframe formats.
Format Type Positive Range Precision
Single Precision E 3.010–77 < X < 91075 7 digits
Double Precision D 3.010–77 < X < 91075 16 digits
Extended Precision L 3.010–77 < X < 91075 36 digits

Page 257 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Representation of Floating Point Numbers


As with the case of integers, we shall most commonly use hexadecimal notation to represent
the values of floating–point numbers stored in the memory. From this point, we shall focus
on the two more commonly used formats: Single Precision and Double Precision.
The single precision format uses a 32–bit number, represented by 8 hexadecimal digits.
The double precision format uses a 64–bit number, represented by 16 hexadecimal digits.
Due to the fact that the two formats use the same field length for the characteristic,
conversion between the two is quite simple. To convert a single precision value to a double
precision value, just add eight hexadecimal zeroes.
Consider the positive number 128.0.
As a single precision number, the value is stored as 4280 0000.
As a double precision number, the value is stored as 4280 0000 0000 0000.
Conversions from double precision to single precision format will involve some rounding.
For example, consider the representation of the positive decimal number 123.45. In a few
pages, we shall show that it is represented as follows.
As a double precision number, the value is stored as 427B 7333 3333 3333.
As a single precision number, the value is stored as 427B 7333.
The Sign Bit and Characteristic Field
We now discuss the first two hexadecimal digits in the representation of a floating–point
number in these two IBM formats. In IBM nomenclature, the bits are allocated as follows.
Bit 0 the sign bit
Bits 1 – 7 the seven–bit number storing the characteristic.
Bit Number 0 1 2 3 4 5 6 7
Hex digit 0 1
Use Sign bit Characteristic (Exponent + 64)
Consider the four bits that comprise hexadecimal digit 0. The sign bit in the floating–point
representation is the “8 bit” in that hexadecimal digit. This leads to a simple rule.
If the number is not negative, bit 0 is 0, and hex digit 0 is one of 0, 1, 2, 3, 4, 5, 6, or 7.
If the number is negative, bit 0 is 1, and hex digit 0 is one of 8, 9, A, B, C, D, E, or F.
Some Single Precision Examples
We now examine a number of examples, using the IBM single–precision floating–point
format. The reader will note that the methods for conversion from decimal to hexadecimal
formats are somewhat informal, and should check previous notes for a more formal method.
Note that the first step in each conversion is to represent the magnitude of the number in the
required form X16E, after which we determine the sign and build the first two hex digits.
Example 1: True 0
The number 0.0, called “true 0” by IBM, is stored as all zeroes [R_15, page 41].
In single precision it would be 0000 0000.
In double precision it would be 0000 0000 0000 0000.

Page 258 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Example 2: Positive exponent and positive fraction.


The decimal number is 128.50. The format demands a representation in the form X16E,
with 0.625  X < 1.0. As 128  X < 256, the number is converted to the form X162.
Note that 128 = (1/2)162 = (8/16)162 , and 0.5 = (1/512)162 = (8/4096)162.
Hence, the value is 128.50 = (8/16 + 0/256 + 8/4096)162; it is 1620x0.808.
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The fractional part comprises six hexadecimal digits, the first three of which are 808.
The number 128.50 is represented as 4280 8000.
Example 3: Positive exponent and negative fraction.
The decimal number is the negative number –128.50. At this point, we would normally
convert the magnitude of the number to hexadecimal representation. This number has the
same magnitude as the previous example, so we just copy the answer; it is 1620x0.808.
We now build the first two hexadecimal digits, noting that the sign bit is 1.
Field Sign Characteristic
Value 1 1 0 0 0 0 1 0
Hex value C 2
The number 128.50 is represented as C280 8000.
Note that we could have obtained this value just by adding 8 to the first hex digit.
Example 4: Negative exponent and positive fraction.
The decimal number is 0.375. As a fraction, this is 3/8 = 6/16. Put another way, it is
1600.375 = 160(6/16). This is in the required format X16E, with 0.625  X < 1.0.
The exponent value is 0, so the characteristic value is either 64 or 0x40 = 100 0000. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 0 0
Hex value 4 0
The fractional part comprises six hexadecimal digits, the first of which is a 6.
The number 0.375 is represented in single precision as 4060 0000.
The number 0.375 is represented in double precision as 4060 0000 0000 0000.

Page 259 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Example 5: A Full Conversion


The number to be converted is 123.45. As we have hinted, this is a non–terminator.
Convert the integer part.
123 / 16 = 7 with remainder 11 this is hexadecimal digit B.
7 / 16 = 0 with remainder 7 this is hexadecimal digit 7.
Reading bottom to top, the integer part converts as 0x7B.
Convert the fractional part.
0.45  16 = 7.20 Extract the 7,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3, and so on.
In the standard format, this number is 1620x0.7B33333333…...
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The number 123.45 is represented in single precision as 427B 3333.
The number 0.375 is represented in double precision as 427B 3333 3333 3333.
Example 5: One in “Reverse”
We are given the single precision representation of the number. It is 4110 0000.
What is the value of the number stored? We begin by examination of the first two hex digits.
Field Sign Characteristic
Value 0 1 0 0 0 0 0 1
Hex value 4 1
The sign bit is 0, so the number is positive. The characteristic is 0x41, so the exponent is
1 and the value may be represented by X161. The fraction field is 100 000, so the value is
161(1/16) = 1.0.
Example 6: Another in “Reverse”
We are given the single precision representation of the number. It is BEC8 0000.
What is the value of the number stored? We begin by examination of the first two hex digits.
Field Sign Characteristic
Value 1 0 1 1 1 1 1 0
Hex value B E
The characteristic has value 0x3E or decimal 316 + 14 = 62. The exponent has value
62 – 64 = –2. The number is then 16-20x0.C8 = 16-2(12/16 + 8/256), which can be
converted to decimal in any number of ways. I prefer the following conversion.
16-2(12/16 + 8/256) = 16-2(3/4 + 1/32) = 16-2(24/32 + 1/32) = 16-2(25/32)
= 25 / (32256) = 25 / 8192  3.051757810–3.
The answer is approximately the negative number –3.051757810–3.

Page 260 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Why Excess–64 Notation for the Exponent?


We have introduced two methods to be used for storing signed integers: two’s–complement
notation and excess–64 notation. One might well ask why two’s-complement notation is not
used to store the exponent in the characteristic field.

The answer for integer notation is simple. Consider some of examples.


128.50 is represented as 4280 8000. Viewed as a 32–bit integer, this is positive.
–128.50 is represented as C280 8000. Viewed as a 32–bit integer, this is negative.
1.00 is represented as 4110 0000. Viewed as a 32–bit integer, this is positive.
–3.0510–3 is represented as BEC8 0000. Viewed as a 32–bit integer, this is negative

It turns out that the excess–64 notation allows the use of the integer compare unit to compare
floating point numbers. Consider two floating point numbers X and Y. Pretend that they are
integers and compare their bit patterns as integer bit patterns. It viewed as an integer, X is
less than Y, then the floating point number X is less than the floating point Y. Note that we
are not converting the numbers to integer form, just looking at the bit patterns and pretending
that they are integers. For example, the above examples would yield the following order.
4280 8000 for 128.50. This is the largest.
4110 0000 for 1.00.
BEC8 0000 for –3.0510–3.
C280 8000 for –128.50. This is the most smallest (most negative).

Examples of Floating–Point Declaratives


Floating point storage and constants are defined with the standard DS and DC declaratives.
There are three possible formats: E (Single Precision), D (Double Precision) and
L (Extended Precision). Standard programs use the E (Single Precision) format, with
occasional use of the D (Double Precision) format. The L format is probably unusual.
Here are some examples of floating–point declaratives.
FL1 DS E This defines a 4–byte storage area, aligned
on a fullword boundary. Presumably, it
will store Single Precision Data.
DL1 DS D An 8-byte storage area, aligned on a double
word boundary. It could store data in
Double Precision format.
FL2 DS E‘12.34’ Define a single precision value.
FL3 DS E‘-12.34’ The negative of the above value.
DL2 DS D‘0.0’ The constant 0.0, in double precision.
The reader may recall that we have used statements, such as the DL1 declarative, to reserve
an 8–byte storage area aligned on a double–word boundary, for use in the CVB and CVD
instructions associated with packed decimal arithmetic. This emphasizes the fact that the
declaratives do not really determine a data type, but just set aside storage. In assembler
language, it is the instructions that determine the data type.

Page 261 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Before proceeding, we must give a disclaimer. There are a few features of floating–point
arithmetic, such as the exponent modifier and scale modifier, that will not be covered in this
discussion. This discussion will also be limited to normalized floating–point numbers and
totally ignore the unnormalized instructions which handle data not in normalized format.

The Floating–Point Registers


In addition to the sixteen general–purpose registers (used for binary integer arithmetic), the
S/360 architecture provides four registers dedicated for floating–point arithmetic. These
registers are numbered 0, 2, 4, and 6(*). Each is a 64–bit register. It is possible that the use
of even numbers to denote these registers is to emphasize that they are not 32–bit registers.
The use of the registers by the floating–point operations depends on the precision.
Single precision formats use the leftmost 32 bits of a floating–point register.
Double precision formats use all 64 bits of the register.
Extended precision formats use two adjacent registers for a 128 bit number.
In order to understand why it is the leftmost 32 bits of the register that are used for the
32–bit single precision floating–point format, we must consider what is involved in
extending the single precision format to a double precision format.
Consider the single–precision constant 123.45, which would be represented by the
32–bit (8 hexadecimal digit) constant 427B 3333. Were this to be extended to double
precision, it would be stored as the 64–bit constant 427B 3333 0000 0000. In other
words, each floating point register stores a value as if it were a double–precision value; the
single–precision values being stored as values with limited precision.
As we saw above, a conversion of 123.45 directly to the double–precision floating–point
format would yield the value 427B 3333 3333 3333, rather than the truncated value
427B 3333 0000 0000 seen above. Put another way, single–precision values stored as
double precision are not as precise as true double–precision constants.
To make this point completely obvious, suppose that a 64–bit floating–point register contains
the following value, expressed as 16 hexadecimal digits.
Byte 0 1 2 3 4 5 6 7
Value 42 7B 33 33 33 33 33 33

An E format (Single Precision) floating–point reference to this register would access only the
leftmost four bytes and use the value 427B 3333. A D format (Double Precision) floating–
point reference would access all eight bytes and use the value 427B 3333 3333 3333.
Each reference should correspond to the decimal value 123.45, just with different precision.
As a side note, some early versions of FORTRAN might print the above number at
something like 123.449999, due to the fact that 123.45 cannot be represented exactly as a
floating–point number. The FORMAT statement provided by the FORTRAN run–time
system was modified to round this value to 123.45.
* Modern System/z architecture supports 16 floating–point registers, numbered 0 – 15. The
additional registers (1, 3, 5, and 7 – 15) are useable if the AFPR option has been selected in
the ACONTROL instruction for the code. [R-17, page 100]

Page 262 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

The Floating–Point Instructions


The floating–point instruction set is less extensive than the binary integer instruction set, but
bears some similarities. The instructions are in two formats: RR (Register to Register) and
RX (Register and Indexed Storage). Obviously the register reference in these instructions are
the floating–point registers. The mnemonics for the instructions are structured into three
parts: a one or two character code for the operation, followed by a character indicating the
precision, then either a blank for type RX or an ‘R’ for type RR.
The Load Instructions
The load instructions load a 64–bit floating point register from either storage or another
floating–point register. The valid register numbers are 0, 2, 4, or 6.
LE R1,D2(X2,B2) Load R1 single precision from memory
Operand 2 is an aligned fullword;
its address is a multiple of 4.
LD R1,D2(X2,B2) Load R1 double precision from memory
Operand 2 is an aligned double word;
its address is a multiple of 8.
LER R1,R2 Load the leftmost 32 bits of R1
from the leftmost 32 bits of R2.
LDR R1,R2 Load the 64-bit register R1 from
the 64-bit register R2.
Neither LE or LER change the rightmost 32 bits of the target floating–point register.
The opcodes for the two type RR instructions are as follows:
LER X‘38’ LDR X‘28’
The object code format for these type RR instructions follows the standard. Each is a
two–byte instruction of the form OP R1,R2.
Type Bytes Operands
RR 2 R1,R2 OP R1 R2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number.
This instruction format is used to process data between registers.
The opcodes for the two type RX instructions are as follows:
LE X‘78’ LD X‘68’
Each is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The third and fourth bytes contain an address in
the standard base/displacement with index register format. The load instructions do not set
any condition code.

Page 263 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

The Store Instructions


There are two store instructions for storing either the leftmost 32 bits or all 64 bits
of the 64 bit floating–point registers. Again, the valid register numbers are 0, 2, 4, or 6.
STE R1,D2(X2,B2) Store the 32 leftmost bits of register R1
as a single precision result into the
aligned fullword address.
STD R1,D2(X2,B2) Store the 64 bits of register R1 as a
double precision result into the aligned
double word address.
The opcodes for these two instructions are as follows:
STE X‘70’ STD X‘60’.
Each is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The third and fourth bytes contain an address in
the standard base/displacement with index register format.
The rules for forming the address of operand 2 in each of the above instructions follow
the standard for type RX instructions. Again, the only new feature is that the address of the
operand must be properly aligned. In practice that means using the proper declarative for
specifying the storage.
Single precision Use DS E or DC E, to insure that the address is a multiple of 4.
Double precision Use DS D or DC D, to insure that the address is a multiple of 8.
Sample Code
LOAD1 LE 0,FL1 LOAD FP REG 0 FROM ADDRESS FL1
LOAD2 LD 2,FL2 LOAD DOUBLE PRECISION
LOAD3 LER 4,0 COPY SINGLE PRECISION INTO FP REG 4
LOAD4 LDR 6,2 COPY DOUBLE PRECISION INTO FP REG 6
STORE1 STE 6,FL3 STORE THE SINGLE PRECISION INTO FL3
STORE2 STD 6,FL4 STORE DOUBLE PRECISION INTO FL4
FL1 DC E‘123.45’ A SINGLE PRECISION FLOATING POINT
CONSTANT. ADDRESS IS A MULTIPLE OF 4.
FL2 DC D‘45678.90’ A DOUBLE PRECISION FLOATING POINT
CONSTANT. ADDRESS IS A MULTIPLE OF 8.
FL3 DS E JUST RESERVE AN ALIGNED FULLWORD
FL4 DS D RESERVE AN ALIGNED DOUBLE WORD.
Note that the contents of register 6 are first stored as a single precision result, then
as a double precision result.

Page 264 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Addition and Subtraction


There are four distinct addition instructions and four distinct subtraction instructions for
normalized floating–point numbers. These instructions are as follows:
Mnemonic Operation Opcode Operand Format
AE Add single precision 7A R1,D2(X2,B2)
AD Add double precision 6A R1,D2(X2,B2)
AER Add register single precision 3A R1,R2
ADR Add register double precision 2A R1,R2
SE Subtract single precision 7B R1,D2(X2,B2)
SD Subtract double precision 6B R1,D2(X2,B2)
SER Subtract register single precision 3B R1,R2
SDR Subtract register double precision 2B R1,R2
Subtraction functions by changing the sign of the second operand and then performing an
addition. The first step in each is ensuring that the characteristics of both operands are equal.
If unequal, the field with the smaller characteristic is adjusted by shifting the fraction to the
right and incrementing the characteristic by 1 until the characteristics are equal.
Each of these operations sets the proper condition code for conditional branching.
Recall that the standard floating point format is as follows:
Leftmost 8 bits Other bits
Sign bit 7–bit characteristic The fraction
Here is an example of adjusting the characteristic.
Characteristic Fraction
41 29000 = 41 29000
40 12000 = 41 01200
41 2A200
Suppose that the fraction overflows. If that happens, the fraction is shifted right by one
hexadecimal digit and the characteristic is incremented by 1. This last operation is called
normalization, in that it returns the result to the expected normal form.
Characteristic Fraction
41 940000
41 760000
41 10A0000 which becomes 42 010A000.
Normalized addition and subtraction perform post–normalization; that is, they normalize the
result after the operation. This is seen in the example above. Precision is maintained by use
of a guard digit, which saves the last digit shifted during normalization prior to addition or
subtraction. This digit may be restored during post–normalization. Here is an example.
Characteristic Fraction
42 0B2584 = 42 0B2584
40 114256 = 42 001142(5) 5 is the guard digit.
42 0B36C6(5)
Normalize the result 41 B36C65.

Page 265 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Here are some examples of the operation, which appear exactly as expected.
* SINGLE PRECISION FLOATING POINT ADDITION
*
ADDSNG LE 2,FL1 LOAD THE REGISTER
AE 2,FL2 ADD SINGLE PRECISION
LE 4,FL3 LOAD ANOTHER REGISTER
AER 4,2 REGISTER 4 IS CHANGED
*
* SINGLE PRECISION FLOATING POINT SUBTRACTION
*
SUBSNG LE 2,FL1 LOAD THE REGISTER
SE 2,FL2 SUBTRACT FROM THE VALUE IN REG 2
LE 4,FL3 LOAD ANOTHER REGISTER
SER 4,2 SUBTRACT REG 2 FROM REG 4,
CHANGING THE VALUE IN REGISTER 4
*
* DOUBLE PRECISION FLOATING POINT ADDITION
*
ADDDBL LD 2,FL1 LOAD THE REGISTER
AD 2,FL2 ADD DOUBLE PRECISION
LD 4,FL3 LOAD ANOTHER REGISTER
ADR 4,2 REGISTER 4 IS CHANGED
*
* DOUBLE PRECISION FLOATING POINT SUBTRACTION
*
SUBBDL LD 2,FL1 LOAD THE REGISTER
SD 2,FL2 SUBTRACT FROM THE VALUE
LD 4,FL3 LOAD ANOTHER REGISTER
SDR 4,2 REGISTER 4 IS CHANGED
*
* A FEW MIXED OPERATIONS
*
MIXED LD 2,FL1 DOUBLE PRECISION LOAD
AE 2,FL2 SINGLE PRECISION ADDITION
SE 2,FL3 SINGLE PRECISION SUBTRACTION
STD 2,FL1 STORE AS DOUBLE PRECISION, THOUGH THE
RESULT IS NOT QUITE THAT PRECISE
*
FL1 DC D ‘123.4’
FL2 DC D ‘10.0’
FL3 DC D ‘150000.0’
Consider the “mixed precision” operations in which both single precision and double
precision floating point numbers are used. The result is certainly less precise than a true
double precision result, though possibly a bit more precise than a single precision one. This
last claim of precision greater than single would be difficult to justify.

Page 266 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Multiplication
There are four distinct floating–point multiplication operations.
Mnemonic Action Opcode Operands
ME Multiply single precision 7C R1,D2(X2,B2)
MD Multiply double precision 6C R1,D2(X2,B2)
MER Multiply single (register) 3C R1,R2
MDR Multiply double (register) 2C R1,R2
In each, the first operand specifies a register that stores the multiplicand and,
after the multiplication, stores the product.
The operation normalizes the product, which in all cases is a double–precision result.

Division
There are four distinct floating–point division operations.
Mnemonic Action Opcode Operands
DE Divide single precision 7D R1,D2(X2,B2)
DD Divide double precision 6D R1,D2(X2,B2)
DER Divide single (register) 3D R1,R2
DDR Divide double (register) 2D R1,R2
In each, the first operand specifies a register that stores the dividend and,
after the division, stores the quotient. There is no remainder.
The operation normalizes the quotient, which in all cases is a double–precision result.
A divisor containing a zero fraction causes a program interrupt. Recall that the two parts of
any number in IBM floating point format are the characteristic and the fraction. The
characteristic is held in the leftmost byte of the format and represents the sign and exponent.
The fraction is held in the rest of the format: for single precision this is the 24 rightmost bits,
and for double precision this is the 56 rightmost bits.

Comparison
There are four distinct floating–point division comparison operations.
Mnemonic Action Opcode Operands
CE Compare single precision 79 R1,D2(X2,B2)
CD Compare double precision 69 R1,D2(X2,B2)
CER Compare single (register) 39 R1,R2
CDR Compare double (register) 29 R1,R2
In each, the comparison sets the condition codes as would be expected for comparisons in the
other formats. Each operation proceeds as a modified subtraction. The characteristic fields
of the two operands are checked, and the smaller exponent is incremented while right shifting
its fraction (denormalizing the number, but preserving its value) before the comparison.
If both operands have fractions that are zero (all bits in the field are 0), the result is
declared to be equal without consideration of either the exponent or the sign.
The single precision operations compare only the leftmost 32 bits in each value.

Page 267 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Floating Point Data

Conversions To and From Floating Point


We now briefly discuss conversion of data between the three main forms that we have
discussed at this time: two’s–complement integer, packed decimal, and floating point. We
begin by considerations related to conversion to and from integer data.
Recall that all floating point formats store data in the form 16EF, where F is a fraction not
less than 1/16 = 0.625 and less than 1.0. Of particular interest here are the values 161 = 16,
and 168 = (24)8 = 232 = 4,294,967,296.
Recall that a 32–bit two’s–complement format can represent integers in a specific range with
the most negative value being –2,147,483,648 and the most positive being 2,147,483,647. In
terms of powers of 2, this range is from –(231) to (231 – 1). We see that 231 = 1681/2.
Consider non–zero integers. The range consistent with the fullword format is as follows.
The smallest magnitude is 1 = 161(1/16); the exponent is 1, stored as 65 = X‘41’.
The largest magnitude is 231 = 1681/2; the exponent is 8, stored as 72 = X‘48’.
Immediately, we see that positive floating point numbers with characteristic fields at least
X‘41’ but not greater than X‘48’ can be converted to integer form. If the characteristic
field is less than X‘41’, the floating–point value will be come an integer 0. If the
characteristic field is greater than X‘48’, the value is too large to be represented.
The primary difficulty with conversions between packed decimal format and floating–point
format is the fact that the position of the decimal point in packed format is not specified.
This difficulty presents itself in different forms, depending on the exact operation.
In translation from packed decimal to floating–point, the position of the decimal point must
be explicitly specified in order to correctly set the exponent.
In translation from floating–point to packed decimal, the computations can be done almost
exactly, but there is no place to store a value representing the position of the decimal point.
We shall explore these conversions again after we have developed a few more tools that can
be used in scanning an array of digits or an array of bytes.

Input and Output of Floating Point Values


At this point in the chapter, the reader should be aware of a glaring omission. There has been
no discussion of conversion from EBCDIC format to any of the floating–point formats or
conversions from those formats back to EBCDIC. In other words, there has been no mention
of methods to write assembly language programs either to read floating point data or to print
those data in some readable format.
The plain fact is that floating–point I/O is not mentioned in any standard source, either the
textbooks [R_02, R_05, R_07, or R_18] or in any of the IBM manuals for the S/370 and
successor systems [R_15, R_16, R_17, R_19, R_20, R_21, R_22, or R_23]. A request to
IBM for any information yielded only a copy of the z/Series Principles of Operation [R_16].
It is likely the case that nobody writes complete floating–point oriented programs in IBM
Assembler Language and has not for quite a few years. If your author finds any additional
information, it will be shared in the next revision of this textbook.

Page 268 Chapter 13 Last revised August 2, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 14: Data Comparison and Branching

The purpose of this chapter is to bring together a number of topics discussed in earlier
chapters, so that we may emphasize a few of the more important points. As the chapter
emphasizes comparison and branching, we begin with a theoretical discussion of sorting.
All comparison is based on the idea of a sort order. There are four possible operators that
can be applied to give a sort order; these are usually denoted as “<”, “>”, “”, and “”. The
two operators “=” and “” are interesting, but will not do for sorting.
As we can choose any of the four operators to support a sort, your author arbitrarily chooses
the “less than” operator and, by implication, its opposite “greater than or equal”.
A<B A is less than B. A precedes B in sort order.
AB A is not less than B. A does not precede B in sort order.
In order to support a sort order, a data type must have the following two properties.
1) Every pair of elements in the data type can be explicitly compared. Let A and B
belong to the data type. Then, it is the case that either A < B or A  B.
2) The transitivity property holds. Let A, B, and C belong to the data type.
If A < B and B < C, it necessarily holds that A < C.
As an aside, it is easy to discover data types that do not suggest an explicit comparison. The
easiest example is that of points in a plane, which are specified by two coordinates. Data
types that always support explicit comparison but do not support the transitivity property can
be devised, but they are more artificial.
The natural tendency would be to define two basic sort orders: numeric and alphabetic.
While this works for data handled manually by humans, it is not really appropriate for data
stored in computers. All data stored in computers, being binary, are ultimately subject to a
numeric comparison. This statement holds for all primitive data types.
The numeric data types (halfword integer, fullword integer, packed decimal, and all floating
point types) all support the expected sort order. Another way to put this is, that subject to
precision and range limitations, the standard rules of algebra apply. The sort order for
character data follows the EBCDIC format, which is ultimately an 8–bit integer format.
The reader should note that the EBCDIC sort order is equivalent to alphabetical order only
when comparing characters all in upper case or all in lower case. There are a few surprises
resulting from the decision to design EBCDIC for easy translation from punch card codes.
The following is a true sort sequence in EBCDIC: “a” < ‘h” < “z” < “A” < “H” < “Z”. The
reason for this is seen in the following table of codes.
Character “A” “H” “Z” “a” “h” “z”
EBCDIC X‘C1’ X‘C8’ X‘E9’ X‘81’ X‘81’ X‘A9’
The following is also a true sort sequence in EBCDIC: “I” < “!” < “J”, as the hexadecimal
codes are X‘C8’, X‘D0’, and X‘D1’. In standard alphabetical order, there is no letter
that stands between “I” and “J”.

Page 269 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

One may imagine a sort order on Boolean data, but it does not help very much. Boolean
variables can have only two values 0 (False) or 1 (True). What we can clearly say is that
0  1, or False True. It is also commonly claimed that False < True, but this seem to your
author to have little practical significance. In any case, we cannot have transitivity with only
two values to consider. The reader should arrive at an independent opinion on this issue.
Branching Strategy
The essence of conditional branching is the two–step process of data–type specific
comparison followed by a branch based on the results. There are a number of design
strategies that can be used to design the appropriate instruction set. IBM seems to have
selected the idea of a standard set of branch conditions (with synonyms) and designing each
comparison instruction to set one of the branch conditions.
The reader should remember that the following instructions also set the branch conditions.
Binary arithmetic: A, S, AH, SH, AR, SR
Boolean N, NC, NI, NR,
O, OC, OI, OR,
X, XC, XI, XR
Packed Format: AP, SP, ZAP
The conditional branch strategy operates based on the condition codes, which are derived
from bits in the PSW (Program Status Word). For the System/370 these are bits 18 and 19 of
the 64 bit PSW. Remember that bits are numbered left to right; the leftmost bit is bit 0.
The two bits stored in the PSW give rise to four standard condition codes. These are:
Condition Code Interpretation
Binary Decimal
00 0 Result is zero or comparison is equal.
For Boolean operators, the result has no bits with value 1.
01 1 Result is negative or the first argument sorts lower than the second.
For Boolean operators, the result has at least one 1 bit.
10 2 Result is positive or the first argument sorts higher than the second.
11 3 Arithmetic overflow has occurred.
As noted previously, it seems a bit odd that the Boolean operator would set the negative bit
when the result contains a 1 bit. Consider the following two binary values, each having 16
bits and possible to interpret as a halfword.
0011 1100 1101 1110 As a 16–bit integer, this is positive.
1111 1100 1101 1110 As a 16–bit integer, this is negative.
One might expect an integer interpretation of the results of the bitwise Boolean operations as
implemented on the System/370. IBM must have had a good reason to implement the
instructions this way; but all we say is “that is the way it was done”.

Page 270 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

Branch Instructions
One of the encodings used to minimize the instruction size is to use the idea of a condition
mask to extend two basic branch instructions into fourteen equivalent branch instructions.
This device is often called “syntactic sugar” or extended mnemonics. There are two basic
branch instructions in the IBM instruction set.
BC MASK,TARGET A TYPE RX INSTRUCTON
BCR MASK,REGISTER A TYPE RR INSTRUCTION
In the Type RX instruction, the target address is computed using the base register and
displacement method, with an optional index register: D2(X2,B2). In the Type RR
instruction, the target address is found as the contents of the register.
Each of these instruction formats uses a four–bit mask, with bit numbers based on the 2–bit
value of the condition code in the PSW, to determine the conditions under which the branch
will be taken. The mask should be considered as having bits numbered left to right as 0 – 3.
Bit 0 is the equal/zero bit. Bit 2 is the high/plus bit.
Bit 1 is the low/minus bit. Bit 3 is the overflow bit.

The Standard Combinations


The following table shows the standard conditional branch instructions and their translation
to the BC (Branch on Condition). The same table applies to BCR (Branch on Condition,
Register), so that there is another complete set of mnemonics for that set.
Bit Mask Flags Condition Extended instructions
0 1 2 3 Sort Arithmetic
0 0 0 0 No branch BC 0,XX NOP
0 0 0 1 Bit 3: Overflow BC 1,XX BO XX
0 0 1 0 Bit 2: High/Plus BC 2,XX BH XX BP
0 1 0 0 Bit 1: Low/Minus BC 4,XX BL XX BM
0 1 1 1 1, 2, 3: Not Equal BC 7,XX BNE XX BNZ
1 0 0 0 Bit 0: Equal/Zero BC 8,XX BE XX BZ
1 0 1 1 0, 2, 3: Not Low BC 11.XX BNL XX BNM
1 1 0 1 0, 1, 3: Not high BC 13,XX BNH XX BNP
1 1 1 1 0, 1, 2, 3: Any BC 15,XX B XX

Note the two sets of extended mnemonics: one for comparisons and an equivalent
set for the results of arithmetic operations.
These equivalent sets are provided to allow the assembler code to read more naturally.

Page 271 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

Here is the complete listing of S/370 assembler mnemonics, showing what is called either
“extended mnemonics” or “syntactic sugar” for each of the BC and BCR instructions.
Branch on Condition (Register) Branch on Condition
Condition Basic Extended Instruction Basic Extended Instruction
Sort Arithmetic Sort Arithmetic
No branch BCR 0,R NOPR BC 0,X NOP
Bit 3: Overflow BCR 1,R BOR R BC 1,X BO X
Bit 2: High/Plus BCR 2,R BHR R BPR R BC 2,X BH X BP X
Bit 1: Low/Minus BCR 4,R BLR R BMR R BC 4,X BL X BM X
1, 2, 3: Not Equal BCR 7,R BNER R BNZR R BC 7,X BNE X BNZ X
Bit 0: Equal/Zero BCR 8,R BER R BZR R BC 8,X BE X BZ X
0, 2, 3: Not Low BCR 11.R BNLR R BNMR R BC 11.X BNL X BNM X
0, 1, 3: Not high BCR 13,R BNHR R BNPR R BC 13,X BNH X BNP X
0,1, 2 No overflow BCR 14,R BNOR R BC 14,X BNO X
0, 1, 2, 3: Any BCR 15,R BR R BC 15,X BX

The BC Instruction
The BC instruction is a type RX instruction with opcode X‘47’.
The source code format for the instruction is BC M,Address or BC M,D2(X2,B2).
The object code format for this instruction is as follows.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) 47 M1 X2 B2 D2 D2D2

The first byte contains the 8–bit instruction code, which is X‘47’.
The second byte contains two 4–bit fields.
The first four bits contain the mask for the branch condition codes
The second four bits contain the number of the index register used in computing
the address of the jump target. If X2 = 0, indexed addressing is not used.
The next two bytes contain the 4–bit number of the base register and the 12–bit displacement
used to form the basic address of the target. This address may be indexed.
Suppose that address TARGET is formed by offset X‘666’ using base register 8.
No index is used and the instruction is BNE TARGET, equivalent to BC 7,TARGET,
as the condition mask for “Not Equal” is the 4–bit number 0111, or decimal 7.
The object code for this is 47 70 86 66.

Page 272 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

The BCR Instruction


The BCR instruction is a two–byte instruction of the form OP M1,R2.
Type Bytes Operands
RR 2 M1,R2 07 M1 R2
The first byte contains the 8–bit instruction code, which is X‘07’.
The second byte contains two 4–bit fields.
The first 4–bit field encodes a branch condition
The second 4–bit field encodes the number of the register containing
the target address for the branch instruction.
For example, the instruction BR R8 is the same as BCR 15,R8. Again, source code written
in this form assumes that the symbol R8 has been defined with an EQU directive.
The object code is 07 F8. The effect of this instruction is to branch unconditionally to the
address in register 8. An instruction such as this is used to implement a subroutine return.
The two code fragments below may be considered to be equivalent. The first fragment is:
LA R8,TARGET Load R8 with the target address
BR R8 Branch to the address in R8.
The second fragment avoids the register as follows:
B TARGET Branch to the target address.

Comparing Binary Data: C, CH, and CR


There are three instructions for binary comparison with the value in a register.
Mnemonic Description Type Format
C Compare full–word RX C R1,D2(X2,B2)
CH Compare half–word RX CH R1,D2(X2,B2)
CR Compare register to register RR CR R1,R2
Each comparison sets the expected condition code.
Condition Condition Code Branch Taken
Operand 1 = Operand 2 0 (Equal/Zero) BE, BZ
Operand 1 < Operand 2 1 (Low/Minus) BL, BM
Operand 1 > Operand 2 2 (High/Plus) BH, BP

Page 273 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

Each of the C and CH instructions is a type RX instruction, with source code shown above.
The object code is of the form that is standard for a type RX instruction.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The opcode for C is X‘59’ and that for
CH is X‘49’. The second byte contains two 4–bit fields, each of which encodes a register
number. The first hexadecimal digit specifies the register containing either the fullword or
the halfword that will be compared. The second hexadecimal digit specifies the optional
register that may be used if indexed addressing is used. If this digit is 0, then the addressing
is simple base/displacement with out any addressing.
The next two bytes contain the 4–bit number of the base register and the 12–bit displacement
used to form the basic address of the target. This address may be indexed.
For the CH (Compare Halfword) instruction, the address computed will reference a halfword.
The value in this halfword will be sign extended to a 32–bit fullword before the comparison.
The CR instruction is a type RR instruction, with opcode X‘19’.
This is a two–byte instruction of the form OP R1,R2.
Type Bytes Operands
RR 2 R1,R2 OP R1 R2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number.
Don’t forget that literal arguments can be used with either C or CH, as in this example.
C R9,=F‘0’ COMPARE THE REGISTER TO ZERO
BH ISPOS IT IS POSITIVE
BL ISNEG NO, IT IS NEGATIVE.
If this line is reached, R9 contains the value 0.
More code here

B DOMORE
ISPOS Code for R9 > 0 is placed here

B DOMORE
ISNEG Code for R9 < 0 is placed here

DOMORE Common code is placed here.

Page 274 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

CP: Compare Packed Decimal Fields


The CP instruction is a type SS instruction with opcode X‘F9’. The source code is of the
form OP D1(L1,B1),D2(L2,B2), which provide a 4–bit number representing the length
for each of the two operands. The object code format is as follows.
Type Bytes Operands 1 2 3 4 5 6
SS(2) 6 D1(L1,B1),D2(L2,B2) X‘F9’ L1 L2 B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code, which is X‘FA’.


The second byte contains a two values, each a 4–bit binary number (one hex digit).
L1 A value that is one less than the length of the first operand.
L2 A value that is one less than the length of the second operand.
Bytes 3 and 4 specify the address of the first operand, using the standard base register and
displacement format. Bytes 5 and 6 specify the address of the second operand, using the
standard base register and displacement format.
Some of the rules for the CP instruction are as follows.
1. The maximum field length for either operand is 16 bytes; thus 31 digits.
2. Both operands must contain valid packed data.
3. If the fields are not the same length, CP extends the shorter field (in the CPU,
but not the copy in memory) by padding it with the proper number of leftmost
zeroes before comparison.
4. The CP instruction follows the rules of standard algebra. Any positive number
will sort greater than any negative number, except that +0 = –0.
5. The implicit number of decimal places in each operand must be the same, or
the comparison results will not reflect the true meaning of the data.

Example
Consider the assembly language statement below, which compares AMOUNT to TOTAL.
CP TOTAL,AMOUNT
Assume: 1. TOTAL is 4 bytes long, so it can hold at most 7 digits.
2. AMOUNT is 3 bytes long, so it can hold at most 5 digits.
3. The label TOTAL is at an address specified by a displacement
of X‘50A’ from the value in register R3, used as a base register.
4. The label AMOUNT is at an address specified by a displacement
of X‘52C’ from the value in register R3, used as a base register.
The object code looks like this: F9 32 35 0A 35 2C

Page 275 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

The Disassembly of the Above Example


Consider F9 32 35 0A 35 2C. The operation code X‘F9’ is that for the
Compare Packed (CP) instruction, which is a type SS(2). The above format applies.
The field 32 is of the form L1 L2.
The first value is X‘3’, or 3 decimal. The first operand is 4 bytes long.
The second value is X‘2’, or 2 decimal. The second operand is 3 bytes long.
The two–byte field 35 0A indicates that register 3 is used as the base register
for the first operand, which is at displacement X‘50A’.
The two–byte field 35 2C indicates that register 3 is used as the base register
for the second operand, which is at displacement X‘52C’.
It is quite common for both operands to use the same base register.

Character Comparison: CLC


The CLC (Compare Logical Character) instruction is one of the two used to compare
character fields, one byte at a time, left to right. The instruction is type SS with opcode
X‘D5’. The source code is of the form CLC D1(L,B1),D2(B2), which provide a length
for only operand 1. The length is specified as an 8–bit byte. The object code format is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) X‘D5’ L B1 D1 D1D1 B2 D2 D2D2

The first byte contains the operation code, which is X‘D5’ for CLC.
The second byte contains a value storing one less than the length of the first operand,
which is the destination for any move. Bytes 3 and 4 specify the address of the first operand,
using the standard base register and displacement format. Bytes 5 and 6 specify the address
of the second operand, using the standard base register and displacement format.
Comparison is based on the binary contents (EBCDIC code) contents of the bytes.
The sort order is from X’00’ through X’FF’.
The instruction may be written as CLC Operand1,Operand2
An example of the instruction is CLC NAME1,NAME2
This instruction sets the condition code that is used by the conditional branch instructions.
The condition code is set as follows:
If Operand1 is equal Operand2 Condition Code = 0
If Operand1 is lower than Operand2 Condition Code = 1
If Operand1 is higher than Operand2 Condition Code = 2
The operation moves, byte by byte, from left to right and terminates as soon as an unequal
comparison is found or one of the operands runs out.

Page 276 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Comparison and Branching

Example of Character Instructions


Consider the example assembly language statement, which compares the string of characters
at label CONAME with those at the location associated with the label TITLE.
CLC TITLE,CONAME
Suppose that: 1. There are fourteen bytes associated with TITLE, say that it was
declared as TITLE DS CL14. Decimal 14 is hexadecimal E.
2. The label TITLE is referenced by displacement X‘40A’
from the value stored in register R3, used as a base register.
3. The label CONAME is referenced by displacement X‘42C’
from the value stored in register R3, used as a base register.
Given that the operation code for CLC is X‘D5’, the instruction assembles as
D5 0D 34 0A 34 2C Length is 14 or X‘0E’; L – 1 is X‘0D’

Final Comments on the Comparison Operators


This chapter has covered a variety of typical comparison operators.
C, CH, and CR for integer comparison,
CP for packed decimal comparison, and
CLC for character comparison.
At this point, it would be helpful to restate the warning that it is the instruction that sets the
data type for the section of memory that is being referenced. If the data are of the wrong type
for the instruction, strange results may be produced.
For example, suppose that the labels DATA1 and DATA2 have been defined somehow and
that they have been initialized with some content.
The instruction C R6,DATA1 will compare the contents of register R6 with the contents of
the four bytes beginning at address DATA1, assuming that those four bytes represent a
32–bit integer in two’s–complement form.
The instruction CH R6,DATA1 will compare the contents of register R6 with the sign
extended contents of the two bytes beginning at address DATA1, assuming that those two
bytes represent a 16–bit integer in two’s–complement form.
The instruction CP DATA1,DATA2 will compare the contents of the two locations,
assuming that each location contains data in valid packed decimal format.
The instruction CLC DATA1,DATA2 will compare the contents of the two locations,
assuming that each location contains EBCDIC character data.
For data that are properly initialized (this is a bit of a trick), it might be possible that each of
the four instructions will execute to completion within the same program. All four might
give results, but only one will give a correct result.

Page 277 Chapter 14 Last Revised July 11, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 15: Looping, Use of Index Registers, and Tables

This lecture discusses loop structures within assembly language, and the language constructs
evolved to support loops. We begin with a review of type RX instructions, which are the
instructions that most naturally can use loop structures. During these lectures, we shall
follow a number of examples taken from a textbook by Mr. George W. Struble of the
University of Oregon. Struble’s textbook, published last in 1975, is out of print.

RX (Register–Indexed Storage) Format


This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The first hexadecimal digit represents the general
purpose register that is the source or destination of the data. The second hexadecimal digit in
the second byte represents the register used for indexed addressing. As always, a value of 0
indicates that indexed addressing is not used.
The third and fourth bytes contain an address in base/displacement format, which may be
further modified by indexing. In order to illustrate this, consider the following data layout.
FW1 DC F‘31’
DC F‘100’ Note that this full word is not labeled
Suppose that FW1 is at an address defined as offset X‘123’ from register 12.
As hexadecimal C is equal to decimal 12, the address would be specified as C1 23.
The next full word might have an address specified as C1 27, but we shall show
another way to do the same thing. The code we shall consider is
L R4,FW1 Load register 4 from
the full word at FW1
A R4,FW1+4 Add the value at the
next full word address
Consider the two line sequence of instructions
L R4,FW1 Operation code is X‘58’.
A R4,FW1+4 Operation code is X‘5A’.
Given that the address of FW1 is specified as C1 23, and that indexing is not used, the
first instruction yields object code as follows: 58 40 C1 23.
The next instruction is similar, except for its operation code, and the address of the operand.
Note that relative addressing is used, so that the operand address is FW1+4, stored at an
offset (X‘123’ + 4) = X‘127’ from the address in base register X‘C’ or decimal 12.
The object code for this instruction is 5A 40 C1 27

Page 278 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

RX Format (Using an Index Register)


Here we shall suppose that we want register 7 to be an index register. As the second
argument is at offset 4 from the first, we set R7 to have value 4.
This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The first hexadecimal digit represents the general
purpose register that is the source or destination of the data. The second hexadecimal digit in
the second byte represents the register used for indexed addressing. As we are assuming now
that indexed addressing is being used, the value of this digit will be nonzero.
The third and fourth bytes contain an address in base/displacement format, which may be
further modified by indexing.
Consider the three line sequence of instructions
L R7,=F‘4’ Register 7 gets the value 4.
L R4,FW1 Operation code is X‘58’.
A R4,FW1(R7) Operation code is X‘5A’.
The object code for the last two instructions is now.
58 40 C1 23 This address is at displacement 123
from the base address, which is in R12.
5A 47 C1 23 R7 contains the value 4.
The address is at displacement 123 + 4
or 127 from the base address, in R12.

Address Modification: Use of Index Registers


As noted above, a type RX instruction has the form OP R1,D2(X2,B2).
This implies that the effective address is the sum of three values:
1. A displacement,
2. An address in a base register, and
3. A value in an index register.
Addresses may be modified by changing the values in any one of these three parts.
The most natural of these choices is to change the value in the index register.
We now consider an example taken from a textbook Assembler Language Programming:
the IBM System/360 and 370 (Second Edition) by George W. Struble. This example
presents a number of ways to achieve the same goal. We shall comment on each of the
approaches, but not claim that any one is better than the other. Before considering the entire
loop, we should first examine a few lines of code as written in Mr. Struble’s style. These can
be quite interesting. Struble uses R3 as the general purpose register, so we shall also.

Page 279 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

The Structure of an Indexed Address


Consider this line of code taken from the loop example.
LOOP C R3,ARG(R10)
The instruction is a Compare Fullword, which is a type RX instruction used to compare the
binary value in a register to that in a fullword at the indicated address. As we shall see, the
intent of this comparison is to set up for a BE instruction. The item of real interest here is the
second operand ARG(R10). How does the assembler map this to the form D2(X2,B2)?
According to Struble (page 168) “The assembler inserts the address of an
implied base register B2 for the second operand. The assembler also
calculates and inserts the appropriate displacement D2 so that D2 and B2
together address ARG. The assembler also includes X2 = 10 [hexadecimal A]
without knowledge or thought of the contents of register 10.”
If register R12 (hexadecimal C) is being used as the implied base register, and if the
label ARG is at displacement X‘234’ from the address in that register, the object
code for the above instruction is 59 3A C2 34.

Incrementing an Indexed Register


Much of this lecture will be focused on methods to change the value in the index register and
so change the value of the effective address of the second argument. This set of slides, which
follows Struble’s example closely, begins with an early example that he modifies to show the
value of the really interesting instructions.
Consider the instruction LA R10,80(R10). What does it do?
This instruction appears to be computing an address, but is it really doing that?
The LA instruction is indeed a “load address” instruction.
Consider the value that is to be loaded into register R10.
One takes the value already in R10, adds 80 to it, and places it back into R10.
In another style, this might be written as R10 = R10 + 80.
This line of code illustrates how programmers use features of the language.

Struble’s First Loop


* PROGRAM TO SEARCH 2O NUMBERS AT ADDRESS ARG, ARG+80,
* ARG+160, ETC. FOR EQUALITY WITH A NUMBER IN REGISTER 3.
LA R10,0 SET VALUE IN R10 TO 0
LOOP C R3,ARG(R10) COMPARE TO A NUMBER
BE OUT IF FOUND, GO PROCESS IT.
LA R10,80(R10) ADD 80 TO VALUE OF INDEX REGISTER.
C R10,=F‘1600’ COMPARE TO 1600.
BNE LOOP IF NOT EQUAL, TRY AGAIN.
DO SOMETHING HERE. THE ARGUMENT IS NOT THERE
OUT DO SOMETHING HERE
This program has only one obvious flaw, but it is a big one. The loop termination code
should be BL LOOP. If the value in R10 goes from 1580 to 1660 and continues
incrementing, the loop with BNE will never terminate properly.

Page 280 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Structure Analysis of Struble’s First Loop


After correcting the obvious logic error in the above loop, it is time to discuss the structure
that is implied by the program fragment. While I extend Struble’s analysis, I remain entirely
consistent with it.
START Initialize the index register.
LOOP Do the comparison and branch to OUT if equal
Update the index register
Test value in index register and loop if necessary.
FALL Write the “fall through” code here. The code
immediately following the loop will execute only
if the value is not found.
B MORE Jump around the code to execute if the value
has been found.
OUT The value has been found. The value in R10
indicates its location in the data structure
labeled as ARG. Execute the common code next.
MORE This code is executed for any option. It
is the continuation of the processing.

Another Example from Struble


Here we have three zero–based arrays, each holding 20 fullword (32–bit) values.
We want an array sum, so that CC[K] = AA[K] + BB[K] for 0  K  19.
Here is one way to do this, again using R10 as an index register.
LA R10,0 INITIALIZE THE INDEX REGISTER
LOOP L R4,AA(R10) GET THE ELEMENT FROM ARRAY AA
A R4,BB(R10) ADD THE ELEMENT FROM ARRAY BB
ST R4,CC(R10) STORE THE ANSWER
LA R10,4(R10) INCREMENT THE INDEX VALUE BY FOUR
C R10,=F‘80’ COMPARE TO 80
BL LOOP
Here we see a very important feature: the index register holds a byte offset for an address
into an array and not an “index” in the sense of a high–level language. Specifically, the
address of the Kth element of array AA is at the byte address given by adding 4K to the
address of element 0 of the array.
Note also the use of LA R10,0 to initialize the register R10 to zero. This is more
common in standard assembly programs than the equivalent L R10,=F‘0’.

Page 281 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

How the VAX–11/780 Would Do This


The standard for the IBM System/360 and related mainframe computers is to use the index
register as holding a byte offset from a base address. In using this feature to move through
an array of particular data types, the standard is to add the size of the data item to the index
register. More complex computers, such as the VAX–11/780 automatically account for
the size of the data. Here is the above code written in the VAX style, while still retaining
most of the structure of a System/370 assembler language program.
LA R10,0 INITIALIZE THE INDEX REGISTER
LOOP L R4,AA(R10) GET THE ELEMENT FROM ARRAY AA
A R4,BB(R10) ADD THE ELEMENT FROM ARRAY BB
ST R4,CC(R10++) STORE THE ANSWER, INCREMENT INDEX
BY 1 FOR USE IN NEXT LOOP.
C R10,=F‘20’ COMPARE TO 20
BL LOOP
In the VAX style of programming, the address AA(R10) would be interpreted as
AA + 4(Value in R10), because AA is an array of four–byte entries. This is a true
use of an index value, as would be expected from our study of algebra. However, it is not the
way that the System/370 assembler handles the addressing.

Other Options for the Loop


We now note a typical structure found in many loops. The loops tend to terminate
with code of the form seen below.
LA REG,INCR(REG) Increment the value
C REG,LIMIT Compare to a limit value
BL LOOP Branch if necessary
The only part of this structure that is not general is the assumption that the loop is
“counting up”. For a loop that counts down, we replace the last by BH LOOP.
A loop termination structure of this sort is so common that the architects of the IBM
System/360 provided a number of special instructions to facilitate it.
The four instructions to be discussed here are as follows.
BXLE Branch on index lower or equal.
BXH Branch on index high.
BCT Branch on count. While this is easier to use, it is
less general than the above.
BCTR Branch on count to address in a register.

Page 282 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

To Loop or Not To Loop


Consider the following code, which sums the contents of a table of a given size.
Here I assume that the table contents are 16–bit halfwords, beginning at address A0
and continuing at addresses A0+2, A0+4, etc. I am using 16–bit halfwords here to
emphasize the fact that the value in the index register must account for the length of the
operands; here each is 2 bytes long.
The first code is the general loop. It is illustrated for an array of 50 two–byte entries.
SR R6,R6 INITIALIZE INDEX REGISTER
SR R7,R7 SET THE SUM TO 0
LOOP AH R7,TAB(R6) ADD ONE ELEMENT VALUE TO THE SUM
A R6,=F‘2’ INCREMENT TO NEXT HALFWORD ADDRESS
C R6,=F‘99’ LAST VALID OFFSET IS 98
BL LOOP
On the other hand, if the table had only three entries, one might write the following code.
LH R7,TAB Load element 0 of the table
AH R7,TAB+2 Add element 1 of the table
AH R7,TAB+4 Add element 2 of the table.
Remember that the function of looping construct is to reduce the complexity of the
source code. If an unrolled loop reads more simply, then it should be used.

Branch on Index Value


The two instructions of interest here are:
BXLE Branch on index lower or equal. Op code = X‘87’.
BXH Branch on index high. Op code = X‘86’.
Each of these instructions is type RS; there are two register operands and a
reference to a memory address. The form is OP R1,R3,D2(B2).
Type Bytes 1 2 3 4
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2

The first byte contains the 8–bit instruction code.


The second byte contains two 4–bit fields, each of which encodes a register number. The
first register is the one that will be incremented and then tested. The second hexadecimal
digit in the second byte encodes a third register, which indicates an even–odd register pair
containing the increment value to be used and the limit value to which the incremented value
is compared.
The third and fourth byte contain a 4–bit register number and 12–bit displacement,
used to specify the memory address for the operand in storage.
Remember that this form of addressing does not use an index register.

Page 283 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

The Even–Odd Register Pair


The form of each of the BXLE and BHX instructions is OP R1,R3,D2(B2).
The source code form of the instructions might be OP R1,R3,S2, in which the
argument S2 denotes the memory location with byte address indicated by D2(B2).
The first register , R1, is the one that will be incremented and then tested. The third register ,
R3, indicates the even register in an even–odd register pair. It is important to note that this
value really should be an even number. While the instruction can work if R3 references an
odd register, it tends to lead to the instruction showing bizarre unintended behavior.
The even register of the pair contains the increment to be applied to the register indicated
by R1. It is important to note that the increment can be a negative number.
The odd register of the pair contains the limit to which the new value in the
register indicated by R1 will be compared.
NOTATION: R3 will denote the even register of the pair, with contents C(R3).
R3+1 will denote the odd register of the even–odd pair,
with contents C(R3+1).

Discussion of BXLE: Branch on Index Less Than or Equal


This could also be called “Branch on Index Not High”.
The instruction is written as BXLE R1,R3,S2.
The object code has the form 87 R1,R3,D2(B2). The processing for this
instruction is as follows.
Step 1 Change the value in R1: R1  C(R1) + C(R3)
Step 2 Test the new value Go to S2 if C(R1)  C(R3 + 1).
Assume that (R4) = 26, (R6) = 62, (R8) = 1, and (R9) = 40.
BXLE 4,8,S2 The even–odd register pair is R8 and R9.
The value in R4 is incremented by the value in R8.
The value in R4 is now 27. This is compared to the value
in R9. 27  40, so the branch is taken.
BXLE 6,8,S2 The even–odd register pair is R8 and R9.
The value in R6 is incremented by the value in R8.
The value in R6 is now 63. This is compared to the value
in R9. 62 > 40, so the branch is not taken.

Page 284 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Discussion of BXH: Branch on Index High


The instruction is written as BXH R1,R3,S2.
The object code has the form 86 R1,R3,D2(B2).
Step 1 Change the value in R1 R1  C(R1) + C(R3)
Step 2 Test the new value Go to S2 if C(R1) > C(R3 + 1).
Assume that (R4) = 4, (R6) = 12, (R8) = –4, and (R9) = 0.
BXH 4,8,S2 The even–odd register pair is R8 and R9.
The value in R4 is incremented by the value in R8.
The value in R4 is now 0. This is compared to the value
in R9. 0  0, so the branch is not taken.
BXH 6,8,S2 The even–odd register pair is R8 and R9.
The value in R6 is incremented by the value in R8.
The value in R6 is now 8. This is compared to the value
in R9. 8 > 0, so the branch is taken.

A New Version of the Array Addition


Again we have three zero–based arrays, each holding 20 fullword (32–bit) values.
We want an array sum, so that CC[K] = AA[K] + BB[K] for 0  K  19.
Here is one way to do this, again using R10 as an index register.
This time, we use BXLE with R8 as the increment register and R9 as the limit register.
LA R10,0 INITIALIZE THE INDEX REGISTER
LA R8,4 INCREMENT BY 4 BYTES FOR FULLWORD
LA R9,76 OFFSET OF 19TH ELEMENT
LOOP L R4,AA(R10) GET THE ELEMENT FROM ARRAY AA
A R4,BB(R10) ADD THE ELEMENT FROM ARRAY BB
ST R4,CC(R10) STORE THE ANSWER
BXLE R10,R8,LOOP INCREMENT R10 BY 4, COMPARE TO 76
When the 19th element is processed R10 will have the value 76 (the proper byte offset).
After the 19th element is processed, R10 will be incremented to have the value 80,
and the branch will not be taken.

Page 285 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Polynomial Evaluation Using Horner’s Rule


Horner’s rule is a standard method for evaluating a polynomial for a given argument.
Let P(X) = ANXN + AN–1XN–1 + …. + A2X2 + A1X + A0.
Let X0 be a specific value of the argument. Evaluate P(X0).
For example, let P(X) = 2X3 + 5X2 – 7X + 10, with X0 = 2.
Then P(2) = 28 + 54 – 72 + 10 = 16 + 20 – 14 + 10 = 32.
Examination of the specific polynomial will show the motivation for Horner’s rule.
P(X) = 2X3 + 5X2 – 7X + 10
=(2X2 + 5X – 7)X + 10
=( [2X + 5]X – 7)X + 10
So P(2) = ( [22 + 5]2 – 7)2 + 10 = ( [4 + 5]2 – 7)2 + 10
= ( [9]2 – 7)2 + 10 = (18 – 7)2 + 10
= (11)2 + 10 = 22 + 10 = 32

A Standard Algorithm for Horner’s Rule


The basic loop is quite simple. In a higher–level language, we would something
like the following, which has no error checking code.
P = A[N]
For J = (N – 1) Down To 0 Do
P = PX + A[J] ;
Consider again the polynomial P(X) = 2X3 + 5X2 – 7X + 10, with X0 = 2.
In a notation appropriate for coding we have the following.
A[3] = 2, A[2] = 5, A[1] = – 7, A[0] = 10, and X0 = 2.
Let’s use the loop above to evaluate the polynomial. N = 3.
Start with P = A[3] = 2.
J=2 P = P2 + A[2] = 22 + 5 =9
J=1 P = P2 + A[1] = 92 – 7 = 11
J=0 P = P2 + A[0] = 112 + 10 = 32.
NOTE: This is entirely different from finding the root of a polynomial.

A Sketch of Our Algorithm for Horner’s Rule


Our version of the assembler does not support explicit loops, so we write the equivalent
code. In this, I shall use register names as “variables”, so R3 will contain a value.
Algorithm Horner
On entry: R3 contains N, the degree of the polynomial
R4 contains X, the value for evaluation.
Set R8 = 0 This will be the answer.
If R3 < 0 Go to END No negative degrees
LOOP R8 = R8R4 + A0[R3]
R3 = R3 – 1
If R3  0 Go to LOOP
END

Page 286 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

This implementation will assume halfword arithmetic; all values are 16–bit integers.
More commonly, one would use floating–point arithmetic. Since my goal here is
to illustrate the loop structure, I stick to the simpler arithmetic of halfwords.

More Notes on Our Implementation


The array will be laid out as a sequence of halfword (two byte) entries in memory.
The base address of the array will be denoted by the label A0.
There are (N + 1) entries, from A0 through AN, found at byte addresses A0, …, A0+2N.
Here is an example for a 5th degree polynomial, with address offsets in decimal.
Address A0 A0+2 A0+4 A0+6 A0+8 A0+10
Entry A0 A1 A2 A3 A4 A5
Each halfword in the array will be referenced as A0(R3), where R3 contains the byte
offset of the item. The value in R3 will be set to 2N and counted back to 0.
The increment value for R3 is –2 (X‘FFFFFFFE’), so that the register is actually
decremented by 2. Its values are the byte offsets: 2N, 2N – 2, …, 4, 2, 0.
As I want to use the BXH instruction for this illustration, and want to allow for R3 = 0,
I shall set the limit for the comparison to –1, though –2 would do as well. At the last
execution of the loop, R3 will be decremented from R3 = 0 to R3 = – 2. The branch will not
be taken.

Horner’s Rule Polynomial Evaluation with BXH


* ALGORITHM HORNER
* ON ENTRY: R3 CONTAINS THE DEGREE OF THE POLYNOMIAL
* R4 CONTAINS THE VALUE OF X FOR P(X)
* PROCESS: R6 AND R7 WILL BE USED FOR THE BXH
* ON EXIT: R9 CONTAINS THE VALUE OF P(X).
SR R9,R9 SET R9 TO ZERO
AR R3,R3 DOUBLE R3 TO MAKE BYTE COUNT.
LH R6,=H‘-2’ LOAD INCREMENT OF -2
LH R7,=H‘-1’ LOAD LIMIT FOR TESTING
LOOP MR R8,R4 PRODUCT IN REGISTER PAIR R8,R9
FOR HALFWORDS, R8 IS NOT USED
AH R9,A0(R3) ADD THE COEFFICIENT
BXH R3,R6,LOOP LOOP IF C(R3) > -1.
For this example, I assume 16–bit integers (halfwords) for both the value of X and
the values of all coefficients of the polynomial.
Given this, the sign bit in R9 will be correct after the multiplication and R8 is not used.

Page 287 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Branch on Count
The two instructions of interest now are:
BCT The branch on count instruction is a type RX instruction, with op code X‘46’.
BCTR The branch on count (register) instruction is a type RR instruction.
This has op code X‘06’. The register holds the branch address.
The forms of the instructions are: BCT R1,S2
BCTR R1,R2.
Each of these instructions decrement the count in the R1 register by 1.
The action of each of these instructions is described formally as follows.
BCT: R1  C(R1) – 1
Branch to S2 if C(R1)  0.
BCTR: R1  C(R1) – 1
Branch to C(R2) if C(R1)  0 and R2  0.
Note that BCTR R1,0 will decrement R1 by 1, but not branch for any value in R1.
Scanning Text for Input/Output
Remember that input should be viewed as a card image of 80 columns and that output
should be viewed as a line–printer line of 132 columns, with leading print control.
Consider a field of N characters found beginning in column M.

Suppose that the leftmost byte in this array is associated with the label BASE.
The leftmost byte in the range of interest will be denoted by the label BASE+M.
Elements in this range will be referenced using an index register as BASE+M(Reg).
For example, suppose that the field of interest contains 12 characters and
begins with column 20. It then goes between columns 20 and 31, inclusive.
Using R3 as an index, we reference this as BASE+20(R3), with 0  (R3) < 20.
Scanning left to right will use BXLE and scanning right to left will use BXH.

Page 288 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Arrays and Tables


We now begin our discussion of arrays and tables with yet another presentation of the
various ways in which addresses can be computed. The two primary modes are indexed
addressing and explicit use of base registers. We shall investigate how these two modes can
be combined. The primary issue being addressed once again is the fact that some address
specifications require detailed inspection in order to understand.
The reason for this endless repetition is your author’s desire to have each chapter contain a
complete description of the topic, without too much direct reference to other chapters.
All classes of instructions, except type RR, can use the explicit base register format of
address specification. These notes focus on four types that are of interest to our discussion of
tables and arrays: type RS, type RX, and the two variants of type SS. Of these, only the type
RX instructions can directly use indexed addressing. The other 3 types use a non–negative
displacement from an address stored in a base register; this can be viewed as being
equivalent to indexed addressing (if one is of a mind to do so).

Type RS Instruction Format


This is a four–byte instruction of the form OP R1,R3,D2(B2).
Type Bytes Operands 1 2 3 4
RS 4 R1,R3,D2(B2) OP R1 R3 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number. Some
RS format instructions use only one register, here R3 is set to 0. This instruction format
follows the IBM architecture standard that “0” is taken as no register, rather than register R0.
The third and fourth byte contain a 4–bit register number and 12–bit displacement, used to
specify the memory address for the operand in storage. Recall that each label in the
assembly language program references an address.
Any address in the format of base register and displacement will appear in the form.
B D1 D2 D3
B is the hexadecimal digit representing the base register.
The three hexadecimal digits D1 D2 D3 form the 12–bit displacement, which is to be
interpreted as a non–negative integer in the range from 0 through 4095, inclusive.
As an example of the type, we consider the BXH instruction with opcode X‘86’.
A standard use of the instruction would be as follows.
BXH R6,R8,L10LOOP
It is important to remember that the above could be written in source code in this form.
LA R4,L10LOOP ADDRESS OF LABEL L10LOOP INTO R4
BXH R6,R8,0(4) BRANCH TARGET ADDRESS IN R4.
One might have an instruction of the following form as well.
BXH R6,R8,12(4) BRANCH TARGET ADDRESS IS DISPLACED
12 (X‘C’) FROM ADDRESS IN R4.

Page 289 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

RX (Register–Indexed Storage) Format


This is a four–byte instruction of the form OP R1,D2(X2,B2).
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) OP R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code.
The second byte contains two 4–bit fields, each of which encodes a register number. The
first hexadecimal digit, denoted R1, identifies the register to be used as either the source or
destination for the data. The second hexadecimal digit, denoted X2, identifies the register to
be used as the index. If the value is 0, indexed addressing is not used.
The third and fourth bytes contain a standard address in base/displacement format.
As an examples of this type, we consider the two following instructions:
L Load Fullword Opcode is X‘58’
A Add Fullword Opcode is X‘5A’
We consider a number of examples based on the following data declarations. Note that the
data are defined in consecutive fullwords in memory, so that fixed offset addressing can be
employed. Each fullword has a length of four bytes.
DAT1 DC F‘1111’
DAT2 DC F‘2222’ AT ADDRESS (DAT1 + 4)
DAT3 DC F‘3333’ AT ADDRESS (DAT2 + 4) OR (DAT1 + 8)
A standard code block might appear as follows.
L R5,DAT1
A R5,DAT2
A R5,DAT3 NOW HAVE THE SUM.
One variant of this code might be the following. See page 92 of R_17.
LA R3,DAT1 GET ADDRESS INTO R3
L R5,0(,3) LOAD DAT1 INTO R5
A R5,4(,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,8(,3) ADD DAT3, AT ADDRESS DAT1+8.
Note the leading comma in the construct (,3), which is of the form (Index, Base). This
indicates that no index register is being used, but that R3 is being used as a base register.
Here is another variant of the above code.
LA R3,DAT1 GET ADDRESS INTO R3
LA R8,4 VALUE 4 INTO REGISTER 8
LA R9,8 VALUE 8 INTO REGISTER 9
L R5,0(,3) LOAD DAT1 INTO R5
A R5,0(8,3) ADD DAT2, AT ADDRESS DAT1+4.
A R5,0(9,3) ADD DAT3, AT ADDRESS DAT1+8.

Page 290 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Explicit Base Addressing for Character Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 271 – 273].
Assume that general–purpose register 4 is being used as the base register, as assigned at
the beginning of the CSECT. Assume also that the following statements hold.
1. General purpose register 4 contains the value X‘8002’.
2. The label PRINT represents an address represented in base/offset form as 401A; that
is it is at offset X‘01A’ from the value stored in the base register, which is R4.
The address then is X‘8002’ + X‘01A’ = X‘801C’.
3. Given that the decimal number 60 is represented in hexadecimal as X‘3C’,
the address PRINT+60 must then be at offset X‘01A’ + X‘3C’ = X‘56’ from
the address in the base register. X‘A’ + X‘C’, in decimal, is 10 + 12 = 16 + 6.
Note that this gives the address of PRINT+60 as X‘8002’ + X‘056’ = X‘8058’,
which is the same as X‘801C’ + X‘03C’. The sum X‘C’ + X‘C’, in decimal, is
represented as 12 + 12 = 24 = 16 + 8.
4. The label ASTERS is associated with an offset of X‘09F’ from the value in the
base register; thus it is located at address X‘80A1’. This label references a storage
of two asterisks. As a decimal value, the offset is 159.
5. That only two characters are to be moved by the MVC instruction examples to be
discussed. Since the length of the move destination is greater than 2, and since the
length of the destination is the default for the number of characters to be moved, this
implies that the number of characters to be moved must be stated explicitly.
The first example to be considered has the simplest appearance. It is as follows:
MVC PRINT+60(2),ASTERS
The operands here are of the form Destination(Length),Source.
The destination is the address PRINT+60. The length (number of characters
to move) is 2. This will be encoded in the length byte as X‘01’, as the length
byte stores one less than the length. The source is the address ASTERS.
As the MVC instruction is encoded with opcode X‘D2’, the object code here is as follows:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 40 56 40 9F
The next few examples are given to remind the reader of other ways to encode
what is essentially the same instruction.

Page 291 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

These examples are based on the true nature of the source code for a MVC instruction, which
is MVC D1(L,B1),D2(B2). In this format, we have the following.
1. The destination address is given by displacement D1 from the address stored in
the base register indicated by B1.
2. The number of characters to move is denoted by L.
3. The source address is given by displacement D2 from the address stored in
the base register indicated by B2.
The second example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT+60 GET ADDRESS PRINT+60 INTO R8
MVC 0(2,8),ASTERS MOVE THE CHARACTERS
Note the structure in the destination part of the source code, which is 0(2,8).

The displacement is 0 from the address X‘8058’, which is stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 00 40 9F
The instruction could have been written as MVC 0(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.
The third example uses an explicit base and displacement representation of the destination
address, with general–purpose register 8 serving as the explicit base register.
LA R8,PRINT GET ADDRESS PRINT INTO R8
MVC 60(2,8),ASTERS SPECIFY A DISPLACEMENT
Note the structure in the destination part of the source code, which is 60(2,8).

The displacement is 60 from the address X‘801C’, stored in R8. The object code is:
Type Bytes Operands 1 2 3 4 5 6
SS(1) 6 D1(L,B1),D2(B2) OP L B1 D1 D1D1 B2 D2 D2D2
D2 01 80 3C 40 9F
The instruction could have been written as MVC 60(2,8),159(4), as the label
ASTERS is found at offset 159 (decimal) from the address in register 4.

Page 292 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Explicit Base Addressing for Packed Decimal Instructions


We now discuss a number of ways in which the operand addresses for character instructions
may be presented in the source code. One should note that each of these source code
representations will give rise to object code that appears almost identical. These examples
are taken from Peter Abel [R_02, pages 273 & 274].
Consider the following source code, taken from Abel. This is based on a conversion of a
weight expressed in kilograms to its equivalent in pounds; assuming 1kg. = 2.2 lb. Physics
students will please ignore the fact that the kilogram measures mass and not weight.
ZAP POUNDS,KGS MOVE KGS TO POUNDS
MP POUNDS,FACTOR MULTIPLY BY THE FACTOR
SRP POUNDS,63,5 ROUND TO ONE DECIMAL PLACE

KGS DC PL3‘12.53’ LENGTH 3 BYTES


FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
The value produced is 12.532.2 = 27.566, which is rounded to 27.57.
The instructions we want to examine in some detail are the MP and ZAP, each of which
is a type SS instruction with source code format OP D1(L1,B1),D2(L2,B2). Each of
the two operands in these instructions has a length specifier.
In the first example of the use of explicit base registers, we assign a base register to
represent the address of each of the arguments. The above code becomes the following:
LA R6,KGS ADDRESS OF LABEL KGS
LA R7,FACTOR ADDRESS
LA R8,POUNDS
ZAP 0(5,8),0(3,6)
MP 0(5,8),0(2,7)
SRP 0(5,8),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 0(5,8),0(3,6) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 0(5,8),0(2,7) Destination is at offset 0 from the address
stored in R8. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R7. The source has length 2 bytes.

Page 293 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

But recall the order in which the labels are declared. The implicit assumption that the labels
are in consecutive memory locations will here be made explicit.
KGS DC PL3‘12.53’ LENGTH 3 BYTES
FACTOR DC PL2‘2.2’ LENGTH 2 BYTES, AT ADDRESSS KGS+3
POUNDS DS PL5 LENGTH 5 BYTES, AT ADDRESS KGS+5
In this version of the code, we use the label KGS as the base address and reference all other
addresses by displacement from that one. Here is the code.
LA R6,KGS ADDRESS OF LABEL KGS
ZAP 5(5,6),0(3,6)
MP 5(5,6),3(2,6)
SRP 5(5,6),63,5
Each of the arguments in the MP and ZAP have the following form:

Recall the definitions of the three labels, seen just above. We analyze the instructions.
ZAP 5(5,6),0(3,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 0 from the address stored
in R6. The source has length 3 bytes.
MP 5(5,6),3(2,6) Destination is at offset 5 from the address
stored in R6. The destination has length 5 bytes.
Source is at offset 3 from the address stored
in R6. The source has length 2 bytes.
In other words, the base/displacement 6000 refers to a displacement of 0 from the address
stored in register 6, which is being used as an explicit base register for this operation. As
the address in R6 is that of KGS, this value represents the address KGS. This is the object
code address generated in response to the source code fragment 0(3,6).
The base/displacement 6003 refers to a displacement of 3 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+3, which is the address FACTOR. This is
the object code address generated in response to the source code fragment 3(2,6).
The base/displacement 6005 refers to a displacement of 5 from the address stored in register
6, which is being used as an explicit base register for this operation. As the address in R6 is
that of KGS, this value represents the address KGS+5, which is the address POUNDS. This is
the object code address generated in response to the source code fragment 5(5,6).
It is worth notice, even at this point, that the use of a single register as the base from which to
reference a block of data declarations is quite suggestive of what is done with a DSECT, also
called a “Dummy Section”.

Page 294 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Tables and Arrays


In an early way of speaking, before the term “data structures” became common, structured
data in a program might be organized in a table. According to [R_02, p 278] data tables
“contain a set of related data arranged so that each item can be referenced according to its
location in the table. … A static table contains defined data, such as income tax steps….
A dynamic table consists of a series of adjacent blank or zero fields defined to store or
accumulate related data.”
We would call these structures “arrays”, with the static table corresponding to an array of
constant values and the dynamic table corresponding to a plain array. The main difference in
the table structure, other than the older terminology, is that the values stored in tables can be
composite values. One might consider these tables as equivalent to an array of records or an
array of structures. In each of tables and arrays, the elements are addressed using an offset
from the base address of the table or array.
Let’s now learn some of the older IBM terminology for tables.

Sample Table
Consider the following table, adapted from the [R_02, page 279].
* 123456789
MONTAB DC C‘01’,‘JANUARY ’
DC C‘02’,‘FEBRUARY ’
...
DC C‘09’,‘SEPTEMBER’
DC C‘10’,‘OCTOBER ’
DC C‘11’,‘NOVEMBER ’
DC C‘12’,‘DECEMBER ’
In the terminology of the book, the first string (representing the month number) is called the
table argument. The month name is called the table function.
The table is to be searched using a value that may match one of the table arguments.
This value is called the search argument.
While one might think of this in terms of a database table, there is no requirement (other than
good coding practice) that the table arguments be unique. There are no keys to this table.
Note that the following table is exactly equivalent.
* 12345678901
MONTAB DC C‘01JANUARY ’
DC C‘02FEBRUARY ’
...
DC C‘09SEPTEMBER’
DC C‘10OCTOBER ’
DC C‘11NOVEMBER ’
DC C‘12DECEMBER ’
Note also that every table entry has exactly the same length (11 characters).
This is required by the table search algorithm.

Page 295 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Searching the Table by “Key Value”


Here is a fragment of code, written in a better style, that searches the above table.
The search argument, MONIN, is defined as two digits.
USING *,4,5
LA 8,MONTAB Address of table in R8
L 9,=H’12’ Number of entries in table
C10LOOP CLC MONIN,0(8) Compare to table argument
BE C30EQUAL Have a match
BL C20NOTEQ Table is ordered; no hit.
AH 8,=H‘11’ Move to next row
BCT 9,C10LOOP Decrement counter, branch if > 0
C20NOTEQ Do something
BR C40DONE
C30EQUAL Do something else.
C40DONE Common code here.
Note that the search argument is being compared to the two characters at the addresses
MONTAB, MONTAB + 11, MONTAB + 22, …, etc. One of the interesting features of this
loop is the address of the second argument in the instruction at address C10LOOP. The
address is specified by 0(8), which is a displacement of 0 from the address in R8.
Note that this is a counted loop. It will search no more than twelve table entries. This is a bit
unusual in that the index used to count the loop is not directly used to address the table; that
is done by explicitly adding 11 to the address in R8 for each loop.
Again, this looping construct is allowed due only to the regular nature of the table;
all entries stored have the same length. In this case, the length is 11 bytes.

Ordered and Unordered Tables


Quite often, a table of the above form will be ordered by the table argument. The most
common order is that the table entries are sorted in increasing order by table entry. Here is
the approach to searching such a table. There are three possibilities for the comparison.
1. The search argument is equal. The table function has been found and
can be used.
2. The search argument is high. Continue the search unless this is the
last entry in the table.
3. The search argument is low. Stop the search and take action appropriate
to the type of table. If it is a table with steps, return with the step number.
For unordered tables, the basic comparisons are restricted to Equal or Not Equal.
As we know, ordered tables can be searched using binary search. This very efficient search
technique is discussed in the textbook.

Page 296 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Arrays, Tables, and Address Computation

Linked Lists
It is possible to use the table structure to implement a linked list. Every entry in the table
contains an additional field specifying the offset in the table of the next item in the list.
Here is a table structured in the form of a linked list that is sorted by increasing part
number. The next offset is found at the end of the list.
Offset Part No. Price Next Offset
0000 0103 12.50 0036
0012 1720 08.95 0024
0024 1827 03.75 0000
0036 0120 13.80 0048
0048 0205 25.00 0012
There are many improvements in this structure that would lead to more flexibility and an
improved set of algorithms to access the list. We may consider some of these later; by
developing an insert and delete method, as well as a more modern create method.

Direct Table Addressing


Consider a table in which the table arguments are sequential and consecutive. One good
example would be the table of months, already discussed. In this type of table, the table
argument is implied by the entry position in the table. This could be written as:
MONTAB DC C‘JANUARY ’
DC C‘FEBRUARY ’
...
DC C‘SEPTEMBER’
DC C‘OCTOBER ’
DC C‘NOVEMBER ’
DC C‘DECEMBER ’
Entry K in the table is at offset (K – 1)9
Let us define the following terms.
A(F) is the address of the required function (table entry).
A(T) is the address of the table.
SA is the numeric value of the search argument
with range 1 through table_length.
L is the length (in bytes) of each function (table entry).
All table entries have the same length.
The equation of interest is
A(F) = A(T) + (SA – 1)L
This is just the access formula for describing a singly dimensioned array in memory. Note
that this formula assumes that the base index has value 1, so that an array declared as A[10]
would have SA as an index value in the range 1 through 10 inclusive.
For an array that has its first index as 0, the equation would be A(F) = A(T) + SAL .

Page 297 Chapter 15 Last revised July 13, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 16: Direct Conversions Between EBCDIC and Fullword Formats

This chapter presents a discussion of direct conversions between digits in the EBCDIC
format and binary integers stored in the 32–bit two’s–complement format. This material is
presented within the context of an academic exercise focused on gaining a more compete
understanding of the basic principles involved. In reality, a program is much more likely to
use the existing tools (PACK, CVB, CVD, and ED) provided by the S/370 assembler.
In other words, the goal of this chapter is not to add to the student’s “bag of assembler tricks”
but to add to the student’s knowledge.

Two’s–Complement Binary Format


Binary integer data are stored on the System/370 in two basic formats.
1. Halfword 16–bit two’s–complement integers
2. Fullword 32–bit two’s–complement integers.
The halfword format is conventionally represented by four hexadecimal digits, which
occupy two bytes of storage. A properly aligned halfword has an address that is a multiple
of 2. The range of values that can be represented is from –32,768 to 32,767 inclusive. The
print representation of a halfword integer contains at most five digits.
The fullword format is conventionally represented by eight hexadecimal digits, which
occupy four bytes of storage. A properly aligned halfword has an address that is a multiple
of 4. The range of values that can be represented is from –2,147,483,648 to 2,147,483,647.
The print representation of a fullword integer contains at most ten digits.
The name “two’s–complement” refers to the manner of storing negative integers. The
student should review the material in chapter 4 of this textbook, especially that on conversion
from decimal to binary format, binary to decimal format, and taking the two’s complement.
Here is a very short presentation on the topic.
The positive decimal number 165 can be represented in hexadecimal as X‘A5’. As an eight
bit binary number, this is 1010 0101. We now consider the representation of the negative
decimal number –165. In order to give the binary representation, we must specify the format.
As a 16–bit number +165 is 0000 0000 1010 0101 or X‘00A5’
take the one’s complement 1111 1111 0101 1010
add one to get the result 1111 1111 0101 1011 or X‘FF5A’
This last number is the binary representation of –165 as a 16–bit integer.
As a 32–bit number +165 is 0000 0000 0000 0000 0000 0000 1010 0101
take the one’s complement 1111 1111 1111 1111 1111 1111 0101 1010
add one to get the result 1111 1111 1111 1111 1111 1111 0101 1011
This last number, also represented as X‘FFFF FF5A’, is the binary representation of
– 165 as a 32–bit binary integer.
Integers are converted from fullword (32 bits or 4 bytes) to halfword (16 bits or 2 bytes)
format by copying the rightmost two bytes, represented by four hexadecimal digits. If the
number is too large in magnitude for the halfword format, it is truncated.

Page 298 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Integers are converted from halfword (16 bit or 2 bytes) to fullword (32 bits or 4 bytes)
format by sign extension. This process insures that the sign of the number is preserved.
+165 in 16 bits is 0000 0000 1010 0101
+165 in 32 bits is 0000 0000 0000 0000 0000 0000 1010 0101
–165 in 16 bits is 1111 1111 0101 1011
–165 in 32 bits is 1111 1111 1111 1111 1111 1111 0101 1011
In each case, it is the leftmost bit in the 16–bit (halfword) representation that is
copied to the leftmost 16 bits added when moving to the 32–bit (fullword) format.
The assumption is that the binary number to be considered will be stored in a
general–purpose register, such as R7. The register might be loaded by an instruction such as
one of the two following.
L R7,FW1 Load R7 from a fullword in memory
LH R7,HW1 Load R7 from a halfword in memory,
and sign extend to a fullword format.
The goal of the input program will be to convert from the EBCDIC digit representation,
which is really just a sequence of character codes, into a binary number in a register.

EBCDIC Representation of Digits


When digits are read in from an input device, they are treated as character data that only
incidentally have numeric value. These must be converted to a numeric format.
The EBCDIC codes of interest in the representation of integer data are the following.
Code Digit Code Digit
X‘F0’ 0 X‘F5’ 5
X‘F1’ 1 X‘F6’ 6
X‘F2’ 2 X‘F7’ 7
X‘F3’ 3 X‘F8’ 8
X‘F4’ 4 X‘F9’ 9
The two other codes of interest are X‘40’ for the space and X‘60’ for the minus sign.

Print Representation of Integers


It goes without saying that the print representation of any integer will involve the use of
EBCDIC characters, especially the ones listed just above. What must be considered is how
to present negative integers. Consider the negative integer 165 to be printed as four digits.
The standard algebraic way to do this is -165.
A less used way is to print it in this form - 165.
A way commonly seen in mainframe programs is as follows 165-.
The last way, though appearing strange, is quite easy to program. For this reason, many
assembler language programs will use the “postfix minus sign” for negative numbers. The
second way involves a bit more code to produce, and the first way considerably more code.
It is this algebraically correct representation that is our goal in this chapter.

Page 299 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

NUMIN: A Program to Input Binary Integers


Numeric data are input into a computer in a three step process.
1. The data are read in as a sequence of characters.
For the IBM System/360, the characters are encoded as EBCDIC.
2. The data are converted to the proper form for numeric use.
3. The data are stored, either in memory or general–purpose registers,
for use in computations.
We shall focus on the input of integer data to be stored in one of the general–purpose
registers. As an arbitrary constraint, we shall limit the numbers to 9 digits, though the
numbers are allowed to be smaller.
Note that any possible nine–digit integer can be stored as a 32–bit fullword. While it is the
case that some ten–digit numbers can be stored as a fullword, this does not hold for all such
numbers; for example:
The ten digit number 2, 100, 000, 000 can be converted to fullword format.
The ten digit number 2, 200, 000, 000 cannot be converted to fullword format.
It is for this reason that our code will focus on numbers with a maximum of nine digits,
represented by ten characters, allowing for an optional sign character.

NUMIN: The Scenario


Remember that input should be viewed as a card image of 80 columns. Consider a field of
N characters found beginning in column M.

Suppose that the leftmost byte in this array is associated with the label CARDIN. The
leftmost byte in the range of interest will be denoted by the label CARDIN+M. Elements in
this range will be referenced using an index register as CARDIN+M(Reg), where the
number in parentheses represents the index register to be used.
Our specific example will assume the following:
1. The character field to hold the integer occupies ten columns on the card,
beginning in column 20 and running through column 29.
2. The number is right justified. If negative, the number has a leading minus sign.
3 An entirely blank field is accepted as representing the number zero.

Page 300 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

NUMIN: The Standard Approach


We begin this set of notes by recalling a more standard approach to conversion from a
sequence of EBCDIC characters to a binary number in a register. This sample code will
assume that all numbers are non–negative.
Here are some data declarations that are used in the code. Note that the data declaration
seems to call for ten digits. Here the assumption will be that the input has at least one
leading space and at most nine numeric digits with no sign.
* THE CHARACTERS FOR INPUT ARE FOUND BEGINNING
* AT CARDIN+20 THROUGH CARDIN+29. NO MINUS SIGN.
DIGITSIN DS CL10 TEN BYTES TO HOLD 10 CHARACTERS
PACKEDIN DS PL6 SIX BYTES HOLD 11 DIGITS
PACKDBL DS D DOUBLE WORD TO HOLD PACKED
Here is the code that uses the above data structures.
MVC DIGITSIN(10),CARDIN+20 GET 10 CHARACTERS
PACK PACKEDIN,DIGITSIN CONVERT TO PACKED
ZAP PACKDBL,PACKEDIN FORMAT FOR CVB
CVB R7,PACKDBL BINARY INTO R7.

NUMIN: The Strategy


The figure below shows the part of the 80–column card image that contains the digits to be
interpreted. We now discuss the strategy to be followed in our direct conversion routine.

The algorithm works as follows:


1. It initializes an output register to 0. Arbitrarily, I choose R7.
2. It scans left to right, looking for a nonblank character.
Assuming that a nonblank character is found in this field, it does the following.
3. If the character is a minus sign, set a flag that the number is negative
and continue the scan.
4. If the number is a digit, process it. If not a digit or “–”, ignore it.
One problem of this code is typical of most sample code. In an attempt to focus on one
point, the code ignores all error processing. Just be aware of the fact.

Page 301 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

NUMIN: EXAMPLE
Consider processing the number represented by the digit string “9413”. We shall illustrate
the process used by our conversion routine.
In this example, let N be the value of the number,
D be the digit read in, and
V be the numeric value of that digit.
Start with N = 0.
Read in D = “9”. Convert to V = 9. N = N10 + V = 010 +9 =9
Read in D = “4”. Convert to V = 4. N = N10 + V = 910 +4 = 94
Read in D = “1”. Convert to V = 1. N = N10 + V = 9410 +1 = 941
Read in D = “3”. Convert to V = 3. N = N10 + V = 94110 + 3 = 9413
The integer value of this string is 9413.

Review of the Instructions: LCR and IC


The code below will use two instructions that should be reviewed at this point. These are
LCR (Load Complement Register) and IC (Insert Character).
Load Complement Register: LCR R1,R2
This loads register R1 with the negative (two’s–complement) of the value in register R2.
This is a convenient way to change the sign of the integer in a register; set the value in the
register equal to the negative of the value now there.
Insert Character: IC R8,CARDIN+20(R3) GET THE DIGIT
This inserts the eight bits of the EBCDIC character into the low order 8 bits (bits 24 – 31) of
the destination register. The other bits are not changed.

There are many interesting uses of this instruction. I elect to use this to set the value in the
register equal to the value of a digit. Thus if the character with EBCDIC representation
X‘F7’ is in storage, I can set the value in the register to 7.

Page 302 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Placing the Numerical Value of a Digit in a Register


The first thing to do is get the EBCDIC code into the register. My solution uses the IC
(Insert Character) instruction.
SR R8,R8 CLEAR R8
IC R8,CARDIN+20(R3) GET THE DIGIT
S R8,=X‘F0’ CONVERT TO VALUE OF DIGIT
In order to be sure that register R8 contains the EBCDIC code for the digit, I first clear the
register to zero and then move the character. This step guarantees that bits 0 –23 of the
register are 0 and that the value in the register, taken as a 32–bit fullword, is the EBCDIC
code for the digit. I then subtract the value of the EBCDIC code for ‘0’ to get the value.
Another way to do this is load the register and use the logical instruction, with mnemonic N,
to mask out all but the last hexadecimal digit. Here is the code.
IC R8,CARDIN+20(R3) GET THE DIGIT
N R8,=X‘F’
I now present my algorithm in fragments of code. We start with the beginning code. Each
fragment will be listed along with its associated data declarations. This first code fragment
just clears the result registers and checks to see if the input field, in the ten columns
beginning at CARDIN+20, is all blanks.
If it is all blanks, the routine interprets the field as containing a 0 and returns.
NUMIN SR R7,R7 SET R7, THE RESULT, TO 0
SR R6,R6 CLEAR HIGH-ORDER PRODUCT
MVI THESIGN,C‘P’ DEFAULT TO POSITIVE
CLC CARDIN+20(10),SPACE10 IS THE INPUT ALL BLANKS
BE DONE IF SO, JUST EXIT WITH
* THE VALUE SET TO 0.
* MORE CODE HERE
* 0123456789 BE SURE OF THE COUNT BELOW
SPACE10 DC CL‘ ’ JUST TEN SPACES
THESIGN DS CL1
The next part scans left to right looking for a non–blank character, which should be there. If
none is found, it just quits. Admittedly, this should not happen, as we have tested and found
at least one non–blank character in the input. This is defensive coding.
* NOW SCAN LEFT TO RIGHT TO FIND FIRST NON-BLANK.
* USE BXLE WITH REGISTER PAIR (R4,R5).
*
SR R3,R3 CLEAR INDEX USED TO SCAN
* THE INPUT CHARACTER ARRAY
LA R4,1 SET INCREMENT TO 1
LA R5,9 OFFSET 9 IS THE LAST DIGIT
SCAN1 CLI CARDIN+20(R3),C‘ ’ DO WE HAVE A SPACE?
BNE NOTBLANK NO, IT MAY BE A DIGIT
BXLE R3,R4,SCAN1 ITS BLANK. LOOK AT NEXT
B DONE ALL BLANKS, WE ARE DONE

Page 303 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

This next section of code checks the first non–blank character. If it is a minus sign, the sets a
flag, which would be a Boolean in a high–level language. Here it is just the character “N”.
If the first non–blank character is a minus sign, then the next character is assumed to be the
first digit. The index value is incremented by 1 to address the character after the “–”.
If the first non–blank character is not a minus sign, it is assumed to be a digit and processed
as one. Note however that the processing loop explicitly makes two tests and processes the
character only if it is not less than “0’ and not greater than “9”.
* AT THIS POINT, R3 IS THE INDEX OF THE NON-BLANK
* CHARACTER. THE VALUES IN (R4,R5) ARE STILL VALID.
* IN PARTICULAR R4 STILL HAS VALUE 1.
*
NOTBLANK CLI CARDIN+20(R3),C‘-’ DO WE HAVE A MINUS SIGN?
BNE ISDIG
MVI THESIGN,C‘N’ NOTE THE SIGN AS NEGATIVE
AR R3,R4 ADD 1 TO VALUE IN R3.
CR R3,R5 R3 HAS BEEN INCREMENTED
BH DONE QUIT IF IT IS TOO BIG.
At this point, we know that CARDIN+20(R3) references a non–blank character that
is in the range of card columns that might contain a digit. Here is the conversion loop. Note
that the first four lines check to see if the character is a digit by performing two tests
equivalent to the compound inequality ‘0’  Code  ‘9’. If the character is not a digit, it is
ignored and a branch to the end of the loop is taken.

ISDIG CLI CARDIN+20(R3),C‘0’ IS IT A DIGIT


BL LOOP NO – CODE < ‘0’
CLI CARDIN+20(R3),C‘9’ AGAIN, IS IT A DIGIT?
BH LOOP NO – CODE > ‘9’
M R6,=F‘10’ MULTIPLY (R6,R7) BY 10
SR R8,R8 CLEAR R8
IC R8,CARDIN+20(R3) GET THE DIGIT
S R8,=X‘F0’ CONVERT TO VALUE OF DIGIT
AR R7,R8 ADD TO THE PRODUCT
LOOP BXLE R3,R4,ISDIG END OF THE LOOP
CLI THESIGN,C‘N’ WAS THE INPUT NEGATIVE
BNE DONE IT IS NOT NEGATIVE
LCR R7,R7 TAKE 2’S COMPLEMENT
DONE * HERE R7 CONTAINS THE BINARY VALUE

Page 304 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Here is the complete code for NUMIN.


NUMIN SR R7,R7 SET R7, THE RESULT, TO 0
SR R6,R6 CLEAR HIGH-ORDER PRODUCT
MVI THESIGN,C‘P’ DEFAULT TO POSITIVE
CLC CARDIN+20(10),SPACE10 IS THE INPUT ALL BLANKS
BE DONE IF SO, JUST EXIT WITH
* THE VALUE SET TO 0.
*
* NOW SCAN LEFT TO RIGHT TO FIND FIRST NON-BLANK.
* USE BXLE WITH REGISTER PAIR (R4,R5).
*
SR R3,R3 CLEAR INDEX USED TO SCAN
* THE INPUT CHARACTER ARRAY
LA R4,1 SET INCREMENT TO 1
LA R5,9 OFFSET 9 IS THE LAST DIGIT
SCAN1 CLI CARDIN+20(R3),C‘ ’ DO WE HAVE A SPACE?
BNE NOTBLANK NO, IT MAY BE A DIGIT
BXLE R3,R4,SCAN1 ITS BLANK. LOOK AT NEXT
B DONE ALL BLANKS, WE ARE DONE
*
* AT THIS POINT, R3 CONTAINS THE INDEX OF THE NON-BLANK
* CHARACTER. THE VALUES IN (R4,R5) ARE STILL VALID.
* IN PARTICULAR R4 STILL HAS VALUE 1.
*
NOTBLANK CLI CARDIN+20(R3),C‘-’ DO WE HAVE A MINUS SIGN?
BNE ISDIG
MVI THESIGN,C‘N’ NOTE THE SIGN AS NEGATIVE
AR R3,R4 ADD 1 TO VALUE IN R3.
CR R3,R5 R3 HAS BEEN INCREMENTED
BH DONE QUIT IF IT IS TOO BIG.
*
ISDIG CLI CARDIN+20(R3),C‘0’ IS IT A DIGIT
BL LOOP NO – CODE < ‘0’
CLI CARDIN+20(R3),C‘9’ AGAIN, IS IT A DIGIT?
BH LOOP NO – CODE > ‘9’
M R6,=F‘10’ MULTIPLY (R6,R7) BY 10
SR R8,R8 CLEAR R8
IC R8,CARDIN+20(R3) GET THE DIGIT
S R8,=X‘F0’ CONVERT TO VALUE OF DIGIT
AR R7,R8 ADD TO THE PRODUCT
LOOP BXLE R3,R4,ISDIG END OF THE LOOP
CLI THESIGN,C‘N’ WAS THE INPUT NEGATIVE
BNE DONE IT IS NOT NEGATIVE
LCR R7,R7 TAKE 2’S COMPLEMENT
*
DONE * HERE R7 CONTAINS THE BINARY VALUE
*
* 0123456789 BE SURE OF THE COUNT BELOW
SPACE10 DC CL‘ ’ JUST TEN SPACES
THESIGN DS CL1

Page 305 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Printing Packed Data


The standard solution to convert binary integer data into printable form uses two
of the standard System/370 assembler language instructions.
CVD Converts the binary to packed decimal.
UNPK Converts the packed decimal to zoned decimal format.
The unpack command, UNPK, has an unfortunate side effect. Consider the decimal number
42, represented in binary in register R4.
CVD R4,PACKOUT produces the value in standard packed decimal format: 042C.
This should be unpacked to the EBCDIC F0 F4 F2
Unpack produces the zoned format F0 F4 C2.
This prints as “04B”, because 0xC2 is the EBCDIC code for the letter ‘B’.
Here is the code that works.
NUMOUT CVD R4,PACKOUT CONVERT THE NUMBER TO PACKED
UNPK THESUM,PACKOUT PRODUCE FORMATTED NUMBER
MVZ THESUM+7(1),=X’F0’ CHANGE THE ZONE FIELD AT
* ADDRESS THESUM+7
BR 8 RETURN ADDRESS IN REGISTER 8
PACKOUT DS PL8 HOLDS THE PACKED OUTPUT
THESUM has eight characters stored as eight bytes. The addresses are:
SUM SUM +1 SUM +2 SUM +3 SUM +4 SUM +5 SUM +6 SUM +7
Hundreds Tens Units
Again, the expression THESUM+7 is an address, not a value.
If THESUM holds C‘01234567’, then THESUM+7 holds C‘7’.
A Problem with the Above Routine
Consider the decimal number –42, stored in a register in binary two’s–complement form.
CVD produces 042D
UNPK produces F0 F4 D2
The above MVZ will convert this to F0 F4 F2, a positive number. There are some easy
fixes that are guaranteed to produce the correct representation for a negative number.
Most of the fixes using CVD and UNPK depend on placing the minus sign to the right of the
digits. So that the negative integer –1234 would be printed as “1234–”.

Page 306 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

My Version of NUMOUT (Number Out)


This routine avoids packed decimal numbers. We are given a binary number (negative or
non–negative) in register R4.
1. Is the number negative?
If so, set the sign to ‘–’ and take the absolute value.
Otherwise, leave the sign as either ‘+’ or ‘ ’ (a blank).
We now have a non–negative number. Assume it is not zero.
2. Divide the number by 10, get a quotient and a remainder.
The remainder will become the character output.
3. The remainder is a positive number in the range [0, 9].
Add =X‘F0’ to produce the EBCDIC code.
4. Place this digit code in the proper output slot.
Is the quotient equal to 0? If so, quit.
If it is not zero, place the quotient in the dividend and return to 2.
Here is a paper example of the proper execution of the algorithm. Consider the positive
integer 9413. Do repeated division by 10 and watch the remainders.
9413 divided by 10: Quotient = 941 Remainder = 3. Generate digit “3”.
941 divided by 10: Quotient = 94 Remainder = 1. Generate digit “1”.
94 divided by 10: Quotient = 9 Remainder = 4. Generate digit “4”.
9 divided by 10: Quotient = 0 Remainder = 9. Generate digit “9”.
Quotient is zero, so the process stops.
As they are generated, the digits are placed right to left, so that the result will print as the
string “9413”. We now investigate the specifications for the code.

NUMOUT: Specifications
The code processes a 32–bit two’s–complement integer, stored as a fullword in register R5
and prints it out as a sequence of EBCDIC characters. The specification calls for printing out
at most 10 digits, each as an EBCDIC character. The sign will be placed in the normal spot,
just before the number. For no particular reason, positive numbers will be prefixed with a
“+”. I just thought I would do something different.
This will use repeated division, using the even–odd register pair (R4, R5), which contains a
64–bit dividend. As a part of our processing we shall insure that the dividend is a 32–bit
positive number. In that case, the “high order” 32 bits of the number are all 0.
For that reason, we initialize the “high order” register, R4, to 0 and initialize the
“low order” register, R5, to the absolute value of the integer to be output.
The EBCDIC characters output will be placed in a 12–byte area associated with
the label CHARSOUT, at byte addresses CHARSOUT through CHARSOUT+11.

Page 307 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Review of the Instructions: LCR and STC


Load Complement Register: LCR R1,R2
This loads register R1 with the negative (two’s–complement) of the value in register R2.
This is also used in my routine NUMIN.
Store Character: STC R8,CHARSOUT(R3) PLACE THE DIGIT
This transfers the EBCDIC character, with code in the low order 8 bits of the source register,
to the target address. None of the bits in the register are changed.
The idea behind NUMOUT is to compute the numerical value of a digit in a source register,
convert it to an EBCDIC code, and move it to the print line. The first part checks the sign of
the integer in register R4 and sets the sign character appropriately.
Note that the first thing to do is clear the output field to that expected for a zero result.
NUMOUT MVC CHARSOUT,ZEROOUT DEFAULT TO 0
MVI THESIGN,C‘+’ DEFAULT TO A PLUS SIGN
C R5,=F‘0’ COMPARE R5 TO 0
BE DONE VALUE IS 0, NOTHING TO DO
BH ISPOS VALUE IS POSITIVE
MVI THESIGN,C‘-’ PLACE A MINUS SIGN
LCR R5,R5 2’S COMPLEMENT R5 TO MAKE POS
ISPOS SR R4,R4 CLEAR REGISTER 4
Here are some data declarations used with this part of the code.
* 123456789012
ZEROOUT DC C‘ 0’ 11 SPACES AND A ZERO
CHARSOUT DS CL12 UP TO 11 DIGITS AND A SIGN

Division (Specifically D – Divide Fullword)


This instruction divides a 64–bit dividend, stored in an even–odd register pair,
by a fullword, and places the quotient and remainder back into the register pair.
This will use the even–odd register pair (R4, R5). The specifics of the
divide instruction are as follows.
R4 R5
Before division Dividend (high order 32 bits) Dividend (low order 32 bits)
After division Remainder Quotient
There are specific methods to handle dividends that might be negative.
As we are considering only positive dividends, we ignore these general methods.

Page 308 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

Our Example of Division


Start with a binary number in register R5.
We assume that register R4 has been cleared to 0, as this example is limited to a 32–bit
positive integer. This code will later be modified to process the remainder, and store
the result as a printable EBCDIC character.
Here is the broad outline of the conversion loop, called DIVIDE because it achieves the
result by repeated division by ten.
DIVIDE D R4,=F‘10’ DIVIDE (R4,R5) BY TEN
*
* THE REMAINDER, IN R4, MUST BE PROCESSED AND STORED
*
SR R4,R4 CLEAR R4 FOR ANOTHER LOOP
C R5,=F‘0’ CHECK THE QUOTIENT
BH DIVIDE CONTINUE IF QUOTIENT > 0

Placing the Digits


At this point, our register and storage usage is as follows:
1. Register R3 will be used as an index register.
2. Register pair (R4, R5) is being used for the division.
3. Register pair (R6, R7) is reserved for use by the BXH instruction.
CHARSOUT DS CL12 contains the twelve characters that form the print representation
of the integer. The number 12 is arbitrary; it could be 10.
The strategy calls for first placing a digit in the units slot (overwriting the ‘0’) and then
moving left to place other digits. To allow for a sign, no digit is to be placed in slot 0, at
address CHARSOUT. The idea will be to place the character into a byte specified by
CHARSOUT(R3).The register is initialized at 11 and decremented by 1 using the BXH
instruction. What the code actually does is increment R3 by the negative value –1.

The Digit Placement Code


Here is a sketch of the digit placement code. It must be integrated into the larger DIVIDE
loop in order to make sense. The register pair (R6, R7) is used for the BXH instruction.
R6 holds the increment value
R7 holds the limit value
L R6,=F‘-1’ SET INCREMENT TO -1
SR R7,R7 CLEAR R7. LIMIT VALUE IS 0.
L R3,=F‘11’ SET INDEX TO 11 FOR LAST DIGIT.
A R4,=X‘F0’ ADD TO GET EBCDIC CODE
STC R4,CHARSOUT(R3) PLACE THE CHARACTER
BXH R3,R6,DIVIDE GO BACK TO TOP OF LOOP
MVC CHARSOUT(R3),THESIGN PLACE THE SIGN

Page 309 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Direct Conversion of Integer Data

The Complete Divide Loop


Here is the complete code for the divide loop. Note the branch out of the loop. The loop
exits either when the quotient is 0 or when ten digits have been placed.
L R6,=F‘-1’ SET INCREMENT TO -1
SR R7,R7 CLEAR R7. LIMIT VALUE IS 0.
L R3,=F‘11’ SET INDEX TO 11 FOR LAST
DIGIT AT CHARSOUT+11.
*
DIVIDE D R4,=F‘10’ DIVIDE (R4,R5) BY TEN AND
A R4,=X‘F0’ ADD X ‘F0’, THE CODE FOR ‘0’
TO GET EBCDIC CODE FOR DIGIT
STC R4,CHARSOUT(R3) PLACE THE CHARACTER
SR R4,R4 CLEAR R4 FOR ANOTHER LOOP
C R5,=F‘0’ CHECK THE QUOTIENT
BNH PUTSIGN EXIT LOOP IF QUOTIENT <= 0
BXH R3,R6,DIVIDE GO BACK TO TOP OF LOOP
*
PUTSIGN MVC CHARSOUT(R3),THESIGN PLACE THE SIGN

Here is the complete code for NUMOUT.


*THE FIRST PART SETS THE DEFAULTS AND PREPARES FOR A 0 OUTPUT
*
NUMOUT MVC CHARSOUT,ZEROOUT DEFAULT TO 0
MVI THESIGN,C‘+’ DEFAULT TO A PLUS SIGN
C R5,=F‘0’ COMPARE R5 TO 0
BE DONE VALUE IS 0, NOTHING TO DO
BH ISPOS VALUE IS POSITIVE
MVI THESIGN,C‘-’ PLACE A MINUS SIGN
LCR R5,R5 2’S COMPLEMENT R5 TO MAKE POS
ISPOS SR R4,R4 CLEAR REGISTER 4
*
L R6,=F‘-1’ SET INCREMENT TO -1
SR R7,R7 CLEAR R7. LIMIT VALUE IS 0.
L R3,=F‘11’ SET INDEX TO 11 FOR LAST
DIGIT AT CHARSOUT+11.
*
DIVIDE D R4,=F‘10’ DIVIDE (R4,R5) BY TEN AND
A R4,=X‘F0’ ADD X ‘F0’, THE CODE FOR ‘0’
TO GET EBCDIC CODE FOR DIGIT
STC R4,CHARSOUT(R3) PLACE THE CHARACTER
SR R4,R4 CLEAR R4 FOR ANOTHER LOOP
C R5,=F‘0’ CHECK THE QUOTIENT
BNH PUTSIGN EXIT LOOP IF QUOTIENT <= 0
BXH R3,R6,DIVIDE GO BACK TO TOP OF LOOP
*
PUTSIGN MVC CHARSOUT(R3),THESIGN PLACE THE SIGN IN THE SPOT
FOR STANDARD ALGEBRA
*
* CODE HERE FOR RETURN FROM SUBROUTINE

Page 310 Chapter 16 Last Revised July 15, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 17: Conversions for Floating–Point Formats

This chapter discusses conversion to and from the IBM floating point format. Specifically,
the chapter covers the following four topics.
1. Conversion of data in 32–bit fullword to a an equivalent value in
single–precision floating–point format.
2. Conversion of data in single–precision floating–point to a an equivalent value in
32–bit fullword format.
3. Conversion of data in the Packed Decimal format to an equivalent value in
double–precision floating–point format. We shall discuss the problem of locating
the decimal point, which is implicit in the Packed Decimal format.
4. Conversion of data in double–precision floating–point to an equivalent value in
Packed Decimal format. This discussion may be a bit general, as the detailed
assembler code is somewhat difficult to design.
The true purpose of this chapter is to focus the reader’s attention on one of the many services
provided by the RTS (Run–Time System) of a modern compiled high–level language. This
is more of the text’s focus on assembler language as a tool to understanding the workings of
a modern computer as opposed to being a language in which the reader is likely to program.
The IBM Mainframe Floating–Point Formats
The first thing to do in this presentation is to give a short review of the IBM Mainframe
format for floating–point numbers. We might note that the modern Series Z machines, such
as the z/10 running z/OS, support three floating–point formats: binary floating–point (the
IEEE standard), decimal floating–point, and hexadecimal floating–point. The older S/370
series supported only what is called “hexadecimal” format. This format is so named because
the exponent is stored as a power of 16. This chapter will use only two of the standard
floating–point formats for the S/370: single–precision (E) and double–precision (D).
Each floating point number in this standard is specified by three fields: the sign bit, the
exponent, and the fraction. The IBM standard allocates the same number of bits for the
exponent of each of its formats. The bit numbers for each of the fields are shown below.
Format Sign bit Bits for exponent Bits for fraction
Single precision 0 1–7 8 – 31
Double precision 0 1–7 8 – 63
In IBM terminology, the field used to store the representation of the exponent is called the
“characteristic field”. This is a 7–bit field, used to store the exponent in excess–64 format;
if the exponent is E, then the value (E + 64) is stored as an unsigned 7–bit number. This field
is prefixed by a sign bit, which is 1 for negative and 0 for non–negative. These two fields
together will be represented by two hexadecimal digits in a one–byte field.
Recalling that the range for integers stored in 7–bit unsigned format is 0  N  127, we have
0  (E + 64)  127, or –64  E  63. The size of the fraction field does depend on the format.
Single precision 24 bits 6 hexadecimal digits,
Double precision 56 bits 14 hexadecimal digits.

Page 311 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

The Sign Bit and Characteristic Field


We now discuss the first two hexadecimal digits in the representation of a floating–point
number in these two IBM formats. In IBM nomenclature, the bits are allocated as follows.
Bit 0 the sign bit
Bits 1 – 7 the seven–bit number storing the characteristic.
Bit Number 0 1 2 3 4 5 6 7
Hex digit 0 1
Use Sign bit Characteristic (Exponent + 64)
Consider the four bits that comprise hexadecimal digit 0. The sign bit in the floating–point
representation is the “8 bit” in that hexadecimal digit. This leads to a simple rule.
If the number is not negative, bit 0 is 0, and hex digit 0 is one of 0, 1, 2, 3, 4, 5, 6, or 7.
If the number is negative, bit 0 is 1, and hex digit 0 is one of 8, 9, A, B, C, D, E, or F.
Some Single Precision Examples
We now examine a number of examples, using the IBM single–precision floating–point
format. The reader will note that the methods for conversion from decimal to hexadecimal
formats are somewhat informal, and should check previous notes for a more formal method.
Note that the first step in each conversion is to represent the magnitude of the number in the
required form X16E, after which we determine the sign and build the first two hex digits.
Example 1: Positive exponent and positive fraction.
The decimal number is 128.50. The format demands a representation in the form X16E,
with 0.625  X < 1.0. As 128  X < 256, the number is converted to the form X162.
Note that 128 = (1/2)162 = (8/16)162 , and 0.5 = (1/512)162 = (8/4096)162.
Hence, the value is 128.50 = (8/16 + 0/256 + 8/4096)162; it is 1620x0.808.
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The fractional part comprises six hexadecimal digits, the first three of which are 808.
The number 128.50 is represented as 4280 8000.
Example 2: Positive exponent and negative fraction.
The decimal number is the negative number –128.50. At this point, we would normally
convert the magnitude of the number to hexadecimal representation. This number has the
same magnitude as the previous example, so we just copy the answer; it is 1620x0.808.
We now build the first two hexadecimal digits, noting that the sign bit is 1.
Field Sign Characteristic
Value 1 1 0 0 0 0 1 0
Hex value C 2
The number 128.50 is represented as C280 8000.
Note that we could have obtained this value just by adding 8 to the first hex digit.

Page 312 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Example 3: Negative exponent and positive fraction.


The decimal number is 0.375. As a fraction, this is 3/8 = 6/16. Put another way, it is
1600.375 = 160(6/16). This is in the required format X16E, with 0.625  X < 1.0.
The exponent value is 0, so the characteristic value is either 64 or 0x40 = 100 0000. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 0 0
Hex value 4 0
The fractional part comprises six hexadecimal digits, the first of which is a 6.
The number 0.375 is represented in single precision as 4060 0000.
The number 0.375 is represented in double precision as 4060 0000 0000 0000.
Example 4: A Full Conversion
The number to be converted is 123.45. As we have hinted, this is a non–terminator.
Convert the integer part.
123 / 16 = 7 with remainder 11 this is hexadecimal digit B.
7 / 16 = 0 with remainder 7 this is hexadecimal digit 7.
Reading bottom to top, the integer part converts as 0x7B.
Convert the fractional part.
0.45  16 = 7.20 Extract the 7,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3,
0.20  16 = 3.20 Extract the 3, and so on.
In the standard format, this number is 1620x0.7B33333333…...
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first
two hexadecimal digits in the eight digit representation are formed as follows.
Field Sign Characteristic
Value 0 1 0 0 0 0 1 0
Hex value 4 2
The number 123.45 is represented in single precision as 427B 3333.
The number 0.375 is represented in double precision as 427B 3333 3333 3333.
Example 5: True 0
The number 0.0, called “true 0” by IBM, is stored as all zeroes [R_15, page 41].
In single precision it would be 0000 0000.
In double precision it would be 0000 0000 0000 0000.
The format of this “true zero” will be important when we consider conversions to and from
the fullword format used for 32–bit integers. In particular, note that the bit field interpreted
as a single–precision true zero will be interpreted as a 32–bit integer zero.

Page 313 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

The structure of the formats facilitates conversion among them. For example, consider the
positive decimal number 80.0, which in hexadecimal is X‘50’. Conversion of this to
floating–point format involves noting that 80 = 64 + 16 = 256(0/2 + 1/4 + 0/8 + 1/16). Thus
the exponent of 16 is 2 and the characteristic field stores X‘42’. The fraction field for this
number is 0101, which is hexadecimal 5. The representation of the number in the two
standard IBM floating–point formats chosen for this chapter’s discussion is as follows.
Single precision (E) format 42 50 00 00
Double precision (D) format 42 50 00 00 00 00 00 00
Conversion from single precision to double precision format is quite easy. Just add 8
hexadecimal zeroes. Conversion from double precision to single precision is either easy or a
bit trickier, depending on whether one truncates or attempts to round.
Convert the double precision value 42 50 00 00 11 10 00 00
Simple truncation will yield 42 50 00 00
A reasonable rounding will yield 42 50 00 01

The Floating–Point Registers


In addition to the sixteen general–purpose registers (used for binary integer arithmetic), the
S/360 architecture provides four registers dedicated for floating–point arithmetic. These
registers are numbered 0, 2, 4, and 6. Each is a 64–bit register. It is possible that the use of
even numbers to denote these registers is to emphasize that they are not 32–bit registers.
The use of the registers by the floating–point operations depends on the precision:
Single precision formats use the leftmost 32 bits of a floating–point register.
Double precision formats use all 64 bits of the register.
To illustrate this idea consider the two data declarations.
EFLOAT DS E Declare a 32–bit single precision
DFLOAT DS D Declare a 64-bit double precision
Consider the following instructions that use floating–point register 0. Remember that this
register holds 64 bits, which is enough for a double–precision (D) floating–point value.
LD 0,DFLOAT Load the full 64-bit register from
the double precision 64-bit value.
LE 0,EFLOAT Load the leftmost 32 bits of the register
from the single precision 32-bit value.
The rightmost 32 bits of the register are
not changed [R_15, page 43].
STD 0,DFLOAT Store the 64 bits from the register into
the 64-bit double precision target.
STE 0,EFLOAT Store the leftmost 32 bits of the register
into the 32-bit single precision target.

Page 314 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Another Look at Two’s–Complement Integers


In order to develop the algorithms for converting between two’s–complement integers and
floating–point formats, we must examine the structure of positive integers from a slightly
different viewpoint, one that is of little view in the “pure integer” world.
We shall focus on conversions for positive fullword integers. As we shall see, handling
negative integers is a simple extension of the above. Handling halfword integers is even
easier, as we shall use the LH (Load Halfword) instruction to load them into a register. All
of our conversions from integer format to floating–point format will assume that the integer
argument is found in a general–purpose register.
The fullword conversion code will begin with an instruction such as
L R9,FW Load the fullword into register 9
The halfword conversion code will begin with an instruction such as
LH R9,HW Load the halfword into register 9,
extending the sign to make a fullword.
The handling of negative numbers is quite simple. We first declare a single–character (one
byte) area called THESIGN, to hold a representation of the sign in a format that will assist
the processing of the resulting floating point number.
For a negative number, THESIGN will be set to X‘80’.
For a non–negative number, its value will be set to X‘00’.
In the code, the location THESIGN would be declared as follows [R_17, page 41].
THESIGN DS X1 One byte of storage
Here is a fragment of the code, assuming that the signed integer value is in R9. Note the use
of the MVI instruction with the hexadecimal equivalent of a character [R_17, page 41].
MVC THESIGN,=X‘00’ Initialize the sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVC THESIGN,=X‘80’ Yes, it is negative.
LCR R9,R9 Get the absolute value
NOTNEG Now process the positive number in R9.
For ease of illustration I shall discuss the structure of a signed 16–bit halfword. As seen
above, we may assume that the halfword represents a positive integer.
Hex digit 0 1 2 3
Power of 16 4 3 2 1 0
Power of 2 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15

In a signed halfword, the bits A0 through A15 would represent the binary bits of the 16–bit
integer. As we have specified that we have a positive integer, we know that A0 = 0 and that
at least one of the other bits is equal to 1.
The value of the halfword is A0215 + A1214 + A2213 + A3212 + … + A1520.

Page 315 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Another way to write this would be as follows:


216(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/216), which can also be written as
164(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/216). This seems to be in a form that is ready for
translation into the IBM floating–point representation. If one of A1, A2, or A3 is nonzero, this
will work. The exponent will be 4 and the fraction A0A1A2A3…A15.
Please note that the IBM Single–Precision Floating–Point format is a 32–bit format, so the
above should not be taken literally. It is just an indicator of where we need to go.
The above method, as extended to 32 bits, might work if it were not for the issue of
normalization. All IBM floating point standards require that the first two bytes (four hex
digits) of the representation be of the following format.
Digit 0 1 2 3
Contents Sign bit and 7–bit characteristic High order bits of the fraction. Next four bits of
field holding the exponent. At least one non-zero bit. the fraction.
In other words, the value of hexadecimal digit 2 cannot be a zero. This is a requirement of
the normalized representation, which calls for representing the floating–point value in the
form 16E  F, where 1/16  F < 1.
In our 16–bit example, suppose that the four high order bits are all zero, but that at least one
of the next four bits is not zero. What we have is of the following form.
Hex digit 0 1 2 3
Power of 16 4 3 2 1 0
Power of 2 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11

The value of the halfword is A0211 + A1210 + A229 + A328 + … + A1120.


Another way to write this would be as follows:
212(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/212), which can also be written as
163(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/212). This seems to be in a form that is ready for
translation into the IBM floating–point representation. If one of A1, A2, or A3 is nonzero, this
will work. The exponent will be 3 and the fraction A0A1A2A3…A11.
Before continuing our discussion, let us reflect on a method to detect whether or not the four
high–order bits in a register are all zero. For this, we need to turn to the logical AND, which
was covered in the last pages of Chapter 12 of this textbook.
The type of instruction I choose to use is the type RX logical AND instruction, N.
LR R8,R9 COPY R9 INTO R8 SO THAT THE FOUR
* HIGH ORDER BITS CAN BE TESTED
* WITHOUT LOSING THE VALUE.
N R8,=X’F0000000’ MASK OUT THE 4 HIGH ORDER BITS
* THE MASK IS F0 00 00 00.
BNZ HAVE1 FOUND A 1 BIT.
Note that the block above is that to be used for 32–bit integers. The logical AND will raise
the zero condition flag only when all bits in R8 become 0 after the operation.

Page 316 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

The Range of Exponents


The first thing to do is predict the largest exponent that can arise from converting a 32–bit
fullword. The magnitude of such an integer cannot exceed 231 = 2,147,483,648, which is the
same as 232  1/2. This value can be represented as 168  1/2, indicating that the largest
exponent for a floating–point number converted from a fullword is 8.
The smallest positive integer is 1 = 161  1/16, indicating that the smallest exponent for a
floating–point number converted from a fullword is 1. Recall that the characteristic field part
of the floating–point representation contains the exponent stored in excess–64 format; the
value stored is (Exponent + 64). The range of possible characteristics is from 72 down to 65.
In our example and in our code, we shall manipulate the characteristic directly.

A Fullword Example
The algorithm to be developed for fullwords will be inspired by the halfword example above.
It will involve multiple shifts and logical operations to locate the most significant 1 bit and
use the information obtained to generate the characteristic field and fraction. But first, let’s
do a computation “by hand”. Our example is 32,685.
As a 16–bit integer, this can be represented as 0111 1111 1010 1101. In 32 bits it
would be 0000 0000 0000 0000 0111 1111 1010 1101. To avoid this mess of
ones and zeroes, this chapter will use hexadecimal notation; the value is 0000 7FAD.
This algorithm functions by testing the leftmost hexadecimal digit in the value, which
represents the four high–order bits in the representation. If the digit is zero, the value is
shifted left by four bits, equivalent to shifting one hexadecimal digit. The SLL (Shift Left
Logical) instruction will be used for this task, as it pads the right with zeroes.
1. Start Characteristic = 72, Value = 0000 7FAD
The most significant digit is 0, so shift left and reduce the characteristic by 1.
2. Characteristic = 71, Value = 0007 FAD0
The most significant digit is 0, so shift left and reduce the characteristic by 1.
3. Characteristic = 70, Value = 007F AD00
The most significant digit is 0, so shift left and reduce the characteristic by 1.
4. Characteristic = 69, Value = 07FA D000
The most significant digit is 0, so shift left and reduce the characteristic by 1.
5. Characteristic = 68, Value = 7FAD 0000
The most significant digit is not 0, so we have both our fraction and our characteristic
with value 68 or X‘44’. The fraction is X ‘7FAD00’.
The representation of this value in the 32–bit single–precision floating–point format is:
44 7F AD 00. Just for fun, let’s reverse engineer this value.
The characteristic field is X‘44’, indicating an exponent of 4. The value represented is
164  (7/16 + 15/162 + 10/163 + 13/164) = 7163 + 15162 + 1016 + 13 =
74096 + 15256 + 160 + 13 = 28,672 + 3,840 + 173 = 32,685.

Page 317 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Why Convert to Single–Precision Floating–Point?


The topic of this section is the conversion of 32–bit fullword integer values into equivalent
floating–point values. One might wonder why we have selected the single–precision format
as the target, in preference to the double–precision floating–point (D) format.
One reason for the choice is simplicity; it is easier to discuss single–precision format in this
context. Another reason is precision. The single–precision floating–point format has a
precision of seven digits. A fullword has at most 10 digits, with the most significant digit
being restricted to 0, 1, or 2; one might stay that the format has only nine digits. In other
words, for most cases, conversion to the single–precision format does not lose accuracy.

Two Unusual Cases


There are two cases in which the above “shift left to find the most significant 1 bit” strategy
does not work. In each of these cases, one finds that one of the bits in the leftmost byte of
the 32–bit integer is not zero. Recall that the format of the single–precision floating–point
format may be expressed as C C | F F F F F F, where the first byte (denoted C C)
holds the sign bit and the characteristic field.
Consider the case illustrated below, in which we assume that not all of A0, A1, A2, and A3 are
zero. Since the number is positive, we do know that A0 = 0, but that is not significant here.
Hex Digit 0 1 2 3 4 5 6 7
Power 16 8 7 6
Power 2 32 31 30 29 28 27 26 25 24
A0 A1 A2 A3 A4 A5 A6 A7 A8 through A31

The value of the fullword is A12 + A22 + A32 + A42 + … + A3120.


30 29 28 27

Another way to write this would be as follows:


232(A1/4 + A2/8 + A3/16 + … + A31/232), which can also be written as
168(A1/4 + A2/8 + A3/16 + … + A31/232). The single–precision floating–point format calls
for an 8–bit field holding the sign and characteristic, followed by a 24–bit fraction, which
here would be A0 through A23. The characteristic field would hold X‘48’, indicating a
positive number with an exponent field of 8.
The conversion for this case is to start with the 32–bit (8 hexadecimal digit) value.
Digit 0 1 2 3 4 5 6 7
A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23 A24-A27 A28-A31
This is logically right shifted by 8 bits (2 hexadecimal digits) to get the value:
Digit 0 1 2 3 4 5 6 7
0000 0000 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23

The two hexadecimal digits for the characteristic field are then inserted to get the final value.
Digit 0 1 2 3 4 5 6 7
4 8 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23

Page 318 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

The Other Case


Consider now the second case. Again we assume that not all of A0, A1, A2, and A3 are zero.
Hex Digit 0 1 2 3 4 5 6 7
Power 16 8 7 6
Power 2 32 31 30 29 28 27 26 25 24
0 0 0 0 A0 A1 A2 A3 A4 through A27

The value of the fullword is A0227 + A1226 + A2225 + A3224 + A4223 + … + A2720.
Another way to write this would be as follows:
228(A0/2 + A1/4 + A2/8 + A3/16 + … + A27/228), which can also be written as
167(A0/2 + A1/4 + A2/8 + A3/16 + … + A27/228). The characteristic field is X‘47’.
Remember that the single–precision format calls for a 24–bit fraction field.
The conversion for this case is to start with the 32–bit (8 hexadecimal digit) value.
Digit 0 1 2 3 4 5 6 7
0000 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23 A24-A27

This is logically right shifted by 8 bits (2 hexadecimal digits) to get the value:
Digit 0 1 2 3 4 5 6 7
0000 0000 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23
The two hexadecimal digits for the characteristic field are then inserted to get the final value.
Digit 0 1 2 3 4 5 6 7
4 7 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23

The “Left Shifter” Cases


In all other cases, the positive integer to be converted has the following format.
Digit 0 1 2 3 4 5 6 7
0000 0000 A0-A3 A4-A7 A8-A11 A12-A15 A16-A19 A20-A23

The two hexadecimal digits that will be occupied by the characteristic field are already clear,
so we do not require any right shifting to move the most significant part of the fraction to its
proper location. We are only assured that at least one of bits A0 through A23 is not zero. The
procedure to follow is the test and shift left procedure sketched above for the halfword case.
The operation to be used in left shifting register R9 will be the SLL (Logical Left Shift),
which will insert 4 binary zeroes on the right part of R9 every time it is left shifted by 4 bits.
This usage is consistent with building a fraction with trailing zeroes; 0.4 = 0.400000.
At the end of the code to be developed, we shall store the integer contents of a the register R9
into a word declared to be in single–precision floating–point format. Note that both the
fullword (F) format and single–precision (E) floating–point formats are 32–bit (four byte)
formats, so that one value can be stored into another.
What we are doing here is manipulating each part of the formatted number as if it were an
integer, and then creating a bit pattern that will bear interpretation as a floating–point value.

Page 319 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Here is the code developed as a result of the discussions so far. The assumption is that the
integer value to be converted is found in general–purpose register R9 and that the result is to
be deposited in an area of memory declared as EFLOAT DS E.
MVI THESIGN,X‘00’ Initialize the sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
LCR R9,R9 Get the absolute value
NOTNEG LR R8,R9 Get a copy into R8
* At this point, R9 will contain the value as it is
* being transformed from 32–bit integer format into
* Single-Precision Floating-Point format.
* R8 is a work register used to test values.
N R8,=X‘F0000000’ Is the high-order hex digit 0
BZ D0IS0 Yes, not this special case
SRL R9,8 Clear out the characteristic
O R9,=X’48000000’ Set the exponent
B SETSIGN Set the sign
D0IS0 LR R8,R9 Get the value back into R8
N R8,=X‘FF000000’ Is the next digit 0
BZ D1IS0 Yes, not this special case
SRL R9,4 Clear out the characteristic
O R9,=X‘47000000’ Set the exponent
B SETSIGN Set the sign
*
* Here we make sure that the two high-order digits in
* R9 are zero, and test that we have a positive value.
*
D1IS0 N R9,=X‘00FFFFFF’ Sanity check: is any bit = 1
BZ SETSIGN NO, the result is 0
LFTSHFT EQU *
* Here we do the left shifting of the number to
* generate the proper characteristic field and
* normalized fraction.
SETSIGN SR R8,R8 Set R8 to zero
IC R8,THESIGN Get the sign byte into R8
CH R8,=H‘0’ Is it zero (non-negative)?
BZ DONE Yes, value is not negative
O R9,=X‘80000000’ Set the sign bit
DONE ST R9,EFLOAT Store the result into the
* 32-bit field EFLOAT

Page 320 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Left Shifting
Having disposed of the two cases that are unusual due to the bit structure of the single–
precision floating–point format, let us consider the “more general” case. In this case, the first
two hexadecimal digits of the integer value are 0 and one (or more) of the other six is non–
zero. From a magnitude consideration, this covers numbers with integer values at least 1 and
less than 224 = 16,777,216. Many commonly used integer values easily fit within this range.
The preconditions for this section of the code are simple. Register R9 contains the absolute
value of the integer, with the sign having been tested and recorded for use later. As noted
above, this magnitude is not greater than 16,777,215, which in hexadecimal is X‘FFFFFF’.
LFTSHFT
ISD3A0 LR R8,R9 Copy value into R8
N R8,=X‘00F00000’ Is the third digit nonzero?
BNZ SETVAL Yes, it is non-zero.
SHL R9,4 No, it is not. Shift left by 4
* bits to examine another digit
B ISD3A0 Try again
SETVAL EQU *
There is quite a bit missing from the above loop. What we need to do is begin with the
characteristic field as X‘46’, or decimal 70, representing an exponent of +6. As each test
reveals digit 3 to be zero, we need to count down the exponent and shift left. The lowest
admissible exponent is 1, represented in the characteristic field as 65 or X‘41’.
The construct appropriate for this is BXH, which will branch on a value higher than X‘41’.
Recall the format of the source code for this instruction.
BXH Register,Register_Pair,Target_Address
Where Register denotes a register containing a count; here the characteristic field.
Register_Pair contains the even register of an even–odd pair.
The even register contains a value to be used in incrementing the count.
The odd register contains a value to be used as a limit.
Target_Address contains the branch target.
The design here is to start the characteristic field at X‘46’, representing an exponent of +6.
For each time the digit is found to be zero, we shift left by 4 bits (one hexadecimal digit), and
decrement the exponent. This continues until the characteristic field is X‘41’, indicating
the smallest characteristic field for a positive non–zero integer.
With R8 and R9 in use, this design calls for the following.
R6 and R7 are selected as the even–odd register pair.
R5 will be used to hold the value of the characteristic field.
Here is an example of the shift strategy. Let R9 contain X‘0000 2BAD’. (R5) = X‘46’.
Is digit 3 a 0? Yes. Shift left and decrement (R5). X‘0002 BAD0’. (R5) = X‘45’.
Is digit 3 a 0? Yes. Shift left and decrement (R5). X‘002B AD00’. (R5) = X‘44’.
Is digit 3 a 0? No, it is not. Keep (R9) = X‘002B AD00’ and (R5) = X‘44’.
The answer is that the floating–point representation is X‘442B AD00’.

Page 321 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Here is the code.


MVI THESIGN,X‘00’ Initialize the sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
LCR R9,R9 Get the absolute value
NOTNEG LR R8,R9 Get a copy into R8
* At this point, R9 will contain the value as it is
* being transformed from 32–bit integer format into
* Single-Precision Floating-Point format.
N R8,=X‘F0000000’ Is the high-order hex digit 0
BZ D0IS0 Yes, not this special case
SRL R9,8 Clear out the characteristic
O R9,=X’48000000’ Set the exponent
B SETSIGN Set the sign
D0IS0 LR R8,R9 Get the value back into R8
N R8,=X‘FF000000’ Is the next digit 0
BZ D1IS0 Yes, not this special case
SRL R9,4 Clear out the characteristic
O R9,=X‘47000000’ Set the exponent
B SETSIGN Set the sign
D1IS0 N R9,=X‘00FFFFFF’ Sanity check: is any bit = 1
BZ SETSIGN NO, the result is 0
LFTSHFT LH R5,=H‘70’ Start value for characteristic
LH R6,=H‘-1’ Increment value.
LH R7,=H‘65’ Limit value
ISD3A0 LR R8,R9 Copy value into R8
N R8,=X‘00F00000’ Is the third digit nonzero?
BNZ SETVAL Yes, it is non-zero.
SHL R9,4 No, it is not. Shift left by 4
BXH R5,R6,ISD3A0 Try again
SETVAL SHL R5,24 Move characteristic into place
OR R9,R5 Create the number
SETSIGN SR R8,R8 Set R8 to zero
IC R8,THESIGN Get the sign byte into R8
CH R8,=H‘0’ Is it zero (non-negative)?
BZ DONE Yes, value is not negative
O R9,=X‘80000000’ Set the sign bit
DONE ST R9,EFLOAT Store the result into the
* 32-bit field EFLOAT

Page 322 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Conversion of Single–Precision Floating–Point to Integer


Here again, the first step is to detect and note the sign of the number. We shall focus on
converting positive values, with the sign added at the end of the conversion process. In this
case the process of “adding the sign” will be that of taking the two’s complement.
The process will begin with the floating–point value stored in location EFLOAT, declared as:
EFLOAT DS E A 32–bit (4 byte) storage allocation.
Note however that, throughout this conversion, EFLOAT will be treated as if it were a 32–bit
fullword integer. Again, we are processing this bit by bit, and hexadecimal digit by hex digit.
We are not really interested in its value when considered as a floating point number.
The first step is to access this four–byte location using an integer instruction.
L R9,EFLOAT
Now, we use a characteristic common to both integer and floating–point arithmetic. If bit 0
(the leftmost bit) of the 32–bit representation is 1, the number is negative. Otherwise, the
number is non–negative, and might be zero. We immediately test for this.
Recall two things when examining the code below.
1. The value X‘00000000’, viewed as a single–precision floating–point value is
what IBM calls a “true zero”. It converts to integer zero.
2. The value X‘7FFFFFFF’ represents a 32–bit number in which all bits, save bit 0
(the sign bit) are 1. We use this to mask out the sign bit and keep in R9 a value
that would be interpreted as the absolute value of the floating–point number.
MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH R9,=H‘0’ and examine the sign bit.
BZ DONE The value is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
The next section of code reflects the fact that, if the fraction part of the representation is zero,
then the value represented is 0 without regard to the characteristic field.
NOTNEG LR R8,R9 Copy the value into R8
N R8,=X‘00FFFFFF’ Examine the fraction. Is it 0?
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ EQU * Keep on processing.
We now check the range of the characteristic field to determine if the exponent is consistent
with conversion to an fullword integer. If the characteristic is less than 65 (X‘41’), the
value is less than 1 and will be converted to a 0. If the characteristic is greater than 72
(X‘48’), the magnitude is too large to be represented as a fullword. What the code should
do in this situation is up to the designer; here we set the integer to the maximum value. This
is probably a poor design choice, but for now it is as good as any. Here is this code.

Page 323 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

LR R8,R9 Copy the value into R8


N R8,=X‘FF000000’ Isolate the characteristic field
SRL R8,24 Shift to least significant byte
CH R8,=H‘64’ Is exponent big enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9 No, set result to zero
B DONE and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ Biggest positive number
B SETVAL Go adjust the sign.
CANDO EQU * Value can be converted.
Here is the code as it exists at this point.
MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH R9,=H‘0’ and examine the sign bit.
BZ DONE The value is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
NOTNEG LR R8,R9 Copy the value into R8
N R8,=X‘00FFFFFF’ Examine the fraction. Is it 0?
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ LR R8,R9 Copy the value into R8
N R8,=X‘FF000000’ Isolate the characteristic field
SRL R8,24 Shift to least significant byte
CH R8,=H‘64’ Is exponent big enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9 No, set result to zero
B DONE and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ This is the biggest positive number
B SETVAL Go adjust the sign.
CANDO EQU * Value can be converted.
* Here is the code for processing the values that
* can be converted into a fullword 32–bit integer.
SETVAL SR R8,R8 Set R8 to 0.
IC R8,THESIGN Load the sign value
CH R8,=H‘0’ Is the sign bit set?
BZ ISPOS No, we are OK
LCR R9,R9 Negate the absolute value
DONE EQU * We are done here.
Now we discuss the code for converting those floating point values that can be converted into
positive fullword values. This code will use SLDL (Shift Left Double Logical).

Page 324 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

We begin with another test to account for a case that cannot be converted. When the
characteristic field is X‘48’ (decimal 72, representing an exponent of 8) and the most
significant bit in the fraction is a 1, the absolute value will be not less than 231, which cannot
be represented as a fullword integer. In other words, we are looking for this value.
Digit 0 1 2 3–7
4 8 1 A1 A2 A3 A4-A23

We use the SLDL instruction on the register pair (8, 9). At first, we shall clear R8 and shift
the two high–order hexadecimal digits of R9 into it (SLDL by 8 bits). If this value is not
X‘48’, we proceed with the conversion. Otherwise one more SLDL will tell the tale.
CANDO SR R8,R8 Set R8 to zero
SLDL R8,8 Shift two high-order digits into R8
CH R8,=H‘72’ Is the exponent an 8?
BL DOIT Yes, we can continue
*
* At this point, the most significant fraction bit occupies
* the sign bit in R9. Check to see if R9 is negative.
*
CH R9,=H‘0’ Is the sign bit set?
BP DOIT No, the high-order fraction bit is 0
L R9,=X‘7FFFFFFF’ Set to the biggest positive integer
B SETVAL Go adjust the sign.
At this point, the register values are as follows:
1. R8 contains the characteristic value, equal to (Exponent + 64).
2. R9 contains the fraction in which the most significant hex digit is not 0.
This is a result of the fact that the number was stored in a normalized format.
3. The low order eight bits (two hexadecimal digits) of R9 are all zero.
This is due to the execution of the logical left shift SLDL.
The final processing of R9 to produce an integer that contains the absolute value of the
desired result is to shift it right by a count related to the exponent. This will shift some
1 bits off the right, thus truncating the value. The requirements are as follows.
Characteristic Exponent Shift right by
72 8 0 bits
71 7 4 bits (1 hexadecimal digit)
70 6 8 bits (2 hexadecimal digits)
69 5 12 bits (3 hexadecimal digits)
68 4 16 bits (4 hexadecimal digits)
67 3 20 bits (5 hexadecimal digits)
66 2 24 bits (6 hexadecimal digits)
65 1 28 bits (7 hexadecimal digits)
The formula for the shift count is seen to be (72 – Characteristic)4.

Page 325 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Here is the code to do that computation and produce the absolute value of the integer.
Recall that the source code format of the logical right shift can be in the following form.
SRL R1,D2(B2) in which the shift amount is determined by adding the value in D2 to the
contents of the register indicated by B2. This is base/displacement form used to compute a
number and not an address.
DOIT SH R8,=H‘72’ Produce (Characteristic – 72)
LCR R8,R8 Produce (72 – Characteristic)
SLL R8,2 Multiply by 4
SRL R9,0(R8) Shift R9 by the amount in R8
Let’s try a few examples to see if this works.
1. A large positive number. In hexadecimal, it is represented as 46 7F 03 00.
Note immediately that the characteristic field is X‘46’, so that the exponent is 6. We first
compute the value directly; it is 166(7/16 + 15/256 + 0/163 + 3/164) =
7165 + 15164 + 3162 =
71048576 + 1565536 + 3256 =
7340032 + 983040 + 768 = 8,323,840.
We now apply our algorithm. At the time that the characteristic is tested, R8 contains
decimal 70 and R9 contains 7F 03 00 00. The algorithm calls for a logical right shift of
R9 by 8 bits or 2 hexadecimal digits. The new value is X‘007F0300’, which represents
the value 0167 + 0166 +7165 + 15164 + 0163 + 3162 + 016 + 0, the value above.
2. A much smaller number related to the above. It is represented as 42 7F 03 00. I
have elected to keep the same fraction to simplify my work in doing the calculations. We
first compute the value directly; it is 162(7/16 + 15/256 + 0/163 + 3/164) =
716 + 15 + 3/256 =
112 + 15 + 0.01171875 = 127.01171875.
We now apply our algorithm. At the time that the characteristic is tested, R8 contains
decimal 66 and R9 contains 7F 03 00 00. The algorithm calls for a logical right shift of
R9 by 24 bits or 6 hexadecimal digits. The new value is X‘0000007F’, which represents
the value 0167 + 0166 +0165 + 0164 + 0163 + 0162 + 716 + 15, which is 127. Note
that this integer conversion has simply dropped the fractional part. Writing code to round off
is not very tricky; your author just elects not to do it.
Here is a sketch of one approach to the round–off question. This will be based on the use of
the shift right logical double instruction SRDL. The value to be converted must be placed in
the even register of an even–odd register pair and the odd register cleared. To illustrate,
suppose that it is R8 that contains the value, represented as 43 7F 03 00.
1. Clear R9. The register pair contains 43 7F 03 00 | 00 00 00 00.
2. Shift right double by 5 digits to get 00 00 04 37 | F0 03 00 00
3. The bit pattern in R8 represents the integer 4256 + 316 + 7 = 1079
The bit pattern in R9 represents a fraction (15/16 + 3/164), bigger than 0.50.
This is noted by detecting the sign bit in R9.
4. Round off the value to 1080.

Page 326 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Packed Decimal Format to Floating–Point


Here we face a problem with no precise solution unless we give some additional input.
Recall that a number in the packed decimal format is represented by a sequence of
hexadecimal digits (all having decimal values in the range 0 through 9) followed by a single
hexadecimal digit in the range X‘A’ through X‘F’. Such a number may have from 1
through 31 decimal digits, with the trailing sign digit being necessary.
The routine for this conversion will be based on selecting individual digits from the packed
format, one at a time. For this purpose, the digits will be numbered left to right in a manner
reminiscent of the bit numbering used in a register. Consider the following.
Digit number 0 1 2 3 4 5 6 7 8 9 A
Value 3 1 4 1 5 9 2 6 5 3 6
The reason that this has no precise solution is that the decimal place is not explicitly specified
in the packed format representation of the value. Since we recognize this value as an
approximate representation of the value , we know the number is 3.1415926536. There are
ten digits to the right of the decimal point and just one before it. In our representation we
shall specify the value as a pair: (packed value, digit position).
The value here would be (31415926536C, 10), indicating that we produce the floating
point value corresponding to the integer value 31415926536 and then divide that by 1010.
At this point, we do not care that the integer just given cannot be represented as either a
halfword or fullword by the S/370; this is just a conceptual calculation. All of our arithmetic
here will be done in double–precision floating–point format.
Design of the Algorithm: Preconditions and Subprograms Used
The algorithm and its implementation in assembly language are designed assuming that:
1. The packed decimal value is found at location PACKNUM, and is validly formatted.
In particular, the number has no more than 31 decimal digits and has a sign digit.
2. The sign digit is either X‘B’ or X‘D’ for a negative number or one of X‘A’, X‘C’,
X‘E’, or X‘F’ for a non–negative number.
3. The digits in the number will be indexed by a value from 0 possibly through 31.
4. One subroutine and one array will be used to help the computation. The subroutine
accepts the digit index in R8 and returns the hexadecimal value of the digit in R9.
The array is an array of double–precision floating–point values in which the
Kth entry, at offset K4, contains the equivalent of float(K).
5. The digits are scanned left to right until a sign digit is found. The numeric digits
are processed very much as was done for the EBCDIC to integer direct conversion,
except that floating–point arithmetic is used.
6. The result will be found in floating–point register 0.
7. As a precaution, the loop will be controlled by a BXLE instruction, to guarantee
that no more than 32 hexadecimal digits are processed.
8. Each addressable byte contains two hexadecimal digits, each of which must be
retrieved individually to compute the value of the Packed Decimal number.

Page 327 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Here is the subprogram used to return the hexadecimal value of a digit. The basic processing
is first to convert the digit offset into a byte offset and then to move the digit into position.
The digit position is converted to a byte offset by division by 2. Consider the example:
PI DC P ‘31415926536’
What is stored is shown in the following table.
Address PI PI+1 PI+2 PI+3 PI+4 PI+5
Value 31 41 59 26 53 6C

The goal of this routine is to get the hexadecimal value of the digit into the low–order four
bits of the general–purpose register 9 and have all other hexadecimal digits equal to 0.
Consider the processing of the digit at offset 2. This is the digit 4.
1. The digit index in R8 is forced to be in the range [0,31].
2. The index is copied into R7 and converted to a byte offset. This offset is 1.
3. The byte with value X‘41’ is loaded into R9.
4. The digit index is tested for being odd. It is not, so there is a logical right
shift to place the first digit into the least significant place. R9 now has X‘4’.
5. The seven high–order hex digits in R9 are masked out, returning the value X‘4’.
Consider the processing of the digit at offset 3. This is the digit 1.
1. The digit index in R8 is forced to be in the range [0,31].
2. The index is copied into R7 and converted to a byte offset. This offset is 1.
3. The byte with value X‘41’ is loaded into R9.
4. The digit index is tested for being odd. It is odd, so there is a logical right so no
right shifting is required. R9 now has X‘41’.
5. The seven high–order hex digits in R9 are masked out, returning the value X‘1’.
Here is the complete subroutine to get the digit. It is called “GETDIGIT”.
* Index of digit is in register R8. Value of R8 is preserved
* The value of the digit is returned in R9.
* R7 is used but not saved. R4 contains the return address.
*
GETDIGIT N R8,=X‘0000001F’ X‘1F’=0001 1111; GET 5 LOW ORDER BITS
LR R7,R8 COPY VALUE OF DIGIT INDEX INTO R7
SRL R7,1 CONVERT INTO BYTE OFFSET
SR R9,R9 SET R9 TO ZERO
IC R9,PACKNUM(R7) GET THE BYTE INTO R7
*
LR R7,R8 GET THE DIGIT INDEX BACK INTO R7
N R7,=X‘00000001’ MASK OUT THE UNIT BIT IN THE INDEX
BNZ ISODD IF UNIT BIT IS NOT 0, INDEX IS ODD
SRL R9,4 SHIFT TO GET DIGIT INTO POSITION
ISODD N R9,=X‘0000000F’ ISOLATE THAT DIGIT
*
* R9 NOW CONTAINS THE NUMERIC VALUE OF THE DIGIT.
* IF VALUE > 9, THE DIGIT IS THE SIGN DIGIT.
BR R4 R4 contains the return address.

Page 328 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

The array in question is just a table holding the double–precision floating–point values
equivalent to the first ten non–negative integers (0 through 9), as well as the value 10.0
(which will be used for multiplication in forming the number). This is just the easiest way to
convert a single digit positive integer into its equivalent floating–point value.
* CONVERT SINGLE DIGIT INTEGER TO FLOATING POINT.
*
* USE: PLACE VALUE INTO INDEX REGISTER, THEN SLL 2
* LD 2,FPVALS(Index Register)
FPVALS DC D‘0.0’
FPV1 DC D‘1.0’
FPV2 DC D‘2.0’
FPV3 DC D‘3.0’
FPV4 DC D‘4.0’
FPV5 DC D‘5.0’
FPV6 DC D‘6.0’
FPV7 DC D‘7.0’
FPV8 DC D‘8.0’
FPV9 DC D‘9.0’
FPV10 DC D‘10.0’
Here is the code for the conversion routine.
PACKTOFP LD 0,FPVALS GET THE 0 ENTRY. CLEAR FP REG 0
* NOW SET UP FOR THE BXLE INSTRUCTION
*
SR R8,R8 SET COUNT TO 0. THIS IS THE DIGIT INDEX
LH R10,=H‘1’ LOOP INCREMENT IS 1, MOVE LEFT TO RIGHT
LH R11,=H’31’ LIMIT ON THE DIGIT INDEX
CONVERT BAL R4,GETDIGIT GET THE DIGIT AT INDEX = R8
CH R9,=H‘10’ DIGIT VALUE RETURNED IN R9
BNL DONE WE HAVE THE SIGN DIGIT
MD 0,FPV10 MULTIPLY CURRENT VALUE BY 10.0
SLL R9,2 MULTIPLY DIGIT VALUE BY 4
LD 2,FPVALS(R9) GET FP VALUE OF THE DIGIT
ADR 0,2 ADD TO ACCUMULATING RESULT
BXLE R8,R10,CONVERT GO GET ANOTHER DIGIT
DONE LH R8,DECPLACE GET THE DECIMAL PLACE INDICATOR
CH R8,=H‘0’ IS IT POSITIVE
BNH SETSIGN NO, JUST SET THE SIGN
ADJUST DD 0,FPV10 DIVIDE TO ADJUST TO DECIMAL POINT
BCT R8,ADJUST KEEP DIVIDING UNTIL VALUE IS RIGHT
SETSIGN CH R9,=H‘11’ R9 HAS SIGN DIGIT. IS IT X‘B’?
BE ISNEG YES, THE VALUE IS NEGATIVE
CH R9,=H‘13’ R9 HAS SIGN DIGIT. IS IT X‘D’?
BNE FINISH NO. THE VALUE IS POSITIVE
ISNEG LDR 2,0 COPY VALUE TO FP REGISTER 2
SDR 0,0 SET FP REGISTER TO 0
SDR 0,2 NOW FP 0 HAS BEEN NEGATED
FINISH BR R3 ALL DONE.

Page 329 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Floating–Point to Packed Decimal Conversion


When considering this conversion, one is presented with a number of technical difficulties in
handling the floating–point as well as issues due to the fundamental incompatibility of the
two formats under consideration. All are difficult, but none are insurmountable.
Here are some of the issues that must be addressed.
1. How to produce repeatedly the most significant decimal digit from a floating–point
representation, and when to stop producing these digits. The floating–point formats”
call for single–precision to have 7 digits significant, and double–precision to have
15 digits significant. Do we stop at these counts?
Consider the number 1.2345107, which of course will be represented in the IBM
formats using hexadecimal notation. We want to extract the exponent as 7, and then
extract the digits 1, 2, 3, 4, and 5 in that order. The answer might be 012345000C.
2. As a related issue, how at any time to determine the largest power of ten that is not
larger than the absolute value of the floating–point number being converted. The
simple way to do this appears to be quite verbose and tedious.
3. The position of the decimal point in any floating–point representation is important
and almost explicitly specified in the representation. The position of the decimal
point for the Packed Decimal format is assumed in the code and not stored in the
format. We got around this for the Packed Decimal to Floating–Point conversion by
by specifying the position of the decimal, but this not a part of the standard.
One obvious way to convert from floating–point to packed decimal is first to convert the
value to a fullword integer and then to convert that value (using CVD) to Packed Format.
This will work for floating–point values that represent integers within the proper range, but
any fractional digits will be lost.
This issue of converting from Floating–Point to Packed Decimal is closely related to the
problem of providing a print representation for floating–point values. As the author of your
textbook, I intend to continue investigating these two conversion issues.
Any solutions found that are suitable for publishing in a textbook will appear in the
next revision.

Page 330 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Conversions for Floating Point

Here is the complete code for the floating–point to integer conversion.


MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH R9,=H‘0’ and examine the sign bit.
BZ DONE The value is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
NOTNEG LR R8,R9 Copy the value into R8
N R8,=X‘00FFFFFF’ Examine the fraction. Is it 0?
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ LR R8,R9 Copy the value into R8
N R8,=X‘FF000000’ Isolate the characteristic field
SRL R8,24 Shift to least significant byte
CH R8,=H‘64’ Is exponent big enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9 No, set result to zero
B DONE and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ This is the biggest positive number
B SETVAL Go adjust the sign.
CANDO SR R8,R8 Set R8 to zero
SLDL R8,8 Shift two high-order digits into R8
CH R8,=H‘72’ Is the exponent an 8?
BL DOIT Yes, we can continue
CH R9,=H‘0’ Is the sign bit set?
BP DOIT No, the high-order fraction bit is 0
L R9,=X‘7FFFFFFF’ Set to the biggest positive integer
B SETVAL Go adjust the sign.
DOIT SH R8,=H‘72’ Produce (Characteristic – 72)
LCR R8,R8 Produce (72 – Characteristic)
SLL R8,2 Multiply by 4
SRL R9,0(R8) Shift R9 by the amount in R8
SETVAL SR R8,R8 Set R8 to 0.
IC R8,THESIGN Load the sign value
CH R8,=H‘0’ Is the sign bit set?
BZ ISPOS No, we are OK
LCR R9,R9 Negate the absolute value
DONE EQU * We are done here.

Page 331 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 18: Writing Macros

This lecture will focus on writing macros, and use stack handling as an example of macro
use. Macros differ from standard subroutines and functions. Functions and subroutines
represent separate blocks of code to which control can be transferred. Linkage is achieved
by management of a return address, which is managed in various ways.
A macro represents code that is automatically generated by the assembler and inserted into
the source code. Macros are less efficient in terms of code space; each invocation of the
macro will generate a copy of the code. Macros are more efficient in terms of run time;
they lack the overhead associated with subroutine call and return. There is an important
definition that is key to understanding what a macro is and what it does.
Definition: A macro definition is a pattern for a character–by–character textual
substitution without interpretation, and a macro invocation causes the
assembler to effect that substitution exactly as written.

Dynamic Memory: Stacks and Heaps


Before discussing macros, let’s discuss an application. The first thing to note in our
discussion of dynamic memory, especially stacks and heaps, is that these features are not
supported by our version of the System/370 assembler.
A stack is a LIFO (Last–In / First–Out) data structure with three basic operations:
PUSH places an item onto the stack,
POP removes an item from the stack
INIT initializes the stack.
A heap is a dynamic structure used by a RTS (Run–Time System) to allocate memory in
response to object creators, such as New. A modern RTS will allocate an area of memory for
use by both the stack and the heap. By convention in system design:
1. The stack starts at high memory addresses and moves toward lower addresses.
2. The heap starts at low memory addresses and moves toward higher addresses.

Division of the Dynamic Memory Space


This shows how the available space is divided between the stack and the heap.
There is no fixed allocation to either, just a limit on the total space used.

A stack is often managed using a stack pointer, SP, that locates its top.

Page 332 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Our Stack Implementation


The first caution in our implementation regards the selection of names for our macros.
IBM has macros called “PUSH” and “POP”, associated with handling print output. We must
pick other names for our stack macros. Our goal in this lecture is to examine the basic stack
structure, and its implementation using macros.
Our implementation will use a fixed–size array to hold the stack. The design will be atypical
in that the stack will grow towards higher addresses. The stack pointer will point to the
location into which the next item will be pushed. The two basic stack operations, as we
implement them, are illustrated in the figures below.
PUSH
STACK[SP] = ITEM
SP = SP + 1 // Moves toward higher addresses

POP
SP = SP – 1
ITEM = STACK[SP]
This non–standard approach is easier for me to code.

A Stack Example
Here we push four integers, one after the other. We then pop the values.
Push onto the stack

Pop from the stack: note the order is reversed.

Page 333 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Our Stack Implementation: Macro or Subroutine?


We have a choice of implementation method to use for our stack handler.
I have chosen to use an approach using macros for two reasons.
1. I wanted to discuss macros.
2. I wanted to use a stack to illustrate the subroutine call mechanism.
That makes it difficult to use a subroutine for the stack.
We shall write three macros for the stack.
STKINIT This is a macro without parameters.
It will initialize the stack count and also the stack pointer.
STKPUSH This is a macro with a single parameter.
It pushes the 32–bit contents of a register onto the stack.
STKPOP This is a macro with a single parameter.
It pops the contents of the stack top into a 32–bit register.
AGAIN: These names are chosen to avoid name conflicts with existing macros.

Mechanics of Writing Macros


The MACRO definitions should occur very early in the source code of the assembler
program. Only comments and assembler control directives may precede a MACRO
definition. This commonly includes the PRINT directive.
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 an example.
Header MACRO
Prototype DIVID &QUOT,&DIVIDEND,&DIVISOR
Model Statements ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
Trailer MEND
Note that the header and trailer must appear exactly as shown above. Each of the terms
“MACRO” and “MEND” begin in column 10. Nothing else is allowed on either line.
The basic idea of a macro is to replace multiple copies of repeated code with a single macro
invocation. Here, the savings are minimal, as we are replacing two lines of code with one
line of code. Again, the reader is cautioned the some teaching examples are quite small.
With the above macro definition, based on packed decimal arithmetic, the idea is to replace
the following two lines of code with the line that follows them.
Replace ZAP X,Y
DP X,Z
With DIVID X,Y,Z

Page 334 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Example of Macro Expansion


In assembly language, a macro is a single statement that causes the assembler to emit a
sequence of other statements specified by the macro definition. Consider the above example,
with prototype
DIVID &QUOT,&DIVIDEND,&DIVISOR.
The macro body is
ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
Here is an example of the macro expansion. We assume that the labels used as “parameters”
have been properly defined by DS or DC statements.
DIVID MPG,MILES,GALS MACRO INSTRUCTION
+ ZAP MPG,MILES ITS EXPANSION
+ DP MPG,GALS

What Do We Mean by “Expansion”?


Consider the following code fragment, written to include a call to a macro.
PACK MILES,CARDIN+10(4) COLUMNS 10 - 13
PACK GALS,CARDIN+14(3) COLUMNS 14 – 16
DIVID MPG,MILES,GALS INVOKE THE MACRO
MVC MPGPR,=X‘40202020’ MOVE THE EDIT MASK
ED MPGPR,MPG EDIT FOR PRINTING
Here is the code that is actually generated. I have inserted line numbers.
Note that the macro invocation itself is not an executable instruction.
51 PACK MILES,CARDIN+10(4) COLUMNS 10 - 13
52 PACK GALS,CARDIN+14(3) COLUMNS 14 – 16
54 ZAP MPG,MILES ITS EXPANSION INTO
55 DP MPG,GALS TWO LINES OF CODE
56 MVC MPGPR,=X‘40202020’ MOVE THE EDIT MASK
57 ED MPGPR,MPG EDIT FOR PRINTING

Symbolic Parameters
The macro prototype contains a list of symbolic parameters. Each symbolic parameter is
written as follows:
1. The name begins with an ampersand (&).
2. The ampersand is followed by one to seven alphanumeric characters, the first of
which must be a letter. The total length must be between 2 and 8 characters: first
an “&”, then a letter, then zero to six alphanumeric characters.
3. Symbolic parameters have a local scope; that is, the name and value they are
assigned only applies to the macro definition in which they have been declared.
[Page 251, R_17]

Page 335 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Keyword Macros
A standard invocation of the above macro might appear as follows:
DIVID MPG,MILES,GALS
In the above macro invocation, the arguments are passed by position. A macro invoked this
way is called a positional macro. Another use, called a keyword macro, allows arguments
to be passed in any order because each argument is tagged with an explicit symbolic
parameter. Keyword macros also allow default values for each or all of the parameters.
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:
Header MACRO
Prototype DIVID2 &QUOT=,&DIVIDEND=,&DIVISOR=
Model Statements ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
Trailer MEND
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,&DIVIDEND
DP &QUOT,&DIVISOR
MEND
With this definition, the two invocations are exactly equivalent.
DIVID MPG,MILES,GALS
DIVID2 &DIVIDEND=MILES,&DIVISOR=GALS
The invocation of the macro DIVID2 will expand as follows:
ZAP MPG,MILES
DP MPG,GALS
It is interesting to note that a keyword macro cannot be invokes as if it were a positional
macro. The student should consult the following listing to see what happens.
From the listing of the macro invocations, we can infer that the statement
DIVID2 MPG,MILES,GALS
is treated as if there were no arguments present.

Page 336 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

One may specify default constants in the keyword macro, being careful to observe the correct
syntax. For example, one might be tempted to specify &DIVISOR=10, but the number by
itself will name a register. The only way to do this would be set &DIVISOR to =P‘10’,
by using the construct required to pass literals to a keyword macro.
MACRO
DIVID3 &QUOT=MPG,&DIVIDEND=,&DIVISOR==P‘10’
ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
MEND
The above usage is explained simply “If the value of a keyword operand is a literal, two
equal signs must be specified.” [R_17, page 300]. A more complete explanation of the
above can be seen by considering the macro DIVID2. The student will note the shortening
of the keywords in what follows, in an attempt to fit the listings on the page.
Here is the prototype DIVID2 &QUOT=MPG,&DVD=,&DVS=
Here is a correct invocation DIVID2 QUOT=ARG1,DVD=ARG2,DVS==P'20'
The key here is to remove the text fragments “QUOT=”, “DVD=”, and “DVS=”, and see what
remains. Let’s do that. Consider QUOT=ARG1,DVD=ARG2,DVS==P'20'
What remains is “ARG1”, “ARG2”, and “=P'20'”, each of which is a correct argument.
The third argument is a literal value for the packed decimal with value 20. Had we invoked
the macro with the third argument as DVS=P'20', the third argument would have been just
“P'20'”, which is meaningless to the assembler.

Sample Expansion Listings for Macros


Here is some assembly output from a program that I wrote to test these ideas.
31 *
32 * MACRO DEFINITIONS
33 *
34 MACRO
35 DIVID &QUOT,&DVD,&DVS
36 ZAP &QUOT,&DVD
37 DP &QUOT,&DVS
38 MEND
39 *
40 MACRO
41 DIVID2 &QUOT=,&DVD=,&DVS=
42 ZAP &QUOT,&DVD
43 DP &QUOT,&DVS
44 MEND
45 *
46 MACRO
47 DIVID3 &QUOT=,&DVD=,&DVS==P'10'
48 ZAP &QUOT,&DVD
49 DP &QUOT,&DVS
50 MEND
51 *

Page 337 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Here is the listing for the expansions of the macros. Note the use of a literal argument in lines 100 and 109. In the positional
macro, the literal has a single equals sign, while in the keyword macro it has two equals signs.
Note the errors in the first expansion of DIVID2. Consider line 104 in particular. The macro definition indicates that the text “ZAP”
is to be followed by a text string forthe first argument, followed by a comma, followed by a text string for the second argument.
However, neither text string has been provided properly, so it attempts to generate the string “ZAP , ”, which has no meaning.
95 * SOME MACRO INVOCATIONS
96 *
97 DIVID ARG1,ARG2,ARG3
00004A F831 C0B2 C0B6 000B8 000BC 98+ ZAP ARG1,ARG2
000050 FD31 C0B2 C0B8 000B8 000BE 99+ DP ARG1,ARG3
100 DIVID ARG1,ARG2,=P'30'
000056 F831 C0B2 C0B6 000B8 000BC 101+ ZAP ARG1,ARG2
00005C FD31 C0B2 C322 000B8 00328 102+ DP ARG1,=P'30'
103 DIVID2 ARG1,ARG2,ARG3
000062 0000 0000 0000 00000 00000 104+ ZAP ,
** ASMA074E Illegal syntax in expression - ,
000068 0000 0000 0000 00000 00000 105+ DP ,
** ASMA074E Illegal syntax in expression - ,
106 DIVID2 DVD=ARG2,DVS=ARG3,QUOT=ARG1
00006E F831 C0B2 C0B6 000B8 000BC 107+ ZAP ARG1,ARG2
000074 FD31 C0B2 C0B8 000B8 000BE 108+ DP ARG1,ARG3
109 DIVID2 DVD=ARG2,DVS==P'20',QUOT=ARG1
00007A F831 C0B2 C0B6 000B8 000BC 110+ ZAP ARG1,ARG2
000080 FD31 C0B2 C324 000B8 0032A 111+ DP ARG1,=P'20'
112 DIVID3 DVD=ARG2,QUOT=ARG1
000086 F831 C0B2 C0B6 000B8 000BC 113+ ZAP ARG1,ARG2
00008C FD31 C0B2 C326 000B8 0032C 114+ DP ARG1,=P'10'
115 *

Page 338 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

A Potential Problem with Macros.


It might appear that a macro invocation cannot be the target of a branch instruction. Here is
some of my early code. I had defined a macro, STKPOP, in the proper place. It was used by
a routine, called DOFACT, to be discussed later. As we shall see, DOFACT computes the
factorial of a small integer, hence the name.
At the time, I was working with non–standard ways to invoke subroutines.
I tried the following code:
B DOFACT CALL THE FACTORIAL CODE
Here is the branch target.
DOFACT STKPOP 4 POP THE ARGUMENT INTO R4
STKPOP 8 POP THE RETURN ADDRESS
BR 8 BRANCH TO RETURN ADDRESS
That did not assemble. The complaint was that the symbol DOFACT was not defined. What
happened? The label was clearly there in the source code. Where did the label go?

Here is What Happened.


Consider the following expansion from a macro call. It has been edited for clarity. At
present, the reader should not worry about lines 134 – 136 of the listing, but just focus on
line 137 (the macro invocation) and its expansion.
0000BA 4840 C4AE 134 A92POP LH 4,STKCOUNT
0000BE 4940 C5B4 135 CH 4,=H'0'
0000C2 47D0 C0FE 136 BNP A98DONE
137 STKPOP 4
0000C6 4830 C4AE 138+ LH 3,STKCOUNT
0000CA 4B30 C5B2 139+ SH 3,=H'1'
0000CE 4030 C4AE 140+ STH 3,STKCOUNT
0000D2 8B30 0002 141+ SLA 3,2
0000D6 4120 C4B2 142+ LA 2,THESTACK
0000DA 5843 2000 143+ L 4,0(3,2)
0000DE The next instruction
Note that the STKPOP instruction on line 137 is not assigned an object code address.
The instruction on line 136 is at address C2 and has length 4. The next instruction will be
at address C6. Only the expanded code is “real”. Line 137 is basically a comment.
In other words, we note two facts:
1. The expansion code is what counts for code accuracy.
2. The label DOFACT does not “make it” into the expanded code.
In my early work on the subject I had concluded that a macro invocation could not also be a
branch target. Then I did something almost radical, I actually read the relevant portion of the
IBM Assembler Language Manual [R_17]. I found the solution.

Page 339 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

The Solution to the Branch Target Problem


In order to solve the above problem, we need to focus on a more precise statement of the
form of a macro definition. We must focus on the prototype and body.
The general form of a prototype statement is as follows.
Symbolic Name Name of macro Zero or more symbolic parameters
If the symbolic name is to be used, it has the form of a symbolic parameter.
If the symbolic name is to be used, it must be duplicated on the first line of the body.
Here is an example, using the DIVID macro.
MACRO
&LABEL DIVID &QUOT,&DIVIDEND,&DIVISOR
&LABEL ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
MEND
Note that the symbolic parameter “&LABEL” is treated as any other such parameter. In
particular, it has local scope; thus the parameter has meaning only within the macro. The
most important point is that the label, first seen in the prototype is repeated in the first model
statement. It is that repetition that allows the label to be present in the expanded code.
Consider the prototype &LABEL DIVID &QUOT,&DIVIDEND,&DIVISOR
matched against the invocation B10DIV DIVID X,Y,Z
This forces the following substitutions in the model statements of the macro body.
&LABEL is replaced by B10DIV, &QUOT is replaced by X, etc. This positional replacement
mimics that seen in arguments to functions as used in high–level languages.

Code Example to Illustrate the Solution


MACRO
&LABEL DIVID &QUOT,&DIVIDEND,&DIVISOR
&LABEL ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
MEND
*
* NOW THE MACRO INVOCATIONS AND EXPANSIONS
*
B10DIV DIVID X,Y,Z
+B10DIV ZAP X,Y
+ DP X,Z
B20DIV DIVID A,B,C
+B20DIV ZAP A,B
+ DP A,C
*
Note that each of the labels B10DIV and B20DIV now appears in the expanded code
and can be used as a branch target address.

Page 340 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Concatenation: Building Operations


In a model statement, it is possible to concatenate two strings of characters.
Consider the macro prototype to load a register from one of several sources.
Note the use of the string “&NAME” to allow this to be a branch target.
MACRO
&NAME LOAD &REG,&TYPE,&ARG
&NAME L&TYPE &REG,&ARG
MEND
Consider a number of invocations.
LOAD R7,R,R6 becomes LR R7,R6
LOAD R7,H,HW becomes LH R7,HW
LOAD R7,,FW becomes L R7,FW
Note that the second argument in the third example is empty. The empty string is
concatenated to “L” to produce the single character “L”.

Our Stack Data Structure


The stack is implemented as an array of full words, with two auxiliary counters.
There is a halfword that counts the number of items on the stack.
There is a halfword constant that gives the maximum stack capacity. This is not changed by
the code. There is the fixed–size array that holds the stack elements.
Here is the declaration of the stack.
STKCOUNT DC H’0’ THE NUMBER OF ITEMS STORED ON STACK
STKSIZE DC H’64’ THE MAXIMUM STACK CAPACITY
THESTACK DC 64F’0’ THE STACK IS ACTUALLY AN ARRAY OF 64
FULLWORDS, REQUIRING 256 BYTES OF STORAGE.
Note that the elements are full–words while the addresses are byte addresses. The elements
of the stack will be stored at the following addresses.
THESTACK, THESTACK + 4, THESTACK + 8, THESTACK + 12
up to a full word starting at THESTACK + 252.

Initialize the Stack


Here is the macro that initializes the stack.
*STKINIT
MACRO
&L1 STKINIT
&L1 SR 4,4 CLEAR R4 – SUBTRACT FROM SELF
STH 4,STKCOUNT STORE AS THE STACK COUNT
MEND
*
Note the standard trick of clearing a register by subtracting it from itself. The register exists
only for the purpose of placing a 0 into the stack count. Following standard practice, the
contents of the stack are not changed, because the elements of interest will be overwritten
before they are used. Note that this macro does not have any symbolic parameters.

Page 341 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

PUSH: Placing Items Onto the Stack


Here is the macro STKPUSH
*STKPUSH
MACRO
&L2 STKPUSH &R
&L2 LH 3,STKCOUNT GET THE CURRENT STACK SIZE
* SLA BY 2 TO MULTIPLY BY FOUR
SLA 3,2 BYTE OFFSET OF INSERTION POINT
LA 2,THESTACK GET ADDRESS OF STACK START
ST &R,0(3,2) STORE THE ITEM INTO THE STACK
LH 3,STKCOUNT GET THE (NOW) OLD STACK SIZE
AH 3,=H’1’ INCREASE THE SIZE BY ONE
STH 3,STKCOUNT STORE THE NEW SIZE
MEND
*
This macro has one symbolic parameter: &R. It is to be a register number.
When called as STKPUSH 4, the operative statement is changed by the
assembler to ST 4,0(3,2) and executed as such at run time.

POP: Removing Items From the Stack


Here is the macro STKPOP
*STKPOP
MACRO
&L3 STKPOP &R
&L3 LH 3,STKCOUNT GET THE STACK COUNT
SH 3,=H’1’ SUBTRACT 1 WORD OFFSET OF TOP
STH 3,STKCOUNT STORE AS NEW SIZE
SLA 3,2 BYTE OFFSET OF STACK TOP
LA 2,THESTACK ADDRESS OF STACK BASE
L &R,0(3,2) LOAD ITEM INTO THE REGISTER
MEND
*
Again, this macro has one symbolic parameter: &R. Again, a register number.
When called as STKPOP 6, this is assembled with the last statement as
L 6,0(3,2).
NOTE:When invoked as STKPOP MYDOG, this will
assemble as L MYDOG,0(3,2); the assembler takes anything.
Needless to say, this last invocation will generate nonsense code if it assembles at all. If the
code does assemble, it will likely generate a run time error. The only way in which this bit of
doggerel (pardon the pun) would assemble is if the symbol MYDOG were equated (with EQU)
to an integer that could be interpreted as a general purpose register.

Page 342 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Using the Macros


Here is the part of the unexpanded source code that uses the macros. Here, it is obvious
that I have retained register R4 for communicating results with macros and subroutines.
That is an arbitrary choice.
STARTUP OPEN (FILEIN,(INPUT)) OPEN THE STANDARD INPUT
OPEN (PRINTER,(OUTPUT)) OPEN THE STANDARD OUTPUT
PUT PRINTER,PRHEAD PRINT HEADER
STKINIT INITIALIZE THE STACK
GET FILEIN,RECORDIN GET THE FIRST RECORD, IF THERE
*
A10LOOP MVC DATAPR,RECORDIN MOVE INPUT RECORD
PUT PRINTER,PRINT PRINT THE RECORD
PACK PACKIN,FIELD01 CONVERT DIGITS INPUT TO PACKED
CVB R4,PACKIN CONVERT THE NUMBER TO BINARY
STKPUSH 4 PUSH THE NUMBER ONTO THE STACK
GET FILEIN,RECORDIN GET THE NEXT RECORD
B A10LOOP GO BACK AND PROCESS
*
A90END CLOSE FILEIN
PUT PRINTER,ENDNOTE ANNOUNCE THE END OF INPUT DATA
A92POP LH 4,STKCOUNT GET THE STACK COUNT
CH 4,=H’0’ IS THE COUNT POSITIVE?
BNP A98DONE NO, WE ARE DONE
STKPOP 4 GET NEXT NUMBER INTO R4
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
BAL 8,NUMOUT PRODUCE THE FORMATTED SUM
MVC DATAPR,THENUM AND COPY TO THE PRINT AREA
PUT PRINTER,PRINT PRINT THE RESULT
B A92POP GO AND GET ANOTHER OUTPUT
A98DONE CLOSE PRINTER

Expansion of the Stack Pop


Here is the expanded code, edited from the assembler listing.
136 A92POP LH 4,STKCOUNT
137 CH 4,=H'0'
138 BNP A98DONE
139 STKPOP 4
140+ LH 3,STKCOUNT
141+ CH 3,=H'0'
142+ SH 3,=H'1'
143+ STH 3,STKCOUNT
144+ SLA 3,2
145+ LA 2,THESTACK
146+ L 4,0(3,2)
147 MVC PRINT,BLANKS
148 BAL 8,NUMOUT
149 MVC DATAPR,THENUM
150 PUT PRINTER,PRINT
151 *
Note: There is no RETURN statement or the like. The code is inserted in line.

Page 343 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

A Problem with the Macros


There is a problem with each of the macros STKPUSH and STKPOP. We show it for
STKPOP, because it is easier to see in this macro. Suppose we have code with the following
two macro calls, one immediately following the other.
STKINIT
STKPOP 6 NOTE: WE HAVE NOT PUSHED AN ITEM
The macro STKINIT will set the value at location STKCOUNT to 0. Now look at the code
in the expansion of macro STKPOP.
139 STKPOP 4
140+ LH 3,STKCOUNT
141+ CH 3,=H'0'
142+ SH 3,=H'1'
143+ STH 3,STKCOUNT
STKCOUNT will be set to –1, and the pop will reference the full word just before the stack.
This is the pair STKCOUNT, STKSIZE: an error. After line 143, the values will be.
STKCOUNT DC X‘FFFF’ MINUS ONE
STKSIZE DC X‘0040’ HEXADECIMAL REPRESENTATION OF 64.
Register 6 would be loaded with X‘FFFF0040’, which is a negative number. A bit of
arithmetic reveals this to be the negative of the number represented in hexadecimal as
X‘0000FFC0’ or as 65,472 in decimal.

Avoiding the Problem: A Flawed Solution


The obvious solution is to test the value of STKCOUNT and avoid popping a value if the
stack is empty. Here is some code that appears to do just that.
*STKPOP
MACRO
STKPOP &R
LH 3,STKCOUNT GET THE STACK SIZE
CH 3,=H'0'
BNP NOPOP
SH 3,=H'1' SUBTRACT 1 WORD OFFSET OF LAST
STH 3,STKCOUNT WORD AND STORE AS NEW SIZE
SLA 3,2 BYTE OFFSET OF STACK TOP
LA 2,THESTACK ADDRESS OF STACK START
L &R,0(3,2) LOAD ITEM INTO R4
NOPOP NOP A DO NOTHING TARGET FOR BNP
MEND
*
If the macro is written this way, the code will assemble and run correctly. Actually, it runs
correctly due only to a quirk in the code. It is a general principle that erroneous code might
run on occasion, but it will not run always.
We shall hold out for code that is correct in that it will always assemble, always run,
and always produce the correct result.

Page 344 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

What Is the Flaw?


The macro definition given above works ONLY because the macro is invoked only
one time. If the macro is invoked twice, trouble appears. In this modification of
running code, the macro is called twice in a row.
A90END CLOSE FILEIN NO MORE INPUT TO PROCESS
PUT PRINTER,ENDNOTE NOTE THE END OF DATA INPUT
A92POP LH 4,STKCOUNT GET THE STACK COUNT
CH 4,=H'0' IS IT POSITIVE
BNP A98DONE NO - WE ARE DONE HERE
STKPOP 4 GET NEXT NUMBER INTO R4
STKPOP 5 **** BAD CALL
MVC PRINT,BLANKS CLEAR THE OUTPUT AREA
BAL 8,NUMOUT PRODUCE THE FORMATTED SUM
MVC DATAPR,THENUM AND MOVE TO PRINT AREA
PUT PRINTER,PRINT PRINT THE NUMBER
B A92POP GO GET ANOTHER
A98DONE CLOSE PRINTER

Listing for Double Use of the Macro


Notice in the listing below that the first macro expansion produces no problems. It is the
second expansion that gives rise to the assembler error. The symbol NOPOP has already been
used when it is redefined in the second expansion. This is not allowed.
Note that this would not be a problem for a symbolic parameter, which has scope local to the
particular expansion of the macro.
139 STKPOP 4
140+ LH 3,STKCOUNT
141+ CH 3,=H'0'
142+ BNP NOPOP
143+ SH 3,=H'1'
144+ STH 3,STKCOUNT
145+ SLA 3,2
146+ LA 2,THESTACK
147+ L 4,0(3,2)
148+NOPOP NOP
148 STKPOP 5
149+ LH 3,STKCOUNT
150+ CH 3,=H'0'
151+ BNP NOPOP
152+ SH 3,=H'1'
153+ STH 3,STKCOUNT
154+ SLA 3,2
155+ LA 2,THESTACK
156+ L 4,0(3,2)
157+NOPOP NOP
** ASMA043E Previously defined symbol - NOPOP

Page 345 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Avoiding the Problem: A Correct Solution


Here is a solution to the problem. It works, but it complex to write. The solution is based on
the current location operator, *. It is a jump to a relative address in bytes. The complexity in
writing this is due to counting the bytes in each instruction beginning with the branch
instruction and ending just before the branch target. It is easy to miscount.
*STKPOP
MACRO
STKPOP &R
LH 3,STKCOUNT GET THE STACK SIZE
SH 3,=H'1' SUBTRACT 1 TO GET WORD OFFSET
* OF THE TOP ITEM IN THE STACK
CH 3,=H'0' IS THE NEW SIZE NEGATIVE?
BM *+20 YES, SO CANNOT POP AN ITEM
STH 3,STKCOUNT WORD AND STORE AS NEW SIZE
SLA 3,2 BYTE OFFSET OF STACK TOP
LA 2,THESTACK ADDRESS OF STACK START
L &R,0(3,2) LOAD ITEM INTO R4
SLA 3,0 A NO-OP TO SERVE AS A TARGET
MEND

Observations on the First Solution


The complexity of the above instruction is based on the necessity of counting bytes in the
object code, not instructions in the source code. The above example is simple, because all
instructions to be skipped have the same length. Let’s look at this again.
CH 3,=H'0' IS THE NEW SIZE NEGATIVE?
BM *+20 RX 4 A type RX instruction, length 4 bytes
STH 3,STKCOUNT RX 4 This instruction is at address *+4
SLA 3,2 RS 4 A type RS instruction at address *+8
LA 2,THESTACK RX 4 This is at address *+12
L &R,0(3,2) RX 4 Another 4-byte instruction at *+16
SLA 3,0 The branch target at address *+20

The Preferred Solution


What we need is a way to generate a branch target that would be unique to each expansion of
the macro. As should be expected, the System/370 assembler provides a method, which is
based on concatenation of system variable symbols. We describe this process in two stages,
first reviewing the idea of using concatenation to build symbols and operations. In our
earlier discussion we used concatenation to build load operators for various types.
MACRO
&NAME LOAD &REG,&TYPE,&ARG
&NAME L&TYPE &REG,&ARG
MEND
Consider a number of invocations, each of which constructs a load operator.
LOAD R7,R,R6 becomes LR R7,R6
LOAD R7,H,HW becomes LH R7,HW
LOAD R7,,FW becomes L R7,FW

Page 346 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

System Variable Symbols


The System/370 assembler provides a large number of special predefined symbols called
“system variable symbols”. There are a number of these symbols. I mention three.
&SYSDATE The system date, in the 8 character form “MM/DD/YY”.
Use in the form of a declaration of initialized storage, as in
TODAY DC C‘&SYSDATE’
&SYSTIME The system time of day, in the five character form “HH.MM”.
Also used in the form of a declaration, as in
NOW DC C‘&SYSTIME’
&SYSNDX The macro expansion index. For the first macro expansion, the
Assembler initializes &SYSNDX to the string “0001”. Each
expansion of any macro invocation increases the value represented
by 1, giving rise to the sequence “0001”, “0002”, “0003”, etc.
The &SYSNDX system variable symbol can prevent a macro from generating duplicate labels.
The system symbol is concatenated to a leading character, which begins the label and must
be unique within the macro definition. In what follows, we use the letter “L”. Consider the
following string, used as a label within the body of a macro definition.
L&SYSNDX L R4,STKSAV4
Note that the string “L&SYSNDX”, as written, contains eight characters: the initial character
“L” followed by the 7 character sequence “&SYSNDX”. On expansion, this will be converted
to labels such as “L0001”, “L0002”, etc. As the string “&SYSNDX” already takes seven
characters, it is better to make the prefix a single letter, though multiple letters are allowed.
In actual fact, the requirement for the leading characters, to which the &SYSNDX is to be
appended can be any sequence of one to four characters, provided only that the first character
is a letter. Thus the following are valid, but they disrupt the flow of the listing.
A12&SYSNDX ... This label might become A120003.
WXYZ&SYSNDX ... This might become WXYZ0117.

A Simple Example of Label Generation


Consider the simple macro used for packed division in the previous lecture.
We adapt it to prevent division by zero.
MACRO
&LABEL DIVID &QUOT,&DIVIDEND,&DIVISOR
&LABEL ZAP &QOUT,&DIVIDEND
CP &DIVISOR,=P‘0’ IS IT ZERO
BNE A&SYSNDX NO, DIVISION IS OK
ZAP &QUOT,=P‘0’ YES, SET QUOTIENT TO 0
B B&SYSNDX
A&SYSNDX DP &QUOT,&DIVISOR
B&SYSNDX NOPR R3 DO NOTHING
MEND
Note that the format of the NOPR instruction requires a register number
(here R3), even though the instruction does nothing.

Page 347 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Sample Expansion of the Macro


With the above definition, consider the following expansions.
A10START DIVID X,Y,Z
+A10START ZAP X,Y
+ CP Z,=P‘0’ IS IT ZERO
+ BNE A0001 NO, DIVISION IS OK
+ ZAP X,=P‘0’ YES, SET QUOTIENT TO 0
+ B B0001
+A0001 DP X,Z
+B0001 NOPR R3 DO NOTHING
A20DOIT DIVID A,B,C
+A20DOIT ZAP A,B
+ CP C,=P‘0’ IS IT ZERO
+ BNE A0002 NO, DIVISION IS OK
+ ZAP X,=P‘0’ YES, SET QUOTIENT TO 0
+ B B0002
+A0002 DP A,C
+B0002 NOPR R3 DO NOTHING
Note that each invocation has distinct labels. This removes the name clashes.
For the first expansion of the macro DIVID, the label &SYSNDX is replaced by the
string “0001” and on the second expansion, the label is replaced by “0002”.
It is important to note that the &SYSNDX is incremented due to the expansion of any macro.
Were there another macro expansion between the two invocations of the macro DIVID, the
second invocation of that macro would be associated with the replacement of the label
&SYSNDX by the string “0003”. The string “0002” would be associated with the
intermediate macro expansion, assuming that it used the system symbol &SYSNDX.

The Preferred Solution Applied to STKPOP


Here is a revision of the code that will avoid the problem of duplicate labels.
*STKPOP
MACRO
STKPOP &R
LH 3,STKCOUNT GET THE STACK SIZE
CH 3,=H'0'
BNP L&SYSNDX
SH 3,=H'1' SUBTRACT 1 WORD OFFSET OF LAST
STH 3,STKCOUNT WORD AND STORE AS NEW SIZE
SLA 3,2 BYTE OFFSET OF STACK TOP
LA 2,THESTACK ADDRESS OF STACK START
L &R,0(3,2) LOAD ITEM INTO R4
L&SYSNDX NOP A DO NOTHING TARGET FOR BNP
MEND
*

Page 348 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

STKPOP: Preferred Solution with Two Invocations


The following listing was produced when the revised macro definition above was
implemented in the source code.
139 STKPOP 4
140+ LH 3,STKCOUNT
141+ CH 3,=H'0'
142+ BNP L0001
143+ SH 3,=H'1'
144+ STH 3,STKCOUNT
145+ SLA 3,2
146+ LA 2,THESTACK
147+ L 4,0(3,2)
148+L0001 NOP
148 STKPOP 5
149+ LH 3,STKCOUNT
150+ CH 3,=H'0'
151+ BNP L0002
152+ SH 3,=H'1'
153+ STH 3,STKCOUNT
154+ SLA 3,2
155+ LA 2,THESTACK
156+ L 4,0(3,2)
157+L0002 NOP

Pushing from Various Sources


We look first at the handling of our STKPUSH. The only restriction on the stack is that every
value pushed be treated as a 32–bit fullword. As a result, a 16–bit halfword will be sign–
extended to a 32–bit fullword before being pushed onto the stack. This is similar to the
function of the LH instruction, which loads a register from a halfword.
The key instruction in the original STKPUSH macro is the following.
ST &R,0(3,2) STORE THE ITEM INTO THE STACK
In this case, the item to be placed on the stack is found in the register
indicated by the symbolic parameter &R.
The way to extend this instruction to all data types is as follows.
1. Select a register to be a fixed source for the word on the stack, and
2. Construct instructions to load that fixed register from the source.

What Shall Be Stored on the Stack?


At this point, we have a decision to make. What data types to store? The size restriction on
the stack limits the simple choices to addresses and the contents of registers, halfwords, and
fullwords. We must select a working register for the new macro. I select R4.
The “key code” becomes as follows.
Stacking an address LA R4,&ARG Load address into R4.
Stacking a halfword LH R4,&ARG Load halfword into R4.
Stacking a fullword L R4,&ARG Load fullword into R4.
Stacking a register LR R4,&ARG Load value from source register

Page 349 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Passing the Type in a Macro Invocation


The solution adopted to the problem above is to pass the type in the macro call and use
concatenation to build the load operator. Here is some code taken from a macro definition
that has been run and tested.
First, we show the macro prototype.
&L2 STKPUSH &ARG,&TYP
Next we show the “key instruction” in the macro body.
L&TYP R4,&ARG
Here are four typical invocations of the macro.
STKPUSH R7,R PUSH VALUE IN REGISTER.
STKPUSH HHW,H PUSH A HALFWORD VALUE.
STKPUSH FFW,A PUSH AN ADDRESS.
STKPUSH FFW PUSH A FULLWORD.
Note that the last invocation lacks a second argument. In the expansion, this
causes &TYP to be set to ‘ ’, a blank; “L&TYP” becomes “L ”.

The Macro Definition


Here is the definition for the macro at this stage of its development.
MACRO
&L2 STKPUSH &ARG,&TYP
&L2 LH R3,STKCOUNT
SLA R3,2
LA R2,THESTACK
L&TYP R4,&ARG
ST R4,0(3,2)
LH R3,STKCOUNT
AH R3,=H'1'
STH 3,STKCOUNT
MEND
Again, the “&L2” allows the macro invocation to be a branch target. This is a practice that
your author has decided to employ, even absent a present need to use any invocation of the
macro as a branch target. This is a flexibility option only; one that is easy to implement.
At this point, the code fixes on general–purpose registers R3 and R4 for use. There is no
particular logic to these choices; it is just that two registers had to be chosen. The point here
is to focus on the construction of the operator using the concatenation “L&TYP”.
This macro will be invoked with four distinct values for the second parameter, &TYP. Again,
the value is “” for push fullword, “H” for push a sign–extended halfword, “A” for an
address, and “R” for register. As always, there is insufficient error checking code. It is
assumed that the macro will always be invoked with the correct type.

Page 350 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Some Invocations of this Macro


91 STKPUSH R7,R
92+ LH R3,STKCOUNT
93+ SLA R3,2
94+ LA R2,THESTACK
95+ LR R4,R7
96+ ST R4,0(3,2)
97+ LH R3,STKCOUNT
98+ AH R3,=H'1'
99+ STH 3,STKCOUNT

100 STKPUSH HHW,H


101+ LH R3,STKCOUNT
102+ SLA R3,2
103+ LA R2,THESTACK
104+ LH R4,HHW
105+ ST R4,0(3,2)
106+ LH R3,STKCOUNT
107+ AH R3,=H'1'
108+ STH 3,STKCOUNT

More Invocations of this Macro


109 STKPUSH FFW
110+ LH R3,STKCOUNT
111+ SLA R3,2
112+ LA R2,THESTACK
113+ L R4,FFW
114+ ST R4,0(3,2)
115+ LH R3,STKCOUNT
116+ AH R3,=H'1'
117+ STH 3,STKCOUNT

118 STKPUSH FFW,A


119+ LH R3,STKCOUNT
120+ SLA R3,2
121+ LA R2,THESTACK
122+ LA R4,FFW
123+ ST R4,0(3,2)
124+ LH R3,STKCOUNT
125+ AH R3,=H'1'
126+ STH 3,STKCOUNT
NOTE: The originals of the program listing are found at the end of the chapter.

Page 351 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Saving the Work Registers


As written, this macro has the side effect of changing the values of three registers:
R2, R3, and R4. The value of R4 is preserved only if it is being pushed. We should write
macros so that they operate without side effects. The only way to do this is to save and
restore the values of the work registers. There are many ways to do this. The simplest is to
alter the stack data structure. Here is the new version.
STKCOUNT DC H‘0’ NUMBER OF ITEMS STORED ON STACK
STKSIZE DC H‘64’ MAXIMUM STACK CAPACITY
STKSAV2 DC F‘0’ SAVES CONTENTS OF R2
STKSAV3 DC F‘0’ SAVES CONTENTS OF R3
STKSAV4 DC F‘0’ SAVES CONTENTS OF R4
THESTACK DC 64F‘0’ THE STACK HOLDS 64 FULLWORDS
This new definition does not alter the STKINIT macro. It does affect the
other two macros: STKPOP and STKPUSH. We illustrate the latter.

The First Revision of STKPUSH


Here is the revision that allows the work registers to be saved.
MACRO
&L2 STKPUSH &ARG,&TYP
&L2 ST R2,STKSAV2 THE ORDER OF SAVING
ST R3,STKSAV3 IS NOT IMPORTANT.
ST R4,STKSAV4
LH R3,STKCOUNT
SLA R3,2
LA R2,THESTACK
L&TYP R4,&ARG
ST R4,0(3,2)
LH R3,STKCOUNT
AH R3,=H'1'
STH R3,STKCOUNT
L R4,STKSAV4 THE ORDER OF RESTORATION
L R3,STKSAV3 IS NOT IMPORTANT EITHER.
L R2,STKSAV2
MEND

The Status of the Macros at This Point


There are a few issues to be addressed at this point.
The only macro that will not change is the initialization macro, STKINIT.
1. We have not yet dealt with generalizing the STKPOP macro.
2. We have not yet dealt with either the stack empty problem or
that of the stack being full. Each has to be addressed.
Each of these issues requires some additional code. We now move towards the final versions
of each of the macros.

Page 352 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

The First Revision of STKINIT


Here is a revision of the STKINIT code that allows initialization of its size. This was done in
order to show how to concatenate the symbolic parameter &SIZE as a prefix.
35 MACRO
36 &L1 STKINIT &SIZE
37 &L1 ST R3,STKSAV3
38 SR R3,R3
39 STH R3,STKCOUNT
40 L R3,STKSAV3
41 B L&SYSNDX
42 STKCOUNT DC H'0'
43 STKSIZE DC H'&SIZE'
44 STKSAV2 DC F'0'
45 STKSAV3 DC F'0'
46 STKSAV4 DC F'0'
47 THESTACK DC &SIZE.F'0'
48 L&SYSNDX SLA R3,0
49 MEND
Note the “.” in the definition of THESTACK as DC &SIZE.F'0'. This concatenates the
value of the symbolic parameter with “F‘0’”, as in “128F‘0’”

The Second Revision of STKPUSH


Here is the final version of the macro for pushing onto the stack.
MACRO
&L2 STKPUSH &ARG,&TYP
&L2 ST R3,STKSAV3
LH R3,STKCOUNT GET COUNT OF ITEMS ON THE STACK
CH R3,STKSIZE IS THE STACK FULL?
BNL Z&SYSNDX YES, DO NOT ADD ANOTHER.
ST R4,STKSAV4 NO, WE CAN PUSH ANOTHER ITEM.
ST R2,STKSAV2 START BY SAVING THE OTHER 2 REGISTERS
SLA R3,2 MULTIPLY THE INDEX BY 4.
LA R2,THESTACK
L&TYP R4,&ARG FORM THE ADDRESS
ST R4,0(3,2) STORE THE ITEM
LH R3,STKCOUNT GET THE OLD COUNT OF ITEMS
AH R3,=H'1' INCREMENT THE COUNT BY 1
STH R3,STKCOUNT STORE THE CURRENT COUNT
L R4,STKSAV4 RESTORE THE REGISTERS.
L R2,STKSAV2
Z&SYSNDX L R3,STKSAV3
MEND

Page 353 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Conditional Assembly
Consider the problem of generalizing STKPOP. We shall want to pop the following from the
stack: register values, halfwords, and fullwords. The type for the argument refers to the
destination; an address can be popped into either a register or fullword. In order to see the
problem for STKPOP, consider the “key instruction”.
Halfword: STH R4,&ARG
Fullword: ST R4,&ARG
Register: LR &ARG,R4 No STR for store register.
We could write a STR macro, but I want to use another solution. We have already seen how
concatenation can be used to construct different instructions in a macro expansion. We now
investigate conditional assembly, in which the expansion of a macro can lead to a number of
distinct code sequences.
Conditional assembly permits the testing of attributes such as data format, data value, or field
length, and to use the results of such testing to generate source code that is specific to the
case in question. This chapter will focus on five specific conditional assembly instructions.
AGO an unconditional branch
AIF a conditional branch. This means “Ask If”.
ANOP A NOP that can be the branch target for either AGO or AIF.
MNOTE print a programmer defined message at assembly time
MEXIT exit the macro definition.

Attributes for Use by Conditional Assembly


The assembler can generate code specified by certain attributes of the arguments to the
macro definition at the time it is expanded. There are six types of attributes that can be
associated with a parameter. Here are three if the more useful attributes.
L’ Length The length of the symbolic parameter
I’ Integer The integer attribute of a fixed–point,
floating–point, or packed decimal number.
T’ Type The type of the parameter, as specified by the
DC or DS declaration with which it is defined.
Some types for the T’ attribute are as follows.
A Address H Halfword
B Binary I Instruction
C Character P Packed Decimal
F Fullword X Hexadecimal

The Sequence Symbol


Conditional assembly is built on the ability to generate conditional branching in the code
generation process. In this, it is not that branch assembler language statements are used, but
that entire segments of code will not even be assembled.
The assembler uses sequence symbols, denoted by the “.” (period) prefix. More on this later.

Page 354 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

The Ask If (AIF) Instruction


The AIF instruction has two parts.
1. A logical expression in parentheses, and
2. A sequence symbol immediately following, which serves as the branch target.
The AIF logical expression may use the following relational operators, which
are quite similar to those seen in early versions of the FORTRAN language.
EQ Equal To NE Not Equal To
LT Less Than GE Greater Than or Equal To
GT Greater Than LE Less Than or Equal To
If the type of &AMT is packed, go to .B23PACK
AIF(T’&AMT EQ ‘P’).B23PACK
If the type of &LINK is not an instruction, go to .R30ERROR
AIF(T’&LINK NE ‘I’).R30ERROR
Here, each of .B23PACK and .R30ERROR are sequence symbols.

Testing the Value of a Symbolic Parameter


What we want for the STKPOP instruction is a conditional assembly based on the value of
the second parameter. The prototype for the macro will be something like
&L1 STKPOP &ARG,&TYP
What we want to issue is an AIF statement such as
AIF (&TYP EQ ‘R’).ISREG
There is a well–known peculiarity in any assembler language, not just in the IBM Assembler,
that disallows this straightforward construct.
We must put the symbolic parameter in single quotes. The statement is thus:
AIF (‘&TYP’ EQ ‘R’).ISREG
If &TYP is the character R, the logical expression becomes (‘R’ EQ ‘R’),
which immediately evaluates to True, and the branch is taken. [Page 384, R_17]

Targets for Use by Conditional Assembly


Each of the AGO and AIF instructions is a branch instruction that takes effect at assembly
time. Neither persists into the assembly source code. It should be expected that the targets
for either of these conditional assembly branch instructions should be of a distinct type. The
targets for these are called sequence symbols.
The format of a sequence symbol is as follows. A sequence symbol begins with a period (.)
followed by one to seven letters or digits, the first of which must be a letter.
Unlike the symbols created by use of the &SYSNDX system symbol, sequence symbols do
not persist into assembly time, and thus cannot generate a name conflict for the assembler.

Page 355 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

A Sample of Conditional Assembly


Here is the DIVID macro, with conditional assembly instructions to
insure that it is expanded only for parameters that are packed decimal.
MACRO
&LABEL DIVID &QUOT,&DIVIDEND,&DIVISOR
AIF (T’&QUOT NE ‘P’).NOTPACK
AIF (T’&DIVIDEND NE T’&QUOT).NOTPACK
AIF (T’&DIVISOR NE T’&QUOT).NOTPACK
AGO .DOIT
.NOTPAK MNOTE ‘ONE PARAMETER IS NOT PACKED DECIMAL’
MEXIT
.DOIT ANOP
&LABEL ZAP &QOUT,&DIVIDEND
CP &DIVISOR,=P‘0’ IS IT ZERO
BNE A&SYSNDX NO, DIVISION IS OK
ZAP &QUOT,=P‘0’ YES, SET QUOTIENT TO 0
B B&SYSNDX
A&SYSNDX DP &QUOT,&DIVISOR
B&SYSNDX NOPR R3 DO NOTHING
MEND

Some Examples of the Conditional Assembly Divide Macro


In the following, assume that each of X, Y, and Z is defined by a DC statement as packed
decimal, but that A, B, and C are defined as halfwords. Here are some possible expansions.
F10DOIT DIVID X,Y,Z
+F10DOIT ZAP X,Y
+ CP Z,=P‘0’ IS IT ZERO
+ BNE A0032 NO, DIVISION IS OK
+ ZAP X,=P‘0’ YES, SET QUOTIENT TO 0
+ B B0032
+A0032 DP X,Z
+B0032 NOPR R3 DO NOTHING
F25NODO DIVID A,B,C
+ONE PARAMETER IS NOT PACKED DECIMAL

The Original Definition of Macro STKPOP


We now begin our redefinition of the STKPOP macro.
We begin with the original definition, which popped a value into a register.
*STKPOP
MACRO
&L3 STKPOP &R
&L3 LH 3,STKCOUNT GET THE STACK COUNT
SH 3,=H’1’ SUBTRACT 1 WORD OFFSET OF TOP
STH 3,STKCOUNT STORE AS NEW SIZE
SLA 3,2 BYTE OFFSET OF STACK TOP
LA 2,THESTACK ADDRESS OF STACK BASE
L &R,0(3,2) LOAD ITEM INTO THE REGISTER.
MEND

Page 356 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Again, this macro has one symbolic parameter: &R. Again, a register number. We want to
expand this definition in a number of ways. We begin by introducing the type &TYP.
At this point, it will become necessary to have another work register.

Mechanics of the Revised STKPOP


The new design will use register R4 to transfer the value at the top of the stack.
The new prototype will be as follows.
&L3 STKPOP &ARG,&TYP
Each type of instruction will include the following as the first statement
in the “key code” – that which actually places the value into the destination.
L R4,0(3,2) LOAD ITEM INTO REGISTER R4.
The second statement of the “key code” depends on the type of the destination.
&TYP == H STH R4,&ARG
&TYP == F ST R4,&ARG
&TYP == A ST R4,&ARG (SAME AS FULLWORD)
&TYP == R LR &ARG,R4 COPY R4 INTO REGISTER
Here is the key code section, with the conditional assembly.
The first statement is common to all types.
L R4,0(3,2) LOAD ITEM INTO REGISTER R4.
AIF (‘&TYPE’ EQ ‘R’).ISREG
ST&TYP R4,&ARG
AGO .CONT
.ISREG LR &ARG,R4
.CONT The next statement.

STKPOP: Revision 2
Here I am going to add some code to save and restore the work registers.
MACRO
&L3 STKPOP &ARG,&TYP
&L3 ST R2,STKSAV2
ST R3,STKSAV3
ST R4,STKSAV4
LH R3,STKCOUNT GET THE STACK COUNT
SH R3,=H’1’ SUBTRACT 1 WORD OFFSET OF TOP
STH R3,STKCOUNT STORE AS NEW SIZE
SLA R3,2 BYTE OFFSET OF STACK TOP
LA R2,THESTACK ADDRESS OF STACK BASE
L R4,0(3,2) LOAD ITEM INTO REGISTER R4.
AIF (‘&TYPE’ EQ ‘R’).ISREG
ST&TYP R4,&ARG
AGO .CONT
.ISREG LR &ARG,R4
.CONT L R4,STKSAV4
L R3,STKSAV3
L R2,STKSAV2
MEND

Page 357 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

STKPOP: The Complete Version


MACRO
&L3 STKPOP &ARG,&TYP
&L3 ST R3,STKSAV3
LH R3,STKCOUNT GET THE STACK COUNT
CH R3,=H‘0’ IS THE COUNT POSITIVE
BNH Z&SYSNDX NO, WE CANNOT POP.
SH R3,=H’1’ SUBTRACT 1 WORD OFFSET OF TOP
STH R3,STKCOUNT STORE AS NEW SIZE
SLA R3,2 BYTE OFFSET OF STACK TOP
ST R2,STKSAV2 SAVE REGISTER R2
ST R4,STKSAV4 SAVE REGISTER R4
LA R2,THESTACK ADDRESS OF STACK BASE
L R4,0(3,2) LOAD ITEM INTO REGISTER R4.
AIF (‘&TYPE’ EQ ‘R’).ISREG
ST&TYP R4,&ARG
AGO .CONT
.ISREG LR &ARG,R4
.CONT L R4,STKSAV4
L R2,STKSAV2
Z&SYSNDX L R3,STKSAV3
MEND

Page 358 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Original Code for the Macro Expansions


33 * MACRO DEFINITIONS
34 *
35 MACRO
36 &L2 STKPUSH &ARG,&TYP
37 &L2 LH R3,STKCOUNT
38 SLA R3,2
39 LA R2,THESTACK
40 L&TYP R4,&ARG
41 ST R4,0(3,2)
42 LH R3,STKCOUNT
43 AH R3,=H'1'
44 STH 3,STKCOUNT
45 MEND
46 *
89 * SOME MACRO INVOCATIONS
90 *
91 STKPUSH R7,R
00004A 4830 C0C6 000CC 92+ LH R3,STKCOUNT
00004E 8B30 0002 00002 93+ SLA R3,2
000052 4120 C0CA 000D0 94+ LA R2,THESTACK
000056 1847 95+ LR R4,R7
000058 5043 2000 00000 96+ ST R4,0(3,2)
00005C 4830 C0C6 000CC 97+ LH R3,STKCOUNT
000060 4A30 C43A 00440 98+ AH R3,=H'1'
000064 4030 C0C6 000CC 99+ STH 3,STKCOUNT
100 STKPUSH HHW,H
000068 4830 C0C6 000CC 101+ LH R3,STKCOUNT
00006C 8B30 0002 00002 102+ SLA R3,2
000070 4120 C0CA 000D0 103+ LA R2,THESTACK
000074 4840 C1CE 001D4 104+ LH R4,HHW
000078 5043 2000 00000 105+ ST R4,0(3,2)
00007C 4830 C0C6 000CC 106+ LH R3,STKCOUNT
000080 4A30 C43A 00440 107+ AH R3,=H'1'
000084 4030 C0C6 000CC 108+ STH 3,STKCOUNT
109 STKPUSH FFW
000088 4830 C0C6 000CC 110+ LH R3,STKCOUNT
00008C 8B30 0002 00002 111+ SLA R3,2
000090 4120 C0CA 000D0 112+ LA R2,THESTACK
000094 5840 C1CA 001D0 113+ L R4,FFW
000098 5043 2000 00000 114+ ST R4,0(3,2)
00009C 4830 C0C6 000CC 115+ LH R3,STKCOUNT
0000A0 4A30 C43A 00440 116+ AH R3,=H'1'
0000A4 4030 C0C6 000CC 117+ STH 3,STKCOUNT
118 STKPUSH FFW,A
0000A8 4830 C0E6 000EC 119+ LH R3,STKCOUNT
0000AC 8B30 0002 00002 120+ SLA R3,2
0000B0 4120 C0EA 000F0 121+ LA R2,THESTACK
0000B4 4140 C1EA 001F0 122+ LA R4,FFW
0000B8 5043 2000 00000 123+ ST R4,0(3,2)
0000BC 4830 C0E6 000EC 124+ LH R3,STKCOUNT
0000C0 4A30 C45A 00460 125+ AH R3,=H'1'
0000C4 4030 C0E6 000EC 126+ STH 3,STKCOUNT
127 *
136 **********************************

Page 359 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Revised Code for the Macros


The next few pages show the listing of the final forms of the macros, as actually
coded and tested. These are followed by listings of the expanded macros.
002900 *
002910 MACRO
002911 &L1 STKINIT
002912 &L1 ST R3,STKSAV3
002913 SR R3,R3
002914 STH R3,STKCOUNT CLEAR THE COUNT
002915 L R3,STKSAV3
002920 MEND
002930 *

003000 MACRO
003100 &L2 STKPUSH &ARG,&TYP
003110 &L2 ST R3,STKSAV3 SAVE REGISTER R3
003200 LH R3,STKCOUNT GET THE CURRENT SIZE
003210 CH R3,STKSIZE IS THE STACK FULL?
003220 BNL Z&SYSNDX YES, DO NOT PUSH
003230 ST R4,STKSAV4 OK, SAVE R2 AND R4
003240 ST R2,STKSAV2
003300 SLA R3,2 MULTIPLY BY FOUR
003310 LA R2,THESTACK ADDRESS OF STACK START
003320 L&TYP R4,&ARG LOAD R4 WITH VALUE
003330 ST R4,0(3,2) STORE INTO THE STACK
003331 LH R3,STKCOUNT
003332 AH R3,=H'1'
003333 STH 3,STKCOUNT
003334 L R4,STKSAV4
003335 L R2,STKSAV2
003336 Z&SYSNDX L R3,STKSAV3
003337 MEND
003338 *
003339 *

Page 360 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

003340 MACRO
003341 &L3 STKPOP &ARG,&TYP
003342 &L3 ST R3,STKSAV3
003343 LH R3,STKCOUNT GET THE STACK COUNT
003344 CH R3,=H'0' IS THE COUNT POSITIVE?
003345 BNH Z&SYSNDX NO, WE CANNOT POP
003346 SH R3,=H'1' SUBTRACT 1 WORD OFFSET
003347 STH R3,STKCOUNT STORE THE NEW SIZE
003348 SLA R3,2 BYTE OFFSET OF STACK TOP
003349 ST R2,STKSAV2 SAVE REGISTER R2
003350 ST R4,STKSAV4 SAVE REGISTER R4
003351 LA R2,THESTACK ADDRESS OF STACK BASE
003352 L R4,0(3,2) LOAD ITEM INTO R4
003353 AIF ('&TYP' EQ 'R').ISREG
003354 ST&TYP R4,&ARG
003355 AGO .CONT
003356 .ISREG LR &ARG,R4
003357 .CONT L R4,STKSAV4
003358 L R2,STKSAV2
003359 Z&SYSNDX L R3,STKSAV3
003360 MEND
003361 *

Revised Code for the Macro STKINIT


Here is an expansion of the newer definition of STKINIT,
which allows the stack size to be specified.
138 STKINIT 128
00004A 5030 C05E 00064 139+ ST R3,STKSAV3
00004E 1B33 140+ SR R3,R3
000050 4030 C056 0005C 141+ STH R3,STKCOUNT
000054 5830 C05E 00064 142+ L R3,STKSAV3
000058 47F0 C266 0026C 143+ B L0009
00005C 0000 144+STKCOUNT DC H'0'
00005E 0080 145+STKSIZE DC H'128'
000060 00000000 146+STKSAV2 DC F'0'
000064 00000000 147+STKSAV3 DC F'0'
000068 00000000 148+STKSAV4 DC F'0'

Page 361 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

Revised Code for the Macro Expansions


128 * SOME MACRO INVOCATIONS
129 *
130 STKINIT
00004A 5030 C22E 00234 131+ ST R3,STKSAV3
00004E 1B33 132+ SR R3,R3
000050 4030 C226 0022C 133+ STH R3,STKCOUNT
000054 5830 C22E 00234 134+ L R3,STKSAV3
135 *
* Stack Push with a Register as an Argument
136 STKPUSH R7,R
000058 5030 C22E 00234 137+ ST R3,STKSAV3
00005C 4830 C226 0022C 138+ LH R3,STKCOUNT
000060 4930 C228 0022E 139+ CH R3,STKSIZE
000064 47B0 C08C 00092 140+ BNL Z0010
000068 5040 C232 00238 141+ ST R4,STKSAV4
00006C 5020 C22A 00230 142+ ST R2,STKSAV2
000070 8B30 0002 00002 143+ SLA R3,2
000074 4120 C236 0023C 144+ LA R2,THESTACK
000078 1847 145+ LR R4,R7
00007A 5043 2000 00000 146+ ST R4,0(3,2)
00007E 4830 C226 0022C 147+ LH R3,STKCOUNT
000082 4A30 C5A2 005A8 148+ AH R3,=H'1'
000086 4030 C226 0022C 149+ STH 3,STKCOUNT
00008A 5840 C232 00238 150+ L R4,STKSAV4
00008E 5820 C22A 00230 151+ L R2,STKSAV2
000092 5830 C22E 00234 152+Z0010 L R3,STKSAV3

* Stack Push with a Halfword as an Argument


153 STKPUSH HHW,H
000096 5030 C22E 00234 154+ ST R3,STKSAV3
00009A 4830 C226 0022C 155+ LH R3,STKCOUNT
00009E 4930 C228 0022E 156+ CH R3,STKSIZE
0000A2 47B0 C0CC 000D2 157+ BNL Z0011
0000A6 5040 C232 00238 158+ ST R4,STKSAV4
0000AA 5020 C22A 00230 159+ ST R2,STKSAV2
0000AE 8B30 0002 00002 160+ SLA R3,2
0000B2 4120 C236 0023C 161+ LA R2,THESTACK
0000B6 4840 C33A 00340 162+ LH R4,HHW
0000BA 5043 2000 00000 163+ ST R4,0(3,2)
0000BE 4830 C226 0022C 164+ LH R3,STKCOUNT
0000C2 4A30 C5A2 005A8 165+ AH R3,=H'1'
0000C6 4030 C226 0022C 166+ STH 3,STKCOUNT
0000CA 5840 C232 00238 167+ L R4,STKSAV4
0000CE 5820 C22A 00230 168+ L R2,STKSAV2
0000D2 5830 C22E 00234 169+Z0011 L R3,STKSAV3

Page 362 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

* Stack Push with a Fullword as an Argument


170 STKPUSH FFW
0000D6 5030 C22E 00234 171+ ST R3,STKSAV3
0000DA 4830 C226 0022C 172+ LH R3,STKCOUNT
0000DE 4930 C228 0022E 173+ CH R3,STKSIZE
0000E2 47B0 C10C 00112 174+ BNL Z0012
0000E6 5040 C232 00238 175+ ST R4,STKSAV4
0000EA 5020 C22A 00230 176+ ST R2,STKSAV2
0000EE 8B30 0002 00002 177+ SLA R3,2
0000F2 4120 C236 0023C 178+ LA R2,THESTACK
0000F6 5840 C336 0033C 179+ L R4,FFW
0000FA 5043 2000 00000 180+ ST R4,0(3,2)
0000FE 4830 C226 0022C 181+ LH R3,STKCOUNT
000102 4A30 C5A2 005A8 182+ AH R3,=H'1'
000106 4030 C226 0022C 183+ STH 3,STKCOUNT
00010A 5840 C232 00238 184+ L R4,STKSAV4
00010E 5820 C22A 00230 185+ L R2,STKSAV2
000112 5830 C22E 00234 186+Z0012 L R3,STKSAV3

* Stack Push with an Address as an Argument


187 STKPUSH FFW,A
000116 5030 C22E 00234 188+ ST R3,STKSAV3
00011A 4830 C226 0022C 189+ LH R3,STKCOUNT
00011E 4930 C228 0022E 190+ CH R3,STKSIZE
000122 47B0 C14C 00152 191+ BNL Z0013
000126 5040 C232 00238 192+ ST R4,STKSAV4
00012A 5020 C22A 00230 193+ ST R2,STKSAV2
00012E 8B30 0002 00002 194+ SLA R3,2
000132 4120 C236 0023C 195+ LA R2,THESTACK
000136 4140 C336 0033C 196+ LA R4,FFW
00013A 5043 2000 00000 197+ ST R4,0(3,2)
00013E 4830 C226 0022C 198+ LH R3,STKCOUNT
000142 4A30 C5A2 005A8 199+ AH R3,=H'1'
000146 4030 C226 0022C 200+ STH 3,STKCOUNT
00014A 5840 C232 00238 201+ L R4,STKSAV4
00014E 5820 C22A 00230 202+ L R2,STKSAV2
000152 5830 C22E 00234 203+Z0013 L R3,STKSAV3
204 *

* Stack Pop with a Register as an Argument


205 STKPOP R8,R
000156 5030 C22E 00234 206+ ST R3,STKSAV3
00015A 4830 C226 0022C 207+ LH R3,STKCOUNT
00015E 4930 C5A4 005AA 208+ CH R3,=H'0'
000162 47D0 C186 0018C 209+ BNH Z0014
000166 4B30 C5A2 005A8 210+ SH R3,=H'1'
00016A 4030 C226 0022C 211+ STH R3,STKCOUNT
00016E 8B30 0002 00002 212+ SLA R3,2
000172 5020 C22A 00230 213+ ST R2,STKSAV2
000176 5040 C232 00238 214+ ST R4,STKSAV4
00017A 4120 C236 0023C 215+ LA R2,THESTACK
00017E 5843 2000 00000 216+ L R4,0(3,2)
000182 1884 217+ LR R8,R4
000184 5840 C232 00238 218+ L R4,STKSAV4
000188 5820 C22A 00230 219+ L R2,STKSAV2
00018C 5830 C22E 00234 220+Z0014 L R3,STKSAV3

Page 363 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Writing Macros

* Stack Pop with a Fullword as an Argument


221 STKPOP FFW
000190 5030 C22E 00234 222+ ST R3,STKSAV3
000194 4830 C226 0022C 223+ LH R3,STKCOUNT
000198 4930 C5A4 005AA 224+ CH R3,=H'0'
00019C 47D0 C1C2 001C8 225+ BNH Z0015
0001A0 4B30 C5A2 005A8 226+ SH R3,=H'1'
0001A4 4030 C226 0022C 227+ STH R3,STKCOUNT
0001A8 8B30 0002 00002 228+ SLA R3,2
0001AC 5020 C22A 00230 229+ ST R2,STKSAV2
0001B0 5040 C232 00238 230+ ST R4,STKSAV4
0001B4 4120 C236 0023C 231+ LA R2,THESTACK
0001B8 5843 2000 00000 232+ L R4,0(3,2)
0001BC 5040 C336 0033C 233+ ST R4,FFW
0001C0 5840 C232 00238 234+ L R4,STKSAV4
0001C4 5820 C22A 00230 235+ L R2,STKSAV2
0001C8 5830 C22E 00234 236+Z0015 L R3,STKSAV3

* Stack Pop with a Halfword as an Argument


237 STKPOP HHW,H
0001CC 5030 C22E 00234 238+ ST R3,STKSAV3
0001D0 4830 C226 0022C 239+ LH R3,STKCOUNT
0001D4 4930 C5A4 005AA 240+ CH R3,=H'0'
0001D8 47D0 C1FE 00204 241+ BNH Z0016
0001DC 4B30 C5A2 005A8 242+ SH R3,=H'1'
0001E0 4030 C226 0022C 243+ STH R3,STKCOUNT
0001E4 8B30 0002 00002 244+ SLA R3,2
0001E8 5020 C22A 00230 245+ ST R2,STKSAV2
0001EC 5040 C232 00238 246+ ST R4,STKSAV4
0001F0 4120 C236 0023C 247+ LA R2,THESTACK
0001F4 5843 2000 00000 248+ L R4,0(3,2)
0001F8 4040 C33A 00340 249+ STH R4,HHW
0001FC 5840 C232 00238 250+ L R4,STKSAV4
000200 5820 C22A 00230 251+ L R2,STKSAV2
000204 5830 C22E 00234 252+Z0016 L R3,STKSAV3
253 *
00006C 0000000000000000 149+THESTACK DC 128F'0'
00026C 8B30 0000 00000 150+L0009 SLA R3,0

Page 364 Chapter 18 Revised August 3, 2009


Copyright © by Edward L. Bosworth, Ph.D.
Chapter 19: Handling of Arrays, Strings and Other Data Structures

Up to this point, we have studied simple data types and basic arrays built on those simple
data types. Some of the simple data types studied include.
a) Integers: both halfword and fullword.
b) Packed decimal
c) Character data.
This lecture will cover the following:
1. A generalized “self describing” array that includes limits on the
permitted index values. Only 1–D and 2–D arrays will be considered.
2. Options for a string data type and how that differs from a character array.
3. Use of indirect addressing with pointer structures generalized to
include descriptions of the data item pointed to.

Structures of Arrays
We first consider the problem of converting an index in a one–dimensional array into an byte
displacement. We then consider two ways of organizing a two–dimensional array, and
proceed to convert the index pair into a byte displacement.
The simple array type has two variants:
0–based: The first element in the array is either AR[0] for a singly
dimensioned array or AR[0][0] for a 2–D array.
1–based: The first element in the array is either AR[1] for a singly
dimensioned array or AR[1][1] for a 2–D array.
We shall follow the convention of using only 0–based arrays. One reason is that it allows for
efficient conversion from a set of indices into a displacement from the base address.
By definition, the base address of an array will be the address of its first element: either the
address of AR[0] or AR[0][0].

Byte Displacement and Addressing Array Elements: The General Case


We first consider addressing issues for an array that contains either character halfword, or
fullword data. It will be constrained to one of these types. The addressing issue is well
illustrated for a singly dimensioned array.
Byte Offset 0 1 2 3 4 5 6 7
Characters C[0] C[1] C[2] C[3] C[4] C[5] C[6] C[7]
Halfwords HW[0] HW[1] HW[2] HW[3]
Fullwords FW[0] FW[1]
For each of these examples, suppose that the array begins at address X.
In other words, the address declared for the array is that of its element 0.
The character entries would be: C[0] at X, C[1] at X + 1, C[2] at X + 2, etc.
The halfword entries would be: HW[0] at X, HW[1] at X + 2, etc.
The fullword entries would be: FW[0] at X, FW[1] at X + 4, etc.

Page 365 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

Byte Displacement and Addressing Array Elements: Our Case


I have decided not to write macros that handle the general case, but to concentrate on arrays
that store 4–byte fullwords. The goal is to focus on array handling and not macro writing.
The data structure for such an array will be designed under the following considerations.
1. It must have a descriptor specifying the maximum allowable index.
In this data structure, I store the size and derive the maximum index.
2. It might store a descriptor specifying the minimum allowable index.
For a 0–based array, that index is 0.
3. It should be created by a macro that allows the size to be specified
at assembly time. Once specified, the array size will not change.
In this design, I assume the following:
1. The array is statically allocated; once loaded, its size is set.
2. The array is “zero based”; its first element has index 0. I decide to include this
“base value” in the array declaration, just to show how to do it.
3. The array is self–describing for its maximum size.
Here is an example of the proposed data structure as it would be written
in System 370 Assembler. The array is named “ARRAY”.
ARBASE DC F‘0’ THE FIRST INDEX IS 0
ARSIZE DC F‘100’ SIZE OF THE ARRAY
ARRAY DC 100F‘0’ STORAGE FOR THE ARRAY
I want to generalize this to allow for a macro construction that will specify
both the array name and its size.

The Constructor for a One–Dimensional Array


Here is the macro I used to construct a one–dimensional array
while following the design considerations listed above.
33 MACRO
34 &L1 ARMAKE &NAME,&SIZE
35 &L1 B X&SYSNDX
36 &NAME.B DC F'0' ZERO BASED ARRAY
37 &NAME.S DC F'&SIZE'
38 &NAME.V DC &SIZE.F'0'
39 X&SYSNDX SLA R3,0
40 MEND
Line 34: The macro is named “ARMAKE” for “Array Make”.
It takes two arguments: the array name and array size.
A typical invocation: ARMAKE XX,20 creates an array called XX.
Note the “&L1” on line 34 and repeated on line 35. This allows a macro
definition to be given a label that will persist into the generated code.

Page 366 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

More on the 1–D Constructor


33 MACRO
34 &L1 ARMAKE &NAME,&SIZE
35 &L1 B X&SYSNDX
36 &NAME.B DC F'0' ZERO BASED ARRAY
37 &NAME.S DC F'&SIZE'
38 &NAME.V DC &SIZE.F'0'
39 X&SYSNDX SLA R3,0
40 MEND
Line 35: A macro is used to generate a code sequence. Since I am using it to create a data
structure, I must provide code to jump around the data, so that the data will not be
executed. While it might be possible to place all invocations of this macro
in a program location that will not be executed, I do not assume that.
Line 36: I put in the lower bound on the index just to show a typical declaration.
Line 37 This holds the size of the array.

Label Concatenations in the Constructor


33 MACRO
34 &L1 ARMAKE &NAME,&SIZE
35 &L1 B X&SYSNDX
36 &NAME.B DC F'0' ZERO BASED ARRAY
37 &NAME.S DC F'&SIZE'
38 &NAME.V DC &SIZE.F'0'
39 X&SYSNDX SLA R3,0
40 MEND
Recall that the system variable symbol &SYSNDX in a counter that contains a four digit
number unique to the macro expansion.
Line 39 uses one style of concatenation to produce a unique label. Note that in this more
standard concatenation, the system variable symbol is the postfix of the generated symbol; it
is the second part of a two–part concatenation. Recall that the symbol &SYSNDX counts total
macro expansions. For the third macro expansion; the label would be “X0003”.
Lines 36, 37, and 38 use another type of concatenation, based on the dot. This is due to the
fact that the symbolic parameter &NAME is the prefix of the generated symbol; it is the first
part of a two–part concatenation. If &NAME is XX, then the labels are XXB, XXS, and XXV.
As always, it is desirable to provide a few macro expansions just to show that all of the
process, as described above, really works. What follows is a sequence of two array
constructions using the macro just discussed.

Page 367 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

Sample Expansions of the 1–D Constructor Macro


90 ARMAKE XX,20
000014 47F0 C06A 00070 91+ B X0003
000018 00000000 92+XXB DC F'0'
00001C 00000014 93+XXS DC F'20'
000020 0000000000000000 94+XXV DC 20F'0'
000070 8B30 0000 00000 95+X0003 SLA R3,0
96 ARMAKE YY,40
000074 47F0 C11A 00120 97+ B X0004
000078 00000000 98+YYB DC F'0'
00007C 00000028 99+YYS DC F'40'
000080 0000000000000000 100+YYV DC 40F'0'
000120 8B30 0000 00000 101+X0004 SLA R3,0
Notice the labels generated. Note also the unconditional branch statements in lines 91 and
97; these prevent the accidental execution of data. The target for each of the branch
statements is a do–nothing shift of a register by zero spaces; it might have been written using
another construct had your author known of that construct at the time. Anyway, this works.

Two More Macros for 1–D Arrays


I now define two macros to use the data structure defined above. I call these ARPUT and
ARGET. Each will use R4 as a working register.
Macro ARPUT &NAME,&INDX stores the contents of register R4 into the indexed element
of the named 1–D array. Consider the high–level language statement A2[10] = Y.
This becomes L R4,Y
ARPUT A2,=F‘10’ CHANGE ELEMENT 10
Consider the high–level language statement Y = A3[20].
This becomes ARGET A3,=F‘20’ GET ELEMENT 20
ST R4,Y
NOTE: For some reason, I decided to implement the index as a fullword when I wrote the
code. I just continue the practice, though a halfword index would make more sense.

Design of the Macros


The two macros, ARPUT and ARGET, share much of the same design. Much is centered on
proper handling of the index, passed as a fullword. Here are the essential processing steps.
1. The index value is examined. If it is negative, the macro exits.
2. If the value in the index is not less than the number of elements in the
array, the macro exits. For N elements, valid indices are 0  K < N.
3. Using the SLA instruction, the index value is multiplied by 4
in order to get a byte offset from the base address.
4. ARPUT stores the value in R4 into the indexed address.
ARGET retrieves the value at the indexed address and loads R4.

Page 368 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

The ARPUT Macro


Here is the definition of the macro to store a value into the named array.
44 MACRO
45 &L2 ARPUT &NAME,&INDX
46 &L2 ST R3,S&SYSNDX
47 L R3,&INDX
48 C R3,&NAME.B
49 BL Z&SYSNDX
50 C R3,&NAME.S
51 BNL Z&SYSNDX
52 SLA R3,2
53 ST R4,&NAME.V(R3)
54 B Z&SYSNDX
55 S&SYSNDX DC F'0'
56 Z&SYSNDX L R3,S&SYSNDX
57 MEND
Note the two labels, S&SYSNDX and Z&SYSNDX, generated by concatenation with the
System Variable Symbol &SYSNDX. This allows the macro to use conditional branching.

ARPUT Expanded
Here is an invocation of ARPUT and its expansion.
107 ARPUT XX,=F'10'
000126 5030 C146 0014C 108+ ST R3,S0005
00012A 5830 C46A 00470 109+ L R3,=F'10'
00012E 5930 C012 00018 110+ C R3,XXB
000132 4740 C14A 00150 111+ BL Z0005
000136 5930 C016 0001C 112+ C R3,XXS
00013A 47B0 C14A 00150 113+ BNL Z0005
00013E 8B30 0002 00002 114+ SLA R3,2
000142 5043 C01A 00020 115+ ST R4,XXV(R3)
000146 47F0 C14A 00150 116+ B Z0005
00014A 0000
00014C 00000000 117+S0005 DC F'0'
000150 5830 C146 0014C 118+Z0005 L R3,S0005
Note the labels generated by use of the System Variable Symbol &SYSNDX.
We now examine the actions of the macro ARPUT.
108+ ST R3,S0005
Register R3 will be used to hold the index into the array. This line saves the value so that it
can be restored at the end of the macro. Here we note that the generated line does not have a
label; this reflects the fact that line 107, the macro invocation, is not labeled.
109+ L R3,=F'10'
Register R3 is loaded with the index to be used for the macro. As the index was specified as
a literal in the invocation, this is copied in the macro expansion. Were this a keyword macro,
the literal would have to be specified in a different manner. This is a positional macro, which
does not require special handling of literals.

Page 369 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

ARPUT: Checking the Index Value


We continue our analysis of the macro. At this point, the value of the array index
has been loaded into register R3, the original contents having been saved.
110+ C R3,XXB
111+ BL Z0005
112+ C R3,XXS
113+ BNL Z0005
This code checks that the index value is within permissible bounds.
The requirement is that XXB  Index < XXS.
If this is not met, the macro restores the value of R3 and exits. If the requirement is met, the
index is multiplied by 4 in order to convert it into a byte displacement from element 0.
114+ SLA R3,2
Here is the code to store the value into the array, called XXV.
115+ ST R4,XXV(R3)
116+ B Z0005
117+S0005 DC F'0'
118+Z0005 L R3,S0005
Line 115 This is the actual store command.
Line 116 Note the necessity of branching around the stored value,
so that the data will not be executed as if it were code.
Line 117 The save area for the macro.
Line 118 This restores the original value of R3. The macro can now exit.

The ARGET Macro


Here is the definition of the macro to retrieve a value from the named array.
61 MACRO
62 &L3 ARGET &NAME,&INDX
63 &L3 ST R3,S&SYSNDX
64 L R3,&INDX
65 C R3,&NAME.B
66 BL Z&SYSNDX
67 C R3,&NAME.S
68 BNL Z&SYSNDX
69 SLA R3,2
70 L R4,&NAME.V(R3)
71 B Z&SYSNDX
72 S&SYSNDX DC F'0'
73 Z&SYSNDX L R3,S&SYSNDX
74 MEND

Page 370 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

ARGET Expanded
Here is an invocation of the macro and its expansion.
119 ARGET YY,=F'20'
000154 5030 C172 00178 120+ ST R3,S0006
000158 5830 C46E 00474 121+ L R3,=F'20'
00015C 5930 C072 00078 122+ C R3,YYB
000160 4740 C176 0017C 123+ BL Z0006
000164 5930 C076 0007C 124+ C R3,YYS
000168 47B0 C176 0017C 125+ BNL Z0006
00016C 8B30 0002 00002 126+ SLA R3,2
000170 5843 C07A 00080 127+ L R4,YYV(R3)
000174 47F0 C176 0017C 128+ B Z0006
000178 00000000 129+S0006 DC F'0'
00017C 5830 C172 00178 130+Z0006 L R3,S0006
The only difference between this macro and ARPUT occurs in line 127 of the expansion.
Here the value is loaded into register R4. Note that, in the sequence of macro expansions,
ARPUT was expansion number 5 and ARGET was expansion number six; hence the labels
here are “S0006” and “Z0006” rather than “S0005” and “Z0005”.

Row–Major and Column–Major 2–D Arrays


The mapping of a one–dimensional array to linear address space is simple. How do we map
a two–dimensional array? There are three standard options: The two that we shall consider
are called row–major order and column–major order.
Consider the array declared as INT A[2][3], using 32–bit integers, which occupy four
bytes. In this array the first index can have values 0 or 1 and the second 0, 1, or 2.
Suppose the first element is found at address A. The following table shows
the allocation of these elements to the linear address space.
Address Row Major Column Major
A A[0][0] A[0][0]
A+4 A[0][1] A[1][0]
A+8 A[0][2] A[0][1]
A + 12 A[1][0] A[1][1]
A + 16 A[1][1] A[0][2]
A + 20 A[1][2] A[1][2]
The mechanism for Java arrays is likely to be somewhat different.

Addressing Elements in Arrays of 32–Bit Fullwords


Consider first a singly dimensioned array that holds 4–byte fullwords. The addressing is
simple: Address ( A[K] ) = Address ( A[0] ) + 4K.
Suppose that we have a two dimensional array declared as A[M][N], where each of M and
N has a fixed positive integer value. Again, we assume 0–based arrays and ask for the
address of an element A[K][J], assuming that 0  K < M and 0  J < N.
At this point, I must specify either row–major or column–major ordering.

Page 371 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

As FORTRAN is the only major language to use column–major ordering, I shall assume
row–major. The formula is as follows.
Element offset = KN + J, which leads to a byte offset of 4(KN + J); hence
Address (A[K][J]) = Address (A[0][0]) + 4(KN + J)
Suppose that the array is declared as A[2][3] and that element A[0][0] is at address A.
Address (A[K][J]) = Address (A[0][0]) + 4(K3 + J).
Element A[0][0] is at offset 4(03 + 0) = 0, or address A + 0.
Element A[0][1] is at offset 4(03 + 1) = 4, or address A + 4.
Element A[0][2] is at offset 4(03 + 2) = 8, or address A + 8.
Element A[1][0] is at offset 4(13 + 0) = 12, or address A + 12.
Element A[1][1] is at offset 4(13 + 1) = 16, or address A + 16.
Element A[1][2] is at offset 4(13 + 1) = 20, or address A + 20.

Here is a first cut at what we might want the data structure to look like.
ARRB DC F‘0’ ROW INDEX STARTS AT 0
ARRCNT DC F‘30’ NUMBER OF ROWS
ARCB DC F‘0’ COLUMN INDEX STARTS AT 0
ARCCNT DC F‘20’ NUMBER OF COLUMNS
ARRAY DC 600F‘0’ STORAGE FOR THE ARRAY
NOTE: The number 600 in the declaration of the storage for the array is not independent of
the row and column count. It is the product of the row and column count.
We need a way to replace the number 600 by 3020, indicating that the size of the array is a
computed value. This leads us to the Macro feature called “SET Symbols”.

SET Symbols
The feature called “SET Symbols” allows for computing values in a macro, based on the
values or attributes of the symbolic parameters. There are three basic types of SET symbols.
1. Arithmetic These are 32–bit numeric values, initialized to 0.
2. Binary These are 1–bit values, initialized to 0.
3. Character These are strings of characters, initialized to the null string.
Each of these comes in two varieties: local and global.
The local SET symbols have meaning only within the macro in which they are defined.
In terms used by programming language textbooks, these symbols have scope that is local to
the macro invocation. Declarations in different macro expansions are independent.
The global SET symbols specify values that are to be known in other macro expansions
within the same assembly. In other words, the scope of such a symbol is probably
the entire unit that is assembled independently; usually this is a CSECT.
A proper use of a global SET symbol demands the use of conditional assembly to insure that
the symbol is defined once and only once.

Page 372 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

Local and Global Set Declarations


Here are the instructions used to declare the SET symbols.
Type Local Global
Instruction Example Instruction Example
Arithmetic LCLA LCLA &F1 GBLA GBLA &G1
Binary LCLB LCLB &F2 GBLB GBLB &G2
Character LCLC LCLC &F3 GBLC GBLC &G3
Each of these instructions declares a SET symbol that can have its value assigned by one of
the SET instructions. There are three SET instructions.
SETA SET Arithmetic Use with LCLA or GBLA SET symbols.
SETB SET Binary Use with LCLB or GBLB SET symbols.
SETC SET Character String Use with LCLC or GBLC SET symbols.

The requirements for placement of these instructions depend on the Operating System being
run. The following standards have two advantages:
1. They are the preferred practice for clear programming, and
2. They seem to be accepted by every version of the Operating System.
Here is the sequence of declarations.
1. The macro prototype statement.
2. The global declarations used: GBLA, GBLB, or GBLC
3. The local declarations used:LCLA, LCLB, or LCLC
4. The appropriate SET instructions to give values to the SET symbols
5. The macro body.

Example of the Preferred Sequence


The following silly macro is not even complete. It illustrates the sequence
for declaration, but might be incorrect in some details.
MACRO
&NAME HEDNG &HEAD, &PAGE
GBLC &DATES HOLDS THE DATE
GBLB &DATEP HAS DATES BEEN DEFINED
LCLA &LEN, &MID HERE IS A LOCAL DECLARATION
AIF (&DATEP).N20 IS DATE DEFINED?
&DATES DC C‘&SYSDATE’ SET THE DATE
&DATEP SETB (1) DECLARE IT SET
.N20 ANOP
&LEN SETA L’&HEAD LENGTH OF THE HEADER
&MID SETA (120-&LEN)/2 MID POINT
&NAME Start of macro body.

Page 373 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

A Constructor Macro for the 2–D Array


This macro uses one arithmetic SET symbol to calculate the array size. Note that this
definition does away with the base for the row and column numbers, as I never use them.
30 *
31 * MACRO DEFINITIONS
32 *
33 MACRO
34 &L1 ARMAK2D &NAME,&ROWS,&COLS
35 LCLA &SIZE
36 &SIZE SETA (&ROWS*&COLS)
37 &L1 B X&SYSNDX
38 &NAME.RS DC H'&ROWS'
39 &NAME.CS DC H'&COLS'
40 &NAME.V DC &SIZE.F'0'
41 X&SYSNDX SLA R3,0
42 MEND
Here are two invocations of the macro ARMAK2D and their expansions.
86 ARMAK2D XX,10,20
00004A 47F0 C36E 00374 87+ B X0009
00004E 000A 88+XXRS DC H'10'
000050 0014 89+XXCS DC H'20'
000052 0000
000054 0000000000000000 90+XXV DC 200F'0'
000374 8B30 0000 00000 91+X0009 SLA R3,0

92 ARMAK2D YY,4,8
000378 47F0 C3FA 00400 93+ B X0010
00037C 0004 94+YYRS DC H'4'
00037E 0008 95+YYCS DC H'8'
000380 0000000000000000 96+YYV DC 32F'0'
000400 8B30 0000 00000 97+X0010 SLA R3,0
Please note the hexadecimal addresses at the left of the listing. Line 90 corresponds to
byte address X‘0054’ and line 91 to byte address X‘0374’. The difference is given by
X‘320’, which is decimal 800. Line 90 reserves 200 fullwords, which occupy 800 bytes.
The storage allocation indicated by lines 96 and 97 is similar. Line 96 sets aside thirty–two
fullwords, for an allocation of 128 bytes. X‘400’ – X‘320’ = X‘80’ = 128 in decimal.
The ARGET2D and ARPUT2D macros would be based on the similar macros discussed
above. Each would take three arguments, and have prototypes as follows:
ARGET2D &NAME,&ROW,&COL
ARPUT2D &NAME,&ROW,&COL
Each macro would insure that the row and column numbers were within bounds, and then
calculate the offset into the block of storage set aside for the array. The writing of the actual
code for each of these macros is left as an exercise for the reader.

Page 374 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

Strings vs. Arrays of Characters


While a string may be considered an array of characters, this is not the normal practice.
A string is a sequence of characters with a fixed length. A string is stored in “string space”,
which may be considered to be a large dynamically allocated array that contains all of the
strings used. There are two ways to declare the length of a string.
1. Allot a special “end of string” character, such as the character with
code X‘00’, as done in C and C++.
2. Store an explicit string length code, usually as a single byte that prefixes the string.
A single byte can store an unsigned integer in the range 0 through 255 inclusive.
In this method, the maximum string length is 255 characters.
There are variants on these two methods; some are worth consideration.

Example String
In this example, I used strings of digits that are encoded in EBCDIC. The character
sequence “12345” would be encoded as F1 F2 F3 F4 F5. This is a sequence of five
characters. In either of the above methods, it would require six bytes to be stored.
Here is the string, as would be stored by C++.
Byte number 0 1 2 3 4 5
Contents F1 F2 F3 F4 F5 00
Here is the string, as might be stored by Visual Basic Version 6.
Byte number 0 1 2 3 4 5
Contents 05 F1 F2 F3 F4 F5
Each method has its advantages. The main difficulty with the first approach, as it is
implemented in C and C++, is that the programmer is responsible for the terminating X‘00’.
Failing to place that can lead to strange run–time errors.

Sharing String Space


String variables usually are just pointers into string space.
Consider the following example in the style of Visual Basic.

Here, each of the symbols C1, C2, and C3


references a string of length 4.
C1 references the string “1301”
C2 references the string “1302”
C3 references the string “2108”

Page 375 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler General Arrays and Strings

Using Indirect Pointers with Attributes


Another string storage method uses indirect pointers, as follows.

Here the intermediate node has the


following structure.
1. A reference count
2. The string length
3. A pointer into string space.
There are two references to the first
string, of length 8: “CPSC 2105”.
There are three references to the second
string, also of length 8: “CPSC 2108”.

There are many advantages to this method


of indirect reference, with attributes
stored in the intermediate node. It may be
the method used by Java.

There are a number of advantages associated with this approach to string storage. In general
the use of indirection in pointers, as illustrated above, simplifies system programming. Here
are a few illustrations of some of the standard considerations:
1. If pointer P1 is deallocated, the reference count for the string “CPSC 2105” is
reduced by 1, but the string is not removed.
2. If pointer P2 is deallocated, then the reference count for the string goes to 0,
and the string space can be reclaimed.
Reclamation of dynamic memory (string space in this example) is a tricky business and often
is simply not done. However, the existence of the intermediate pointer facilitates such an
operation. Suppose that the string “CPSC 2105” is removed and the string “CPSC2108” is
moved up by eight positions. There is only one value that needs to be reassigned, and it is
not the addresses associated with pointers P3, P4, or P5. It is the address in the intermediate
node that each of P3, P4, and P5 reference. This intermediate node is easy to locate.

Page 376 Chapter 19 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 20: Subroutine Linkage

We now begin discussion of subroutine linkage, which is the way in which data and control are
passed from a calling program to a called subprogram. We start by considering simple
subroutines without large argument blocks. We should mention that the term “subprogram”
can be used generically to mean “subroutine”, “procedure”, or “function”.
In general, the term function refers to a subprogram that returns a value that can be used as a
part of an assignment statement. Common functions include the trigonometric functions and the
mathematical ones, such as square root. Here is a function call in the style of FORTRAN.
Y = SIN(X)
In general, the term subroutine refers to a subprogram that may or not return a value, but
usually not a value that can be used in an assignment statement typical of function calls. Some
programming languages use the term “procedure” or “function returning void” to replace the
older term “subroutine”. A good example of such a subroutine would be the following.
QUADRATIC (A, B, C, X1, X2)
We might specify that the above subroutine would produce the roots of the quadratic equation
written in the form AX2 + BX + C = 0. The arguments A, B, and C would be passed to
the subroutine, which would then calculate the two roots and return them in X1 and X2.
Subroutines and functions are normally written to facilitate repetitive tasks. Indeed the concept
arose in the late 1940’s and was named the Wheeler Jump” (EDSAC, 1952) after David J.
Wheeler, who developed the concept while working as a graduate student. It is worth noting
that, while many early computing machines were developed as exercises in engineering, the
EDSAC was developed solely to serve as a platform for research in computer programming.
The development of the subroutine was one of many innovations associated with the EDSAC.
Early operating systems began as collection of subroutines to facilitate handling of input and
output devices, mainly line printers. Each programmer had to write his own (yes, they were
almost exclusively male) I/O procedures. As these were tedious to write correctly, programmers
began to share code; these quickly evolved into a shared subroutine library.
When batch programming became common, the computer needed a control program to
automate the processing of a sequence of jobs, read and processed one after another. This
control program was merged with a set of subroutines for Input/Output handling and
routines for standard mathematical functions to create the first operating system.
Subroutines and/or functions can be invoked for side effect only or in order to compute
and return results. Many of the subroutines common in assembler programming are called for
side effect – to manage print position on a page and issue a new page command when necessary.

Page 377 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Subroutine Linkage: Instructions


The language requires two instructions associated with subroutines: one to call the subroutine
and one to affect a return from the subroutine. The instruction used is either BAL (Branch and
Link) or BALR (Branch and Link, Register). Each instruction stores a return address in a
designated register, which is accessed by the BR instruction used to return from the subroutine.
The BAL instruction is a type RX instruction, with opcode X‘45’. This is a four–byte
instruction of the form BAL R1,D2(X2,B2). The object code has the format.
Type Bytes Operands 1 2 3 4
RX 4 R1,D2(X2,B2) X‘45’ R1 X2 B2 D2 D2D2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The first 4–bit field, denoted R1, denotes the register
to hold the return address. The second 4–bit field, denoted X2, contains the optional index
register. The next two bytes contain the base/displacement part of the address.
The format of the instruction is BAL Reg,Address
An example of such an instruction is BAL 8,P10PAGE
The first argument is a register number to be used for subroutine linkage. We explain this more
fully in just a bit. The second argument is the address of the first instruction in the subroutine.
There are other standards for this argument, but this is the one that IBM uses.
The BALR instruction is a type RR instruction, with opcode X‘05’. This is a two–byte
instruction of the form BALR R1,R2.
Type Bytes Operands 1 2
RR 2 R1,R2 X‘05’ R1 R2
The first byte contains the 8–bit instruction code. The second byte contains two 4–bit fields,
each of which encodes a register number. The first register, denoted R1, is used as in the BAL
instruction, to hold the return address. The second register, denoted R2, is used to hold the
address of the called routine. Later, we shall see that general–purpose registers R14 and R15
are favored for use by BALR in this context. The following two code sequences are equivalent.
BAL R8,P10PAGE
L R9,=A(P10PAGE)
BALR R8,R9
Each of the BAL and BALR instructions loads the address of the next instruction into the
register denoted R1, and then executes a branch to the indicated address. As we shall see, the
BAL and BALR facilitate subprogram calling but are not necessary for doing so.
There is an important exception to the BALR instruction. If the second register is 0, the
instruction just loads the first register with the address of the next instruction and then executes
it. No branch is taken, as register 0 cannot hold an address. We shall see code such as:
BALR R12,0 Establish addressability by storing the
USING *,R12 address START in R12 and using it as
START LA R2,SAVEAREA the base address. No branch is taken.

Page 378 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

We now present equivalent code sequences for calling a subroutine with the name NUMOUT.
Technically speaking, it is the subroutine at the address associated with the label NUMOUT, but
we may allow ourselves to speak loosely on occasion.
At present the code sequences written without the use of either BAL or BALR will serve only to
illustrate the functioning of those two instructions. We shall use them in another context later.
We first investigate the standard instruction BAL, shown here in a fragment of code. The BAL
instruction functions by storing the address NUMRET into general–purpose register R8 and then
branching unconditionally to the address NUMOUT.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
BAL R8,NUMOUT PRODUCE THE FORMATTED SUM
NUMRET MVC DATAPR,THENUM AND COPY TO THE PRINT AREA
Here is the equivalent code, written with a B (unconditional branch) instruction.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
LA R8,NUMRET LOAD THE ADDRESS OF THE INSTRUCTION
IMMEDIATELY FOLLOWING THE BRANCH
B NUMOUT BRANCH DIRECTLY TO NUMOUT
NUMRET MVC DATAPR,THENUM AND COPY TO THE PRINT AREA
Here is the equivalent code, written with the more traditional BALR instruction.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
LA R9,NUMOUT GET THE TARGET ADDRESS
BALR R8,R9 PRODUCE THE FORMATTED SUM
NUMRET MVC DATAPR,THENUM AND COPY TO THE PRINT AREA
Here is the equivalent code, written with a BR (unconditional branch) instruction.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
LA R9,NUMOUT GET THE TARGET ADDRESS
LA R8,NUMRET LOAD THE ADDRESS OF THE INSTRUCTION
IMMEDIATELY FOLLOWING THE BRANCH
BR R9 BRANCH DIRECTLY TO NUMOUT
NUMRET MVC DATAPR,THENUM AND COPY TO THE PRINT AREA

Returning from the subroutine


This instruction is used to return from execution of the subroutine. It is an unconditional
jump to an address contained in the register.
The format of the instruction is BR Reg
An example of such an instruction is BR R8
The first thing to note is that the register used in the BR will, under almost all circumstances, be
that used in the BAL or BALR instruction calling the subroutine. A bit of reflection will show
that this mechanism, by itself, will not allow the use of recursive subroutines. Actually, there is
a workaround, but it involves the use of a separate register for each level of subroutine nesting.

Page 379 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

A Standard Example
Here is an example of subroutine invocation in which the called program is in the same CSECT
as the calling code. In such cases, the overhead of subroutine invocation is quite small. In
particular, the subroutine has direct access to all data in the calling program.
OPEN (FILEIN,(INPUT))
OPEN (PRINTER,(OUTPUT))
PUT PRINTER,PRHEAD
GET FILEIN,RECORDIN
*
A10LOOP BAL R8,B10DOIT Call the subroutine
GET FILEIN,RECORDIN This address stored in R8.
B A10LOOP
A90END CLOSE FILEIN
CLOSE PRINTER
EXIT Macro to exit the program
*
B10DOIT MVC DATAPR,RECORDIN
PUT PRINTER,PRINT
BR R8 Return to address stored in
* R8 by the BAL instruction.

Functions and Subroutines


The assembly language programmer will generally speak of “subprograms”. The concepts of
subroutines and functions are generally associated with higher level languages, though they are
really just programming conventions placed on the use of the assembly language.
Given a programming language, such as the IBM Assembler, that provides support for
subprogram linkage, all that is required to support functions is the designation of one or
more general–purpose registers to return values from the function. This designation is simply a
programming standard, followed by all programmers working on a project.
In CDC–7600 Assembly Language, the two designated registers were X6 and X7. The usage
depended on the precision of the function result, which was usually a floating–point value.
Single–precision results Register X7 would return the value.
Double–precision results Register X7 would return the low–order 32 bits
Register X6 would return the high–order 32 bits.
As a result, any subroutine could be called as a function. What one got as a result would be the
value that the subroutine last placed in X7 or both X6 and X7. While this was chancy, it was
predictable. It was the sort of thing programming geeks liked to do.

Control Section: CSECT


A control section (CSECT) is, by definition, a block of coding that can be relocated within the
computer address space without affecting the operating logic of the program. A large system
may comprise a number of control sections; each independently assembled.
Every program contains a large number of references, either to variables or addresses. In a large
system, individual control sections may contain references to variables or addresses not found in
the local assembly unit. These are links to other control sections.

Page 380 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

A link editor edits the links; it searches each CSECT for references that cannot be
resolved locally and attempts to find matches in other CSECTS in the system.
As an example, suppose your HLL program contains the following line of code.
Y = 100*SIN(X)
It is not likely that your program contains a function called SIN, presumably the sine.
The linkage editor will find the appropriate function in the RTS library and resolve the
reference by building the link from your program to the system routine.

Declaring External References


There are two possibilities if your code contains a reference that cannot be found within the
local CSECT:
1. You forgot to declare the reference and have an error in your program.
2. The reference is to a variable or address in another CSECT.
In order to distinguish between the two cases, one must explicitly declare a reference as
external if it is not declared within the local CSECT. In order to understand the processing of
external labels, we must take a detour and review the output of the assembler.
The main job of the assembler is to take an assembler language program in text form and change
it into a sequence of machine language statements that can be prepared for execution by the link
editor. Were this the only function of the assembler, one could not support external symbols.
There are always at least two outputs of the assembler, which may be loosely called “data” and
“metadata”. The data emitted (if one chooses to use this term) form the machine language code.
The metadata emitted describe the machine code and add other information required for
successful link editing. Part of these metadata is a listing of all external symbols, contained in
the ESD (External Symbol Dictionary) [R_18, pages 538 – 544]. It is this metadata that allow
the link editor to build a software system from a set of independently assembled modules.
There are two declarations used with regard to external symbols: EXTRN and ENTRY. For
subprograms, these will be used in pairs. One module will declare a symbol as an ENTRY and
other modules will declare their use of that symbol by declaring it as an EXTRN.
The format of the EXTRN statement is just a list of names, as in the following.
EXTRN NAME1,NAME2,….
This directive informs the assembler that each of the names in the list is referenced within this
assembly unit but is defined externally. This informs the linkage editor that an appropriate
address to be associated with each name must be communicated to the containing program at
link time, otherwise the symbol will become undefined.
The ENTRY instruction identifies symbols defined in the given source module as “external” so
that they can be referenced by another source module. Symbols defined in an ENTRY statement
are called “entry symbols”. The form of the ENTRY instruction is simple.
ENTRY NAME1,NAME2,….

Page 381 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

In essence, this is a list of symbols that the assembly unit will make available for use by other
assembler units. Each entry symbol is entered into the ESD (External Symbol Dictionary) for
access by the linkage editor. Any symbol used as the name entry of a START or CSECT
instruction is automatically considered an entry symbol and is placed into the ESD, even if not
explicitly identified by an ENTRY instruction [R_17, page 182].
An entry symbol may be referenced in the module in which it is declared.
An example of the expected use of this pair of assembler directives is shown below.
* CALLING PROGRAM
EXTRN SUBA SYMBOL IS USED HERE, DEFINED ELSEWHERE
PROG1
L R15,ADRSUBA LOAD R15 WITH ADDRESS
BALR R14,R15 BRANCH TO SUBROUTINE

ADRSUBA DC A(SUBA) ADDRESS OF THIS EXTERNAL SYMBOL


END PROG1

* CALLED PROGRAM
ENTRY SUBA
SUBA Executable code associated with the symbol

BR R14 RETURN TO CALLING PROGRAM


END
In this example, the symbol SUBA would be found twice in the ESD, once as an external symbol
and once as an entry symbol.
Thus, the EXTRN and ENTRY statements cause their respective arguments to be placed in the
ESD. As long as the linkage editor is provided with an entry symbol (defined by ENTRY) to
match each external symbol (defined by EXTRN), all symbolic linkage will be handled properly
by the linkage editor, and the executable system can be built.

The V Data Type


We return to the key issue associated with the use of an external symbol. Such a symbol would
be declared as an entry symbol in the assembler unit in which it is defined. Most of what we
have to deal with is how to declare such a symbol in an assembler unit in which that symbol is
referenced but not defined. We have seen the use of the EXTRN declaration for this purpose.
An alternate way to handle this external declaration is to declare the symbol in the calling unit
as a V-type address constant. This defines the symbol as an externally defined address.
Recall that all “variable” references are really address references that access the contents of the
address. Again, there are two ways to handle this. the first is to use a declaration of the form.
Symbolic_Name DC V(Name)
This might be something like the following.
ADRSUBA DC V(SUBA)
Where the symbol SUBA is declared elsewhere as an entry symbol.

Page 382 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The code to use this construct might appear as follows.


* CALLING PROGRAM

L R15,ADDRSUBA
BALR R14,R15

ADDRSUBA DC V(SUBA)
END
But this seems to be done rarely, if at all. Invocation of a subroutine found in a separate CSECT
is achieved by use of the standard system macro, CALL. We give an example, and expand it.
Note that the address of the called routine is presented as a literal of the proper type. The literal
=V(SUBA) is called an external address constant. At assembly time, the constant is assigned
the value X‘0000’, which is changed by the linkage editor.
CALL SUBA
+ L 15,=V(SUBA) LOAD ADDRESS OF EXTERNAL REFERENCE
+ BALR 14,15 STORE RETURN ADDRESS INTO R14

The Save Areas


One key design feature when developing subroutines and functions is the minimization
of side effects. One particular requirement concerns the general purpose registers. This design
requirement is that after the return from a called subprogram, the contents of the general
purpose registers be exactly the same as before the call.
The only exception to this rule is the use of a general purpose register for the return of a
function value. In this case, the design of each of the calling routine and the called routine
explicitly allows for the value of that one specified register to be changed.
Save and Restore
The strategy used is that each routine (including the main program) will save the contents of all
but one of the general purpose registers on entry and restore those on exit. Recall that the main
program is handled by the operating system as if it were a subprogram. This strategy has
evolved from an earlier strategy in which a developer would save the contents of only those
registers to be used explicitly in the subprogram. It was found to be better practice to have
every subprogram start with a uniform set of assumptions rather than explicitly monitoring
every register used by the subprogram.
In the statically allocated, non–recursive world of IBM assembler programs, each routine
will declare an 18–fullword “save area”, used to save important data. There are three important
system macros one should use when invoking a standard external subprogram. These are
CALL, SAVE, and RETURN. These are described in IBM z/VSE System Macros Reference
[R_23, pages 26, 338, and 339], Peter Abel’s book [R_02, pages 346 – 353], and elsewhere.

The Save Area


Each assembler module should have a save area, which may be declared as follows.
The important feature is that eighteen full words (72 bytes) are allocated.
SAVEA DS 18F

Page 383 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The structure of the save area is shown in the table below [R_02, page 346].
Word Displacement Contents of the Word
1 0 This is no longer used.
It was once used by PL/1 programs.
2 4 The address of the save area of the calling program.
Saved here to facilitate error processing.
3 8 The address of the save area of any subprogram called.
The subprogram called will update this value.
4 12 The contents of general–purpose register 14,
which contains the return address to the calling program.
5 16 The contents of general–purpose register 15, which
contains the address of the entry point in this program.
6 20 The contents of general–purpose register 0.
7 – 18 24 These twelve fullwords contain the contents of
general–purpose registers 1 through 12.

The Standard Sequence


Recalling that the user program is treated by the z/OS as a subprogram, we first sketch the
sequence of events associated with a standard subprogram invocation. It is usually advisable to
adhere to these standards in writing programs, as they avoid a number of bothersome problems.
1. Establish a save area, as defined above.
2. Before issuing the CALL macro, first load the address of this save area into R13.
This is a standard use of that particular register.
3. Call the subprogram.
4. The called program should first invoke the SAVE macro to save the calling
program’s register contents into the area designated by R13.
5. On return to the calling program, the called program invokes the RETURN macro.
Here is a sketch of the code necessary. Here PROGA calls PROGB. Note the specific registers
(12, 13, and 14; or R12, R13, and R14 if you wish). These should be used as is.
* CALLING PROGRAM
PROGA
LA 13,SAVEAREA
CALL PROGB
SAVEAREA DS 18F
* CALLED PROGRAM
PROGB SAVE (14,12)
Miscellaneous code
RETURN (14,12)
In other words, our user programs should have the same structure as PROGB just above.

Page 384 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The CALL Macro


This macro links a calling program to a called program. Presumably, the z/OS uses this macro,
or a close variant of it, to invoke the user program. Again, we give the caution that this macro
should really be viewed as the second statement of a pair, such as the following.
LA 13,SAVEAREA
CALL PROGB
The source code format of the CALL macro, as we shall use it, is as follows [R_23, page 26].
[LABEL] CALL ENTRYPOINT [,(ADDRESS LIST)]
As is the case with almost all assembler language statements, this statement may have a label.
The square brackets around the label indicate that it is optional. Read the above as follows: a
valid call macro starts with an optional label, followed by the keyword CALL, followed by an
entry point, followed by an optional address list. The comma is used only if the list is used.
CALL loads the address of the next sequential instruction into general–purpose register 14 to
facilitate the return and then branches to the called program, using either BAL or BALR.
The operand ENTRYPOINT is the name of the first executable instruction of the called program.
It may be the case that the subprogram has many entry points (though this is dubious coding
practice). This is just where one wants to begin execution.
The CALL macro passes control to a control section at the specified entry point as follows: If a
control section is not part of the object module that applies to the CALL macro, the linkage
editor attempts to resolve this external reference by including the object module which contains
the control section in which the entry point exists. Control is passed to that entry point.
The linkage relationship established by the CALL macro is the same as that created by a BAL
instruction; that is, the issuing program expects control to be returned.
The operand ENTRYPOINT may be represented as (15), indicating that general–purpose
register 15 holds the address of the entry point in the called routine. The following two
sequences appear to have the same effect. As we shall see later, the standard calls for R15 to
hold the address of the entry point in the called routine.
SEQ1 CALL PROGA
SEQ2 L 15,=V(PROGA)
CALL (15)
The entry ADDRESS LIST allows for passing one or more addresses, separated by commas, to
the called program. To create the parameter list, the each address is expanded to a fullword on a
fullword boundary in the specified order. If this is used, register R1 is loaded with the address
of this parameter list; otherwise it is not altered. We shall discuss argument passing soon.
There are other options for the CALL macro as described in the manual IBM z/VSE System
Macros Reference. These options appear to apply to variants of the assembler language that
are more advanced than the System/370 assembler we are studying, and will not be discussed.

Page 385 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Here is an example of the use of the CALL macro with the address list.
CALLIT CALL PROGB, (AP1,AP2)

AP1 A(PARAM1)
AP2 A(PARAM2)

PARAM1 DC H‘2’
PARAM2 DC H‘4’
The first address in the list of addresses has label AP1. It is this address that the macro
will place into general–purpose register 1 before executing the BAL or BALR. What follows is a
listing of a program written to use the CALL macro, along with the macro expansion.
85 CALLIT CALL PROGB,(AP1,AP2)
000060 87+ CNOP 0,4
000060 47F0 C062 00068 88+CALLIT B *+8
000064 00000000 89+IHB0011B DC V(PROGB)
000068 4110 C06A 00070 92+ LA 1,IHB0013
00006C 47F0 C072 00078 93+ B IHB0013A
000070 94+IHB0013 DS 0F
000070 00000178 95+ DC A(AP1)
000074 0000017C 96+ DC A(AP2)
00078 97+IHB0013A EQU *
000078 58F0 C05E 00064 98+ L 15,IHB0011B
00007C 05EF 99+ BALR 14,15
100 NEXTONE GET FILEIN,RECORDIN

221 *
000178 00000180 222 AP1 DC A(P1)
00017C 00000182 223 AP2 DC A(P2)
000180 0014 224 P1 DC H'20'
000182 0028 225 P2 DC H'40'
Line 85 contains the actual use of the macro. There are two address arguments.
Line 87 contains a conditional no–operation instruction, CNOP, which causes the following
code to be aligned on the proper address boundaries.
Line 88 begins the actual expansion of the macro. Note that it branches around a declaration of
the external address reference to be used as the entry point of the called subprogram.
Line 92 loads general–purpose register 1 with the address IHB0013, discussed below.
Line 93 branches around the lines associated with the address IHB0013, so that those data
will not be executed. The label IHB0013A uses an equate to set it to the address for line 98.
The DS 0F on line 94 forces what follows to be aligned on fullword boundaries. What follows
are two fullwords, each containing the address of an address parameter for the call.
Line 98 loads the external address, presumably now resolved by the link editor, into register
R15 in preparation for the BALR on line 99.
Lines 222 and 223 declare the address constants, which refer to the constants defined in the next
two lines. Note that the contents of AP1 are X‘00000180’, the address of P1.

Page 386 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The Return Macro


The return macro restores the contents of the registers that have been saved and returns to the
calling program. To conform with the standard, it should be written as RETURN (14, 12).
Here is an actual expansion of the RETURN macro as used in a test program.
123 RETURN (14,12)
0000AA 98EC D00C 0000C 125+ LM 14,12,12(13)
0000AE 07FE 126+ BR 14

The SAVE Macro


Often the first executable instruction of a program or subprogram will be SAVE (14,12).
Here is the actual code from the second lab assignment, in which I chose to expand macros so
that I could see the code generated in the macro expansions.
31 LAB02 CSECT
32 SAVE (14,12) SAVE CALLER’S REGISTERS
34+ DS 0H
35+ STM 14,12,12(13)
36 BALR R12,0 ESTABLISH ADDRESSABILITY
37 USING *,R12
38 LA R2,SAVEAREA LINK THE SAVE AREAS
39 ST R2,8(,R13)
40 ST R13,SAVEAREA+4
41 LR R13,R2
On entry, general–purpose register 13 contains the address of the supervisor’s save area. The
SAVE macro is written under this assumption. The user program always executes as a
subprogram of the supervisor (Operating System).
Recall that the address designated 12(13) corresponds to an offset of 12 from the value stored
in register 13. If R13 contains address S0, then 12(13) corresponds to address (S0 + 12).
As a reminder, we note that the line “USING *,R12” is a directive and does not translate into
any generated machine code. From the viewpoint of the machine language generated the code
reads as follows. Line 37 has been omitted from this list as it does not generate code.
35+ STM 14,12,12(13)
36 BALR R12,0 ESTABLISH ADDRESSABILITY
38 LA R2,SAVEAREA LINK THE SAVE AREAS
In particular, the machine language instruction following that for the BALR is the machine
language instruction for the LA. It is that address that is loaded into register R12. Again, since
the second register field in the BALR holds a 0, no branch is actually taken.
We now give an illustration of how these save areas are used to chain together various programs
into what is often referred to as a “call stack”. This is especially useful when one wants to
unwind the mess caused by an abnormal program termination.
In this illustration, assume the following.
1. The save area of the supervisor begins at address S0.
2. The user main program is PA, with save area starting at address SA.
3. The user program calls program PB, which has save area starting at SB.

Page 387 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The User Program Saves the Registers


This is the case on entry to main program PA. Register 13 points to the start of
the save area for the supervisor and 12(13) points to the start of its register save area.

The instruction STM 14,12,12(13) is then executed. The contents of the supervisor’s
save area is now as follows.

The User Program Links the Save Areas


The next step is to establish addressability in the user program, so that addresses such as
that of the save area can be used. The user program then forward links the supervisor’s
save area. Before that happens, we just have two save areas.

Here is the code to do the forward link. The address of the start of the user save area
is placed in the fullword at offset 8 from the start of the supervisor’s save area.
38 LA R2,SA LINK THE SAVE AREAS
39 ST R2,8(,R13) OFFSET 8 FROM S0

The program now executes the following code to establish the backward link from the user
program to the supervisor’s save area.
40 ST R13,SA+4
At this point, register R13 contains the address of the supervisor’s save area. The result of this
instruction is the completion of the two–way links.

Page 388 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Now R2 holds the address of the user save area. Note that this could have been any of the
registers in the range 2 – 12, excepting R12 which was used for addressability.
The next instruction established R13 as once again holding the address of the save area of the
current program.
41 LR R13,R2

The Chain Continues


Suppose the user program calls a subprogram. The chain is continued.

The Return Process


The return process restores the general–purpose registers to their values
before the call of the subroutine.
R13 is first restored to point to the save area for the calling program.
Then the other general–purpose registers are restored.
Here is the situation on return from Subprogram PB.

The code is as follows.


L R13,SB+4 GET ADDRESS OF CALLER’S SAVE AREA
LM R14,R12,12(R13) RELOAD THE REGISTERS. R14 IS
LOADED WITH THE RETURN ADDRESS
BR R14 RETURN TO THE CALLER

Page 389 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Entry/Exit Considerations
Consider how a program or subprogram starts and exits.
The start code is something like the following.
SUB02 CSECT
SAVE (14,12) SAVE CALLER’S REGISTERS
+ DS 0H
+ STM 14,12,12(13)
BALR R12,0 LOAD R12 WITH THE ADDRESS
USING *,R12 OF THE NEXT INSTRUCTION
Here is the standard exit code. Assume the save area is at address SB.
L R13,SB+4 ADDRESS OF CALLERS SA
LM R14,R12,12(R13) CALLER’S REGISTER VALUES
BR R14 RETURN
Note that the next to last instruction in the second section causes addressability in the
called program to be lost. This is due to the fact that the value that had been loaded into
R12 to serve as the base register for this code’s addressability has been overwritten with
the value that had been used in the calling program and will be used again.

Setting the Return Code


The IBM linkage standard calls for general–purpose register R15 to be loaded with a return code
indicating success or failure. A value of 0 usually denotes a success.
It is common to set the return code just before the terminating BR instruction, just
after the restoration of the calling routine’s registers.
The following is typical code. Here, I am setting a return code of 3.
L R13,SB+4 ADDRESS OF CALLERS SA
LM R14,R12,12(R13) CALLER’S REGISTER VALUES
LA R15,3 USE THE LOAD ADDRESS INSTRUCTION
TO LOAD THE CONSTANT VALUE 3.
BR R14 RETURN
This uses the LA (Load Address) instruction in its common sense as a way to load a
non–negative constant less than 4,096 into a general–purpose register. Note that an instruction
such as L R15,=H‘3’ would require access to an element in the subprogram’s literal pool.
However, the value of the subprogram’s base register has been overwritten, and addressability
has been lost. Due to this, the subprogram’s literal pool can no longer be accessed.
A normal return is usually indicated by a return code of 0, which is placed in R15. This may be
done in at least two ways: either LA R15,0 or SR R15,R15.
We now move on to a discussion of methods for passing argument values from a calling
program to the called subprogram.

Page 390 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Call By Reference vs. Call By Value


Two of the more common methods for passing data to and from a subprogram are
call by reference and call by value. Note that there are several other common methods.
In call by value, the calling program delivers the actual values of the data to the subroutine.
This subroutine can alter the values of those data, but the altered values will not be returned to
the calling routine. Some languages call these “in parameters”.
In call by reference, the calling program delivers the addresses of the data items to the
subroutine. The values of these data can be changed by the called subroutine and those values
propagated back to the calling program. These may be called “in–out parameters”.
Note that the return address for the subroutine can also be changed. This is an old trick used by
malicious hackers in order to gain control of a computer. We may discuss this trick later.
The next question we must ask is how these values and/or addresses will be passed to the
subroutine. We shall see that the System/370 assembler supports both mechanisms.

Mechanisms for Passing


By this title, we mean either the passing of values or the passing of addresses. Basically, there
are three mechanisms for passing values to a subroutine. Each of these has been used.
1. Pass the values in registers specifically designated for the purpose.
2. Pass the values on the stack.
3. Pass the values in an area of memory and pass a pointer to that area
by one of the other methods.
Remember that a pointer is really just an address in memory; it is an unsigned integer.
In some high–level languages, a pointer may be manipulated as if it were an unsigned
integer (which it is). In others, standard arithmetic cannot be applied to pointers.
Languages, such as Java and C#, provide for pointers but do not allow direct arithmetic
manipulation of these addresses. For that reason, the term “pointer” is not used.

Subroutines, Separate Assemblies and Linkage


The first example of a subroutine is the B10DOIT routine we have seen before.
B10DOIT MVC DATAPR,RECORDIN
PUT PRINTER,PRINT
BR 8
While this is a valid subroutine, we note three facts of importance.
1. It is in the same assembly as the calling module.
2. It is in the same CSECT as the calling module.
3. The symbols (DATAPR, RECORDIN, PRINTER, and PRINT) used by the
subroutine are in the scope of the calling module, but are visible to the subroutine.
The point of discussing subroutine B10DOIT is simple. There is an advantage to coding
multiple subroutines within a given CSECT. These usually simplify the design of the code.
However, they present very few issues for the passing of arguments or control.

Page 391 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

In general, we would like to link modules that are not assembled at the same time. It might
even be necessary to link assembled code with code written in a higher–level language and
compiled. Thus COBOL programs might call assembler language routines.
We have already encountered the external declaration, which is used to declare that:
1. A label corresponds to an address declared in another module, and
2. The linking loader will have to resolve that address by loading the called module,
assigning an address to this label, and updating that reference in the calling code.

Register Usage in Subprogram Calling


The following is the Standard Linkage Convention for the use of general–purpose registers.
This convention is to be used by any subprogram that is to be run under z/OS. [R_19, page 146].
Register Use
1 Address of the parameter list.
13 Address of calling routine’s save area. This is an area set
aside to save the register values from the calling program.
14 Address in the calling routine to which
control is to be returned.
15 The address of the entry point
in the called subprogram.
There is no direct standard for the other twelve general–purpose registers (0 and 2 – 12).
We have already seen an example of the use of registers 14 and 15. Consider the following
code, which is written in the standard format preferred for S/370 assembler programs.
L 15,=V(PROGB) LOAD ADDRESS OF EXTERNAL REFERENCE
BALR 14,15 STORE RETURN ADDRESS INTO R14
IBM has established a set of conventions for use by all modules when calling separately
assembled modules. These insure that each module can work with any other module.

Implementation of Argument Passing Mechanisms


We shall now discuss in more detail the list of options presented for the passing of arguments to
a subprogram. As of now, we shall assume that the subprogram is assembled separately from
the main program. Assume that PROGA calls PROGB, or an entry within PROGB. In terms of
the theory of programming languages, we assume that we have two different scopes; labels
defined within PROGA have no meaning within PROGB, and vice–versa. The linkage is
provided by the linkage editor, using external symbols and entry symbols. The reason for this
focus is that the simpler situation presents no difficulties worth further discussion.
One simple way to pass an argument to a subprogram would use a register, which might contain
either the value of the argument or the address of the argument. This might work for small
systems designed and implemented by a single programmer, but the design does not scale well
to large systems. For that reason, we shall mention this method only to be complete.

Page 392 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Another mechanism for passing arguments might be called the argument block method. In
this method, one register is chosen to hold the address of a block used to contain the arguments,
either values or addresses. One advantage of this method is that it does not limit the number of
arguments to the number of registers available. We shall discuss the implementation of this idea
as developed by IBM for the systems programs that ran on the System/360.
This method calls for general–purpose register R1 to hold the address of a parameter block. In
this parameter block we find a list of the addresses of the parameters, not the values. This is the
mechanism that was discussed just above in the example of the CALL macro. Consider the
following code fragment, taken from Yarmish & Yarmish [R_18, pages 544 & 545].
* CALLING ROUTINE
S1 LA R1,PARAMLST Load address of the parameter list
S2 L R15,ADDSUB Entry point to subroutine
BALR R14,R15 Call the subroutine

ADDSUB DC V(SUBA) External reference


*
PARAMLST DC A(PARAM1) Address of first parameter
DC A(PARAM2) Address of second parameter
DC A(ANSWER) Address of third parameter
*
PARAM1 DC F‘22’
PARAM2 DC F‘33’
ANSWER DS F
* CALLED ROUTINE
ENTRY SUBA Declare as an entry point
SUBA L R2,0(1) Load R2 from the address at offset
0 from the address in R1.
S3 L R3,4(1) Load R3 from the address at offset
4 from the address in R1.
S4 L R7,0(2) Load R7 from the address in R2
S5 A R7,0(3) Add value at address in R3
S6 L R8,8(1) Get the third address passed
S7 ST R7,0(8) Store the result into that address
BR R14 Return
This code requires some comments. The line labeled SUBA has register R2 loaded from an
address that is offset 0 from the address stored in general–purpose register 1. The value there is
A(PARAM1), the address of the first parameter. The line labeled S3 loads R3 from an address
that is offset 4 from the address in R1. The value here is A(PARAM2).
Line S4 loads R7 from the address that is offset 0 from the value in R2. The value in R2 is the
address of PARAM1, so R7 is now loaded with the value of PARAM1, which is 22. Line S5 adds
to R7 the value that is at offset 0 from the address in R3. The address is that of PARAM2, so the
value of PARAM2 is added to R7, which now holds 55. Line S6 loads R8 from the value at
offset 8 from the address in R1; this is A(ANSWER). Line S7 stores the contents of R7 into the
address held in R8, thus returning the answer to the calling program.

Page 393 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

The Dummy Section (DSECT)


We now consider a logical extension to the argument block method of passing values and/or
addresses to a separately assembled subprogram. In more modern terms, this might be
considered as passing a record to a subprogram by specifying the structure of the record and the
address of the first member of the record. Loosely speaking, a DSECT is the specification of
the structure of a record without the allocation of memory for that structure.
Recall that parameters are passed by reference when it is desired to allow the called program to
change the values as stored in the calling program. Call by reference is also the preferred
method for passing reference to a data structure so large that making a copy for pass–by–value
would be inefficient. In other words, the programmer may elect to use call–by–reference even
in those cases in which the subprogram does not change any of the data passed to it.
For data represented by a large number of labels, it is convenient to use a dummy section. This
process is best considered as passing a record structure to the called subprogram.
1. All the data items to be passed to the called program are grouped in a
contiguous data block.
2. The address of this data block is passed to the called subprogram.
3. The called subprogram accesses items in the data block by offset from
the address passed to it.
The DSECT is used in the called subprogram as a template for the assembler to generate the
proper address offsets to be used in accessing the original data. Sharon Tuggle [R_09, pages
369 & 370] gives a very good introduction to the idea of a DSECT, which I quote here.
“There are times in programming when the programmer needs to refer to whole
blocks of data residing outside his own program (i.e., data passed between
subroutines). Because of the quantity of data being referenced, it is impractical
to use address constants and EXTRN statements to refer to each piece or pass
each data item as an individual parameter. Instead, all the data items are
collected in contiguous areas that make up a block of data; and one address, the
address of the beginning of the block, is passed as a parameter between
subroutines. This one address can be loaded into a register and that register used
as the base register for a dummy control section (a DSECT).”
“A DSECT is a convenient means that the programmer can use to describe the
layout of an area of storage without actually reserving the storage. It is assumed
that the storage is reserved elsewhere (most likely in another subroutine).”
The format of a DSECT instruction is as follows [R_17, page 177].
[LABEL] DSECT
Following the optional label is the single statement declaring the start of a dummy section. The
most common usages of the dummy section all require an ordinary symbol to label the DSECT.
According to IBM [R_17, page 177] “The location counter for a dummy section is always set to
an initial value of 0.” In other words, items within the DSECT are given addresses relative to
the start of the DSECT.

Page 394 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

Here are some notes on the DSECT, taken from [R_17, pages 177 and 178].
1. The assembler language statements that appear in a dummy section
are not assembled into object code.
2. When establishing the addressability of a dummy section, the symbol in
the name field of the DSECT instruction, or any symbol defined in the
dummy section, can be specified in a USING instruction.
The standard way to effect references to the storage area defined by a dummy section is to
provide a USING statement that specifies both a general–purpose register that the assembler can
use as a base register for the dummy section, and a value from the dummy section that the
assembler may assume the register contains.

Example of Linkage Using a DSECT


Suppose that I want to pass customer data from PROGA (the calling program, in which the data
are defined) to subprogram PROGB, in which they are used.
Here is a sketch of code and declarations in the calling program, which is PROGA.
This uses the calling convention that R1 holds the address of the parameters.
PROGA CSECT
* SECTION TO CALL PROGB
LA R1,=A(CREC) LOAD RECORD ADDRESS
L R15,=V(PROGB) LOAD ADDRESS OF PROGB
BALR R14,R15 CALL THE SUBPROGRAM
Next Instruction
*
CREC DS 0CL96 THE RECORD WITH ITS SUBFIELDS
CNAME DS CL30 OFFSET = 0
CADDR1 DS CL20 OFFSET = 30
CADDR2 DS CL20 OFFSET = 50
CCITY DS CL15 OFFSET = 70
CSTATE DS CL2 OFFSET = 85
CZIP DS CL9 OFFSET = 87

The Dummy Section Itself


The dummy section will be declared in the called subprogram using a DSECT.
Here is the proper declaration for our case.
CRECB DSECT
CNAME DS CL30 OFFSET = 0
CADDR1 DS CL20 OFFSET = 30
CADDR2 DS CL20 OFFSET = 50
CCITY DS CL15 OFFSET = 70
CSTATE DS CL2 OFFSET = 85
CZIP DS CL9 OFFSET = 87
The DSECT is a convenient means that can be used to describe the layout of a
storage area without actually reserving storage.

Page 395 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language Standard Subroutine Linkage

In use of a DSECT, it is assumed that the storage has been reserved elsewhere and
that the base address of that storage will be passed as a parameter.
The DSECT is just a mechanism to instruct the assembler on generation of offsets
from the base address into this shared data area.

Use of the DSECT in PROGB


Here is a sketch of the use of the DSECT in PROGB, assembled independently.
Recall that general–purpose register R1 contains the address of the customer record.
PROGB CSECT
BALR R12,0 ESTABLISH ADDRESSABILITY
USING *,R12
LR R10,R1 GET THE PARAMETER ADDRESS
USING CRECB,R10 ESTABLISH ADDRESSABILITY FOR
THE DUMMY SECTION
MVC OUTC,CCITY THIS ACCESSES THE DATA IN
THE CALLING PROGRAM
OUTC DS CL15 DATA BELONGING TO PROGB

CRECB DSECT
CNAME DS CL30 OFFSET = 0
CADDR1 DS CL20 OFFSET = 30
CADDR2 DS CL20 OFFSET = 50
CCITY DS CL15 OFFSET = 70
CSTATE DS CL2 OFFSET = 85
CZIP DS CL9 OFFSET = 87

A Detailed Look at Addresses


Here we recall two facts relative to the one instruction MVC OUTC,CCITY.
The label OUTC belongs to the called subprogram PROGB. It is accessed using base register
R12, which is the basis for addressability in this subprogram. The label CCITY belongs to the
dummy section. It is accessed using the base register explicitly associated with the DSECT;
here it is R10. The LR R10,R1 instruction copies the address of the parameter block in the
calling program into R10 for use in the subprogram PROGB.
Suppose that OUTC has address X‘100’ (decimal 256) within PROGB, it is at that
displacement from the value contained in the base register R12. From the DSECT it is clear that
the label CCITY is at displacement 70 (X‘46’) from the beginning of the data record. The
field has length 15, or X‘0F’
The instruction MVC OUTC,CCITY could have been written with explicit base register
references as MVC 256(15,R12),70(R10), with object code D2 0E C1 00 A0 46
D2 is the operation code for MVC. 0E encodes decimal 14, one less than the length.
C1 00 represents an address at displacement X‘100’ from base register 12.
A0 46 represents an address at displacement X‘46’ from base register 10.

Page 396 Chapter 20 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 21: Input/Output Macros

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.
Header MACRO
Prototype DIVID &QUOT,&DIVIDEND,&DIVISOR
Model Statements ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
Trailer MEND
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:
Header MACRO
Prototype DIVID2 &QUOT=,&DIVIDEND=,&DIVISOR=
Model Statements ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
Trailer MEND
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

Page 397 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

It is possible to use labels defined in the body of the program as default values.
MACRO
DIVID2 &QUOT=MPG,&DIVIDEND=,&DIVISOR=
ZAP &QOUT,&DIVIDEND
DP &QUOT,&DIVISOR
MEND
With this definition, the two invocations are exactly equivalent.
DIVID MPG,MILES,GALS
DIVID2 &DIVIDEND=MILES,&DIVISOR=GALS
The invocation of the macro DIVID2 will expand as follows:
ZAP MPG,MILES
DP MPG,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:
DCB Data Control Block, used to define files.
OPEN This makes a file available to a program, for either input or output.
CLOSE This terminates access to a file in an orderly way. For a buffered output
approach, this ensures that all data have been output properly.
GET This makes a record available for processing.
PUT This writes a record to an output file. In a buffered output, this may
write 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 1 Logical IOCS macros, supervisor macros, and other IBM
macros use these registers to pass addresses.
13 Used 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 15 Logical IOCS uses these registers for linkage. A GET or PUT
will 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.

Page 398 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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.

Page 399 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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, and
physical 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.

Page 400 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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.
FILEIN DCB 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.
FILEIN DCB 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:
DDNAME=FILEIN,DSORG=PS,DEVD=DA,RECFM=FB,LRECL=80,EODAD=A90END,MACRF=(GM)

The File Definition Macro


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:
Filename DCB 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)

Page 401 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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:
Filename DCB 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:
PS Physical 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:
F Fixed length and unblocked
FB Fixed 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.

Page 402 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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.
FILEIN DCB Define the input file here
PRINTER DCB Define the output file here
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.
* OPTION 1
OPEN (FILEIN,(INPUT))
*
* OPTION 2
LA R2,FILEIN
OPEN ((2),(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.

Page 403 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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.
A90END CLOSE 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.
A90END CLOSE (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.
A90END CLOSE (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 PRINTER indicates 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.

Page 404 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

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] GET Filename,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.
GET FILEIN,RECDIN
FILEIN DCB Define the input file
RECDIN DS CL80 This 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,FILEIN Address of the file definition
LA 0,RECDIN Address of the work area
READIT GET (1),(0) Read a record into RECDIN. Note the
standard use of the parentheses.
The PUT Macro
This macro writes a record from the output work area. There are two general formats.
[label] PUT Filename,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.
PUT FILEIN,RECDIN
PRINTER DCB Define the input file
DATOUT DS CL133 This 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
LA 1,PRINTER Address of the file definition
LA 0,DATOUT Address of the work area
PUT (1),(0) Copy data from work area to printer.

Page 405 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

Expansion of the I/O Macros


47 OPEN (PRINTER,(OUTPUT))
000014 48+ CNOP 0,4
000014 4510 C016 0001C 49+ BAL 1,*+8
000018 8F 50+ DC AL1(143)
000019 000098 51+ DC AL3(PRINTER)
00001C 0A13 52+ SVC 19
53 OPEN (FILEIN,(INPUT))
00001E 0700 54+ CNOP 0,4
000020 4510 C022 00028 55+ BAL 1,*+8
000024 80 56+ DC AL1(128)
000025 0000F8 57+ DC AL3(FILEIN)
000028 0A13 58+ SVC 19

59 PUT PRINTER,PRHEAD
00002A 4110 C092 00098 61+ LA 1,PRINTER
00002E 4100 C1A2 001A8 62+ LA 0,PRHEAD
000032 1FFF 63+ SLR 15,15
000034 BFF7 1031 00031 64+ ICM 15,7,49(1)
000038 05EF 65+ BALR 14,15
66 GET FILEIN,RECORDIN
00003A 4110 C0F2 000F8 68+ LA 1,FILEIN
00003E 4100 C152 00158 69+ LA 0,RECORDIN
000042 1FFF 70+ SLR 15,15
000044 BFF7 1031 00031 71+ ICM 15,7,49(1)
000048 05EF 72+ BALR 14,15

95 A90END CLOSE (FILEIN)


000074 96+ CNOP 0,4
000074 4510 C076 0007C 97+A90END BAL 1,*+8
000078 80 98+ DC AL1(128)
000079 0000F8 99+ DC AL3(FILEIN)
00007C 0A14 100+ SVC 20
101 CLOSE (PRINTER)
00007E 0700 102+ CNOP 0,4
000080 4510 C082 00088 103+ BAL 1,*+8
000084 80 104+ DC AL1(128)
000085 000098 105+ DC AL3(PRINTER)
000088 0A14 106+ SVC 20

Page 406 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

116 PRINTER DCB DSORG=PS,


DDNAME=PRINTER,
RECFM=FM,
LRECL=133
119+* DATA CONTROL BLOCK
120+*
000098 121+PRINTER DC 0F'0' ORIGIN ON
122+* DIRECT ACCESS DE
000098 0000000000000000 123+ DC BL16'0' FDAD, DVTB
0000A8 00000000 124+ DC A(0) KEYLEN, DE
125+* COMMON ACCESS ME
0000AC 00 126+ DC AL1(0) BUFNO, NUM
0000AD 000001 127+ DC AL3(1) BUFCB, BUF
0000B0 0000 128+ DC AL2(0) BUFL, BUFF
0000B2 4000 129+ DC BL2'0100000000000000' DSO
0000B4 00000001 130+ DC A(1) IOBAD FOR
131+* FOUNDATION EXTEN
0000B8 00 132+ DC BL1'00000000' BFTEK, BFA
0000B9 000001 133+ DC AL3(1) EODAD (END
0000BC 82 134+ DC BL1'10000010' RECFM (REC
0000BD 000000 135+ DC AL3(0) EXLST (EXI
136+* FOUNDATION BLOCK
0000C0 D7D9C9D5E3C5D940 137+ DC CL8'PRINTER' DDNAME
0000C8 02 138+ DC BL1'00000010' OFLGS (OPE
0000C9 00 139+ DC BL1'00000000' IFLGS (IOS
0000CA 0050 140+ DC BL2'0000000001010000' MAC
141+* BSAM-BPAM-QSAM I
0000CC 00 142+ DC BL1'00000000' OPTCD, OPT
0000CD 000001 143+ DC AL3(1) CHECK OR I
0000D0 00000001 144+ DC A(1) SYNAD, SYN
0000D4 0000 145+ DC H'0' INTERNAL A
0000D6 0000 146+ DC AL2(0) BLKSIZE, B
0000D8 00000000 147+ DC F'0' INTERNAL A
0000DC 00000001 148+ DC A(1) INTERNAL A
149+* QSAM INTERF
0000E0 00000001 150+ DC A(1) EOBAD
0000E4 00000001 151+ DC A(1) RECAD
0000E8 0000 152+ DC H'0' QSWS (FLAG
0000EA 0085 153+ DC AL2(133) LRECL
0000EC 00 154+ DC BL1'00000000' EROPT, ERR
0000ED 000001 155+ DC AL3(1) CNTRL
0000F0 00000000 156+ DC H'0,0' RESERVED A
0000F4 00000001 157+ DC A(1) EOB, INTER

Page 407 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler Language I/O Macros

158 ****************************************
159 *
160 * INPUT FILE - DATA CONTROL BLOCK
161 *
162 ****************************************
163 FILEIN DCB DSORG=PS,
MACRF=(GM),
DEVD=DA,
DDNAME=FILEIN,
EODAD=A90END,
RECFM=FB,
LRECL=80
166+* DATA CONTROL BLOCK
167+*
0000F8 168+FILEIN DC 0F'0' ORIGIN ON
169+* DIRECT ACCESS DE
0000F8 0000000000000000 170+ DC BL16'0' FDAD, DVTB
000108 00000000 171+ DC A(0) KEYLEN, DE
172+* COMMON ACCESS ME
00010C 00 173+ DC AL1(0) BUFNO, NUM
00010D 000001 174+ DC AL3(1) BUFCB, BUF
000110 0000 175+ DC AL2(0) BUFL, BUFF
000112 4000 176+ DC BL2'0100000000000000' DSO
000114 00000001 177+ DC A(1) IOBAD FOR
178+* FOUNDATION EXTEN
000118 00 179+ DC BL1'00000000' BFTEK, BFA
000119 000074 180+ DC AL3(A90END) EODAD (END
00011C 90 181+ DC BL1'10010000' RECFM (REC
00011D 000000 182+ DC AL3(0) EXLST (EXI
183+* FOUNDATION BLOCK
000120 C6C9D3C5C9D54040 184+ DC CL8'FILEIN' DDNAME
000128 02 185+ DC BL1'00000010' OFLGS (OPE
000129 00 186+ DC BL1'00000000' IFLGS (IOS
00012A 5000 187+ DC BL2'0101000000000000' MAC
188+* BSAM-BPAM-QSAM I
00012C 00 189+ DC BL1'00000000' OPTCD, OPT
00012D 000001 190+ DC AL3(1) CHECK OR I
000130 00000001 191+ DC A(1) SYNAD, SYN
000134 0000 192+ DC H'0' INTERNAL A
000136 0000 193+ DC AL2(0) BLKSIZE, B
000138 00000000 194+ DC F'0' INTERNAL A
00013C 00000001 195+ DC A(1) INTERNAL A
196+* QSAM INTERF
000140 00000001 197+ DC A(1) EOBAD
000144 00000001 198+ DC A(1) RECAD
000148 0000 199+ DC H'0' QSWS (FLAG
00014A 0050 200+ DC AL2(80) LRECL
00014C 00 201+ DC BL1'00000000' EROPT, ERR
00014D 000001 202+ DC AL3(1) CNTRL
000150 00000000 203+ DC H'0,0' RESERVED A
000154 00000001 204+ DC A(1) EOB, INTER

Page 408 Chapter 21 Revised August 3, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 22: Job Control Language

This chapter presents a discussion of JCL (Job Control Language) as used for jobs run on a
modern IBM mainframe running a descendant of the OS operating system, such as z/OS.
First, we must define the term “job”. A job is a unit of work for the computer to execute.
The job comprises identification statements, control statements, possibly program text, and
usually data. There are conventions to label the statements that are not program text and data
so that the Control Program part of the Operating System can determine which is what.
The paradigm for a job is a sequence of cards, each card with one statement. The standard
card type is the IBM 80 column card, an example of which is shown below. The use of these
cards persisted well into the time at which programs and data could be entered through a
computer terminal. Today, in classes associated with this textbook, we skip the card input
and create text files for submission as jobs. Just remember that each line of text should be
imagined as being the content of an 80 column card.

Photo by the author of a card in his collection


The card pictured above is a “6/7/8/9 card” used on a CDC–7600. This was a control card
used to indicate the end of a specific job. In modern terms, a “7/8/9 card” would have been
an EOD (End of Data) and a “6/7/8/9 card” an EOF (End of File). The 7/8/9 cards were
green and the 6/7/8/9 cards were orange; this as a convenience to the programmer. The only
computer–readable data on any card is found in the pattern of column punches.
The transition from card input of jobs to other means was driven by the simple inconvenience
of handling boxes containing hundreds of cards. The key feature that facilitated that change
was the introduction of system disk drives big enough to store significant amounts of user
programs and data. This change was not driven by hardware only; it was some time after the
introduction of disk drives that the software designers were able to develop a stable operating
system based on the use of such drives. Your instructor recalls using a Xerox Sigma–7 while
at Vanderbilt University in the 1970’s, a time during which the operating system was being
debugged. We called the machine the “Yo–Yo 7” as it was constantly down and up.
The first step in transitioning from card input was the ability to catalog a card deck on a disk
file maintained by the computer center. Though the jobs remained card based, they became
very short: access this file, change these statements, add these statements, and then run.
Soon thereafter, the cards went away.

Page 409 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Next, it is important to dispel a misunderstanding that would be almost comical, had it not
actually occurred during the teaching of a course based on this textbook. We begin by
considering the first few lines of a program that your author assigns as a first lab.
//KC02263R JOB (KC02263),'ED BOZ',REGION=3M,CLASS=A,MSGCLASS=H,
// NOTIFY=KC02263,MSGLEVEL=(1,1)
//*
//*
//*
//FFFPROC JCLLIB ORDER=(TSOEFFF.STUDENT.PROCLIB.ASM)
//JESDS OUTPUT PAGEDEF=V06483,JESDS=ALL,DEFAULT=Y,CHARS=GT15
//STEP1 EXEC PROC=HLLASM
//ASM.SYSIN DD *
The above text is the block of job control language that precedes the text of the first
assembler language program. Note that many of the lines begin with “//”. Several students
decided that these mandatory lines were optional, since they were obviously comments.
The structure of a comment in either a programming language or an execution control
statement depends on the language or operating system. It is peculiar to that system. The
fact that the “//” character sequence introduces in–line comments in both C++ and Java
does not imply similar functioning in other situations. In IBM Job Control Language,
comments are prefixed by “//*”, with the asterisk being very significant.

The Job Control Language


There are six types of job control statements that will interest us at this time. These are:
JOB This marks the beginning of a job. It gives the user identification,
accounting information, and other site–specific data.
EXEC This marks the beginning of a job step by specifying a program or
procedure to be executed.
DD This request the allocation of an I/O device and describes the data set
on that device. It must use the logical device name from the program.
//* This is a comment in the job control language.
/* This terminates an input stream data set.
// This can be used to mark the end of a job.

Logical and Physical Devices


One of the advantages of the structure of the JCL is the ability to define a logical device
using a DCB macro within the code, and use the DD control statement to link that logical
device to an actual physical device. With the DCB, the code specifies the logical properties
of a device. For example a logical printer might be described as PS (Physical Sequential)
with record length of 133 bytes (one control character and 132 characters to be printed). The
DD statement might then associate this logical device either with the standard output stream
or with a dedicated disk file that can be saved and accessed by another job.
Much of this is discussed in chapters 5 and 6 of the IBM Redbook Introduction to the New
Mainframe: z/OS Basics [R_24].

Page 410 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The Job Card
This identifies the beginning of a job. It must include a name to associate with the job. For
use in our classes, that name is most often the user ID. The name must begin in column 3 of
the “card”, following the “//” characters. Remember that none of this is free–form input.
In general, the format of the JOB statement starts as follows.
//name JOB (account number),programmer name
Consider our example from the listing of a lab exercise.
//KC02263R JOB (KC02263),‘ED BOZ’,REGION=3M,CLASS=A,MSGCLASS=H,
The user name consists of from one to eight alphanumeric characters, with the first one being
alphabetic. The standard for our course is the user ID with a single letter following it. The
job card above shows a user ID of KC02263, with the letter “R” appended.
The next entry in this statement is the keyword “JOB” identifying this as a JOB card.
This is followed by the account number in parentheses. For our student use, the account
number is the same as the user ID. This is followed by the programmer name, which is
enclosed in quotes as the name contains a space.
The next entry, REGION=3M, specifies the amount of memory space in megabytes required
by the step. This could have been specified by REGION=3072K, indicating the same
allocation of space. The two size options here are obviously “K” and “M” [R_25, page 16–4].
The entry CLASS=A assigns a job to a class, roughly equivalent to a run–time priority.
According to R_25 [page 20-15] the “class you should request depends on the characteristics
of the job and your installation’s rules for assigning classes”. This assignment works.
The entry MSGCLASS=H assigns the job log to an output class [R_25, page 20-24].
Depending on the MSGLEVEL statement (see below), the job log will have various content.
The next line of text in the above example should be considered as a continuation of the job
card, in that the information that is found there could have been on the job card.
// NOTIFY=KC02263,MSGLEVEL=(1,1)
The notify line indicates what user is to be given information about the execution of the job;
the level of information is indicated by the integers associated with MSGLEVEL. The first
number specifies which job control statements are to be printed in the listing. There are three
possible choices.
0 Only the JOB statement is displayed. This is the default for many centers.
1. All job control statements are displayed including those generated from a cataloged
procedure. This is the default for a student job. Note that a cataloged procedure is
a sequence of control statements that have been given a name and placed in a library
of cataloged procedures.
2. Only those job control statements appearing in the input stream are displayed.
The second number inside the parentheses specifies whether or not the I/O device allocation
messages are to be printed. A 1 (the default) indicates that all allocation and termination
messages are to be printed, regardless of how the job terminates.

Page 411 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The EXEC Statement
The execute statement begins a job step that is associated with the program name or
procedure name that controls that step. Each EXEC can begin with an optional step name,
which must begin in column 3 and be unique within the job.
There are three standard forms of the execute statement.
//step name EXEC PGM=program name
//step name EXEC PROC=procedure name
//step name EXEC procedure name
The step name is optional, but if it exists it must be unique in the job. For example, we have
this line in the job control language of our first lab assignment. This calls for the H–level
assembler to be invoked. The procedure takes care of a number of steps that are required,
and can be mechanically created.
//STEP1 EXEC PROC=HLLASM
In some more advanced JCL, there is a control logic that requires step names. In this
example, we assign names just to show that we can do that.
The PGM option is rarely used by students, who commonly use cataloged procedures. This
author views stored procedures in the same light as programming macros; they are
predefined sets of statements that have proven useful in the past.
The second and third lines are equivalent, indicating that the default is to execute a cataloged
procedure. This expands into a sequence of program EXEC and DD statements.
Here is an example of the ASMFC cataloged procedure [R_09, page 384]. This is given
without explanation in order to show the expansion of a very simple cataloged procedure.
//ASM EXEC PGM=IEUASM,REGION=50K
//SYSLIB DD DSNAME=SYS1.MACLIB,DISP=SHR
//SYSUT1 DD DSNAME=&SYSUT1,UNIT=SYSSQ,SPACE=(1700,(400,50)), X
// SEP=(SYSLIB)
//SYSUT2 DD DSNAME=&SYSUT2,UNIT=SYSSQ,SPACE=(1700,(400,50))
//SYSUT3 DD DSNAME=&SYSUT3,SPACE=(1700,(400,50)), X
// UNIT=(SYSSQ,SEP=(SYSUT2,SYSUT1,SYSLIB))
//SYSPRINT DD SYSOUT=A
//SYSPPUNCH DD SYSOUT=B
There are a number of parameters to the EXEC statement, but none of these need concern us
here. The student who is interested is referred to [R_25, Chapter 16].

The DD (Data Definition) Statement


Any data sets used by the program must be described in DD statements. These must follow
the EXEC statement for the particular step in which the data sets are accessed. In the lab
examples used with the course associated with this textbook, the DD statements follow the
assembler procedure invocation and its associated program input.
For more information, the reader should consult Chapter 6 of Introduction to the New
Mainframe [R_24] or Chapter 12 of the MVS JCL Reference [R-25].

Page 412 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The general format of the DD statement is rather flexible, but all have this form.
//proc.ddname DD options
The first part of the name is the procedure step. In our programs, we use “GO” for this.
The second part of the name is identical to that used in the DCB macro in the source
program, and it further describes the data set referenced in that macro. In general, we have
the following sets of relationships within the job.

Here is an example of the linkage between DCB and DD as found in our lab 1.
FILEIN DCB DDNAME=FILEIN, X
DSORG=PS, X
DEVD=DA, X
RECFM=FB, X
LRECL=80, X
EODAD=A90END, X
MACRF=(GM)
PRINTER DCB DDNAME=PRINTER, X
DSORG=PS, X
DEVD=DA, X
MACRF=(PM), X
LRECL=133, X
RECFM=FM
END
/*
//GO.PRINTER DD SYSOUT=*
//GO.FILEIN DD *
What we have in the above example is a use of the standard input and output data streams.
The input stream data set is simply the stream that includes the text of the program and the
job control language. The “DD *” indicates that the stream is to be taken as the sequence of
80–character lines immediately following. This stream ends with “/*”.
The following represents the last lines in a job intended to print out the text of three lines.
Note the three lines of input text immediately following the DD.
//GO.FILEIN DD *
LINE 1
LINE 2
LINE 3
/*
The statement “DD SYSOUT=*” indicates that the output associated with the ddname
PRINTER is to be routed to the standard output stream, called SYSOUT.

Page 413 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The flexibility of this linkage between the DCB and DD statements is illustrated in the
following fragment, taken from another lab exercise associated with this textbook. We have
taken the above and changed only the DD statement. We have as follows:
PRINTER DCB DDNAME=PRINTER, X
DSORG=PS, X
DEVD=DA, X
MACRF=(PM), X
LRECL=133, X
RECFM=FM
END
/*
//GO PRINTER DD DSN=KC02263.SP2008.LAB10UT,SPACE=(TRK,(1,1),RLSE),
// DISP=(NEW,CATLG,DELETE)
//GO.FILEIN DD *
LINE 1
LINE 2
LINE 3
/*

The print output is now saved as a text file, called SP2008.LAB1OUT in the user area
associated with the user KC02263, which was at the time your author’s user ID. Neither the
name “SP2008” nor the name “LAB1OUT” can exceed eight characters in length.
In this version of the DD statement, we use the DSNAME operand, abbreviated as DSN. This
identifies the data set (disk file) name to be associated with the output and specifies a few
options. The two we use are the disposition option and the space allocation option.
The data set disposition operand has the general form as follows.
DISP=(file status, normal disposition, error disposition)
The first terms indicates the status of the data set in relation to this job step. The options are:
OLD An existing sat set is used as input only to this step.
SHR An existing disk data set that can be shared with other jobs concurrently.
MOD A partially completed sequential data set. New records to added at the end.
NEW A new output data set is to be created for this job step.
The second term indicates the disposition of the data set in case of a normal termination of
the process associated with the step. There are five options for this one.
KEEP Keep the data set.
PASS Pass the data set to a later job step.
DELETE Delete this existing data set.
CATLG Catalog and keep the data set.
UNCATLG Remove this data set from the catalog, but keep it.
The third term specifies disposition in the case of an abnormal termination. The option
PASS is not available, as it is presumed that an abnormal termination will be associated with
corrupt data. Note that our JCL says DISP=(NEW,CATLG,DELETE), indicating to create
a new file and catalog it if the job terminates normally. If the job has an abnormal
termination, just discard the file.

Page 414 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The space operand has the following format. It is used only for DASD (Direct Access
Storage Device, read “disk”) data sets.
SPACE=(units,(quantity,increment),option)
The units term indicates the measure of storage space to be used. In order to understand this,
one should review the architecture of a typical disk unit. The two options for this term are
CYL (cylinder) and TRK (track). Our JCL has the option SPACE=(TRK,(1,1),RLSE),
indicating that one track is to be allocated initially for our data set and that additional disk
space is to be allocated one track at a time when the existing allocation is exhausted.
The RLSE option indicates that the unused space on the DASD (disk drive) is to be released
and made available for data storage by other programs when this program terminates and the
data set is closed. [R_25, page 12–12].
One option worth mention just for historical reasons is the LABEL option. This was used
when accessing data sets on magnetic tape, either 7–track or 9–track. The label was an
identifier assigned to an individual physical tape. It was physically written on the label of the
tape (to be read by the computer operator) and written in the header record of the tape (to be
read by the Operating System). This option would insure that the correct tape was mounted,
so that the desired data (and not some other) would be processed.
The reader who is interested in tape labels is referred to a few references, including
[R_02, page 449; R_24, page 203, and R_25, chapter 12].

Page 415 Chapter 22 Revised August 5, 2009


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 23: Some Issues from Systems Programming

In this chapter, we shall discuss a number of issues related to system programming. The
main topic of the chapter focuses on the support by the RTS (Run–Time System) for the style
of programming called recursion, in which a program can call itself as a subprogram. The
topics to be investigated include the following:
a) Recursive programming with an explicit stack.
b) Writing reentrant code and using it in systems programs.
c) String space and handling variable–length strings.
d) Double–indirect addressing and Dynamic Link Libraries.

Writing Recursive Subroutines


We note immediately that the IBM 370 does not directly support recursion, though later
revisions of the Assembler Language might. The purpose of this chapter is to use the stack
handling macros discussed in a previous chapter to implement simple recursive subroutines.
Recursion is a process that requires a stack, provided either explicitly or implicitly by the
RTS (Run Time System). In this chapter, we assume no native support for recursion, and
directly manage the call stack. The simple protocol has two steps.
Subroutine Call: Push the return address onto the stack
Branch to the subroutine
Subroutine Return Pop the return address into a register
Return to that address.
Other protocols provide for using the stack to transmit variables. We shall discuss those later
in this lecture. As our first example, we consider the subprogram NUMOUT.

NUMOUT: The Old Version


Here is the original code for the packed decimal version of NUMOUT.
NUMOUT CVD R4,PACKOUT CONVERT TO PACKED
UNPK THENUM,PACKOUT PRODUCE FORMATTED NUMBER
MVZ THENUM+7(1),=X’F0’ CONVERT SIGN HALF-BYTE
BR 8 RETURN ADDRESS IN R8
This is the calling sequence for NUMOUT, placed within its context.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
BAL 8,NUMOUT PRODUCE THE FORMATTED SUM
MVC DATAPR,THENUM AND COPY TO THE PRINT AREA

Note that the BAL instruction saves the address of the next instruction into R8
before the branch is taken. The saved return address is then used by the BR 8 instruction to
return from the subroutine.

Page 416 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
NUMOUT: The Newer Version
The newer version of NUMOUT will be written in the style required for recursive
subroutines, although it will not be recursive. This style requires explicit management of the
return address. This requires the definition of a label for the instruction following the call to
NUMOUT. For no particular reason, this statement is called NUMRET.
MVC PRINT,BLANKS CLEAR THE OUTPUT BUFFER
LA 8,NUMRET STATEMENT AFTER NUMOUT
STKPUSH R8,R PLACE ADDRESS ONTO STACK
B NUMOUT BRANCH DIRECTLY TO NUMOUT
NUMRET MVC DATAPR,THENUM AND COPY TO THE PRINT AREA

Here is the new code for NUMOUT.


NUMOUT CVD R4,PACKOUT CONVERT TO PACKED
UNPK THENUM,PACKOUT PRODUCE FORMATTED NUMBER
MVZ THENUM+7(1),=X’F0’ CONVERT SIGN HALF-BYTE
STKPOP R8,R POP THE RETURN ADDRESS
BR 8 RETURN ADDRESS IN R8

Factorial: A Recursive Function


One of the standard examples of recursion is the factorial function. We shall give its
standard recursive definition and then show some typical code.
Definition: If N  1, then N! = 1
Otherwise N! = N(N – 1)!
Here is a typical programming language definition of the factorial function.
Integer Function FACT(N : Integer)
If N  1 Then Return 1
Else Return N*FACT(N – 1)

Such a function is easily implemented in a compiled high–level language (such as C++


or Java) that provides a RTS (Run Time System) with native support of a stack. As we shall
see, a low–level language, such as IBM 370 assembler, must be provided with explicit stack
handling routines if recursion is to be implemented.

Tail Recursion and Clever Compilers


Compilers for high–level languages can generally process a construct that is “tail recursive”,
in which the recursive call is the last executable statement. Consider the above code for the
factorial function.

Integer Function FACT(N : Integer)


If N  1 Then Return 1
Else Return N*FACT(N – 1)
Note that the recursive call is the last statement executed when N > 1.

Page 417 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
A good compiler will turn the code into the following, which is equivalent.
Integer Function FACT(N : Integer)
Integer F = 1 ; Declare a variable and initialize it
For (K = 2, K++, K <= N) Do F = F*K ;
Return F ;
This iterative code consumes fewer RTS resources and executes much faster.
NOTE: For fullword (32–bit integer) arithmetic, the biggest we can calculate is 12!

A Pseudo–Assembler Implementation with Problems


We want an implementation of the factorial function. It takes one argument and returns one
value. We shall attempt an implementation as FACTOR, with each of the argument and
result being passed in register R4 (my favorite). It might be called as follows.
L 4,THEARG
BAL 8,FACTOR
N1 ST 4,THERESULT
Pseudocode for the function might appear as follows.
If (R4  1) Then
L R4, = F’1’ SET R4 EQUAL TO 1
A1 BR 8 RETURN TO CALLING ROUTINE
Else
LR 7,4 COPY R4 INTO R5
S 4,=F’1’
BAL 8,FACTOR
N2 MR 6,4 MULTIPLY
A2 BR 8
This code works only for N  1.

Confusion with the Return Addresses


Suppose that FACTOR is called with N = 1. The following code executes.
L 4,=F’1’
BAL 8,FACTOR The first call to FACTOR
N1 ST 4,THERESULT

If (R4  1) then the function code is invoked. This is all that happens.
L R4, = F’1’ SET R4 EQUAL TO 1
A1 BR 8 RETURN TO CALLING ROUTINE
But note at this point, register 8 contains the address N1. Return is normal.

Suppose now that FACTOR is called with N = 2.


L 4,=F’2’
BAL 8,FACTOR PLACE A(N1) INTO R8
N1 ST 4,THERESULT

Page 418 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
This code is executed.
LR 7,4 COPY R4 INTO R5
S 4,=F’1’
BAL 8,FACTOR PLACE A(N2) INTO R8
N2 MR 6,4 MULTIPLY
A2 BR 8
The above call causes the following code to execute, as N = 1 now.
L R4, = F’1’ SET R4 EQUAL TO 1
A1 BR 8 RETURN TO CALLING ROUTINE
Here is the trouble. For N = 1, the return is OK.
Back at the invocation for N = 2. Compute 21 = 2.
Try to return to N1. But R8 contains the address N2.
The code is “trapped within FACTOR”. It can never return to the main program.

Outline of the Solution


Given the limitations of the IBM 370 original assembly language, the only way to implement
recursion is to manage the return addresses ourselves. This must be done by explicit use of
the stack. Given that we are handling the return addresses directly, we dispense with the
BAL instruction and use the unconditional branch instruction, B.
Here is code that shows the use of the unconditional branch instruction.
At this point, register R4 contains the argument.
LA R8,A94PUTIT ADDRESS OF STATEMENT AFTER CALL
STKPUSH R8,R PUSH THE ADDRESS ONTO THE STACK
STKPUSH R4,R PUSH THE ARGUMENT ONTO THE STACK
B DOFACT CALL THE SUBROUTINE
A94PUTIT BAL 8,NUMOUT FINALLY, RETURN HERE.
Note that the address of the return instruction is placed on the stack. Note also that the return
target uses the traditional subroutine call mechanism. In this example, the goal is to focus on
recursion in the use of the DOFACT subprogram. For NUMOUT, we shall use the standard
subroutine linkage based on the BAL instruction.

Proof of Principle: Code Fragment 1


Here is the complete code for the first proof of principle. The calling code is as follows.
The function is now called DOFACT.
LA R8,A94PUTIT ADDRESS OF STATEMENT AFTER CALL
STKPUSH R8,R PUSH THE ADDRESS ONTO THE STACK
STKPUSH R4,R PUSH THE ARGUMENT ONTO THE STACK
B DOFACT CALL THE SUBROUTINE
A94PUTIT BAL 8,NUMOUT FINALLY, RETURN HERE.

Page 419 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The first test case was designed with a stub for DOFACT. This design was to prove the
return mechanism. The code for this “do nothing” version of DOFACT is as follows.
DOFACT STKPOP R4,R POP RESULT BACK INTO R4
STKPOP R8,R POP RETURN ADDRESS INTO R8
BR 8 BRANCH TO THE POPPED ADDRESS

Remember: 1. STKPOP R4,R is a macro invocation.


2. The macros have to be written with a symbolic parameter as
the label of the first statement.

The Stack for Both Argument and Return Address


We now examine a slightly non–standard approach to using the stack to store both arguments
to the function and the return address. In general, the stack can be used to store any number
of arguments to a function or subroutine. We need only one argument, so that is all that we
shall stack.

Remember that a stack is a Last In / First Out data structure.


It could also be called a First In / Last Out data structure; this is seldom done.

Recall the basic structure of the function DOFACT. Here is the skeleton.
DOFACT
Use the argument from the stack
STKPOP R8,R POP RETURN ADDRESS INTO R8
BR 8 BRANCH TO THE POPPED ADDRESS
Since the return address is the last thing popped from the stack when the routine returns,
it must be the first thing pushed onto the stack when the routine is being called.

Basic Structure of the Function


On entry, the stack has both the argument and return address. On exit, it must have neither.
The return address is popped last, so it is pushed first.

On entry to the routine, this is the status of the stack. By “Stack Top”, I
indicate the location of the last item pushed.

At some point, the argument must be popped from the stack, so that the
Return Address is available to be popped.

STKPOP 8 Get the return address


BR 8 Go there
Note that the contents of the stack are not removed. This is in line with
standard stack protocol, though it might have some security implications.

Page 420 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
When Do We Pop the Argument?
The position of the STKPOP depends on the use of the argument sent to the function. There
are two considerations, both of which are quite valid. Assume that register R7 contains the
argument. We shall get it there on the next slide. Consider the fragment of code
corresponding to NFACT(N – 1).
FDOIT S R7,=F'1' SUBTRACT 1 FOR NEW ARGUMENT
LA 8,FRET GET THE ADDRESS OF RETURN
STKPUSH R8,R STORE NEW RETURN ADDRESS
STKPUSH R7,R NOW, PUSH NEW ARG ONTO STACK
B DOFACT MAKE RECURSIVE CALL
FRET L R2,=F'0'
At this point, the return register (say R4) will contain FACT(N – 1).
At this point, the value of N should be popped from the stack and multiplied by the result
to get the result NFACT(N – 1), which will be placed into R4 as the return value. But recall
that the basic structure of the factorial function calls for something like:
STKPOP R7,R
If the value in R7 is not greater than 1, execute this code.
L R4,=F’1’ SET THE RETURN VALUE TO 1
STKPOP R8,R POP THE RETURN ADDRESS
BR 8 RETURN TO THE CALLING ROUTINE.
If the value in R7 is larger than 1, then execute this code.
FDOIT S R7,=F'1' SUBTRACT 1 FOR NEW ARGUMENT
LA 8,FRET GET THE ADDRESS OF RETURN
STKPUSH R8,R STORE NEW RETURN ADDRESS
STKPUSH R7,R NOW, PUSH NEW ARG ONTO STACK
B DOFACT MAKE RECURSIVE CALL
FRET L R2,=F'0'
But, there is only one copy of the argument value. How can we pop it twice.
Answer: We push it back onto the stack.

Examining the Value at the Top of the Stack


Here is the startup code for the function DOFACT.

DOFACT L R2,=F'0'
STKPOP R7,R GET THE ARGUMENT AND EXAMINE
STKPUSH R7,R BUT PUT IT BACK ONTO THE STACK
C R7,=F'1' IS THE ARGUMENT BIGGER THAN 1
BH FDOIT YES, WE HAVE A COMPUTATION
This code fragment shows the strategy for examining the top of the stack without removing
the value: just pop it and push it back onto the stack. There is another common way of
examining the top of the stack. Many stack implementations use a function STKTOP, which
returns the value at the stack top without removing it. We shall not use this option.

Page 421 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
This is another valid option. That code could be written as follows.
DOFACT L R2,=F'0' SET R2 TO ZERO
STKTOP R7,R GET THE ARGUMENT VALUE
C R7,=F'1' IS THE ARGUMENT BIGGER THAN 1
BH FDOIT YES, WE HAVE A COMPUTATION

The Factorial Function DOFACT


Here is the code for the recursive version of the function DOFACT.
DOFACT STKPOP R7,R GET THE ARGUMENT AND EXAMINE
STKPUSH R7,R BUT PUT IT BACK ONTO THE STACK
C R7,=F'1' IS THE ARGUMENT BIGGER THAN 1
BH FDOIT YES, WE HAVE A COMPUTATION
L R4,=F'1' NO, JUST RETURN THE VALUE 1
STKPOP R7,R ARG IS NOT USED, SO POP IT
B FDONE AND RETURN
FDOIT S R7,=F'1' SUBTRACT 1 FOR NEW ARGUMENT
LA 8,FRET GET THE ADDRESS OF RETURN
STKPUSH R8,R STORE NEW RETURN ADDRESS
STKPUSH R7,R NOW, PUSH NEW ARG ONTO STACK
B DOFACT MAKE RECURSIVE CALL
FRET STKPOP R7,R POP THIS ARGUMENT FROM STACK
MR 6,4 PUT R4*R7 INTO (R6,R7)
LR 4,7 COPY PRODUCT INTO R4
FDONE STKPOP R8,R POP RETURN ADDRESS FROM STACK
BR 8 BRANCH TO THAT ADDRESS
Analysis of DOFACT
Let’s start with the code at the end. At this point, the register R4 contains the return value of
the function, and the argument has been removed from the stack.
FDONE STKPOP R8,R POP RETURN ADDRESS FROM STACK
BR 8 BRANCH TO THAT ADDRESS
The label FDONE is the common target address for the two cases discussed above.
Again, here is the top–level structure.
1. Get the argument value, N, from the stack.
2. If ( N  1 ) then
Set the return value to 1
B FDONE
3. If ( N  2) then
Handle the recursive call and return from that call.
4. FDONE: Manage the return from the function

Page 422 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
DOFACT Part 2: Handling the Case for N  1
Here is the startup code and the code to return the value for N  1.

DOFACT STKPOP R7,R GET THE ARGUMENT AND EXAMINE


STKPUSH R7,R BUT PUT IT BACK ONTO THE STACK
C R7,=F'1' IS THE ARGUMENT BIGGER THAN 1
BH FDOIT YES, WE HAVE A COMPUTATION
*
* N = 1
L R4,=F’1’ NO, JUST RETURN THE VALUE 1
STKPOP R7,R ARG IS NOT USED, SO POP IT
B FDONE AND RETURN

The startup code uses STKPOP followed by STKPUSH to get the argument value into
register R7 without removing it from the stack. That value is then compared to the constant 1.
If the argument has value 1 or less, the return value is set at 1. Note that the argument is still
on the stack. It must be popped so that the return address will be at the top of the stack and
useable by the return code at FDONE.
DOFACT Part 3: Handling the Case for N > 1
Here is the code for the case N > 1.

FDOIT S R7,=F'1' SUBTRACT 1 FOR NEW ARGUMENT


LA 8,FRET GET THE ADDRESS OF RETURN
STKPUSH R8,R STORE NEW RETURN ADDRESS
STKPUSH R7,R NOW, PUSH NEW ARG ONTO STACK
B DOFACT MAKE RECURSIVE CALL
FRET L R2,=F'0'
STKPOP R7,R
POP THIS ARGUMENT FROM STACK
*HERE
* R7 CONTAINS THE VALUE N
* R4 CONTAINS THE VALUE FACT(N – 1)
*
MR 6,4 PUT R4*R7 INTO (R6,R7)
LR 4,7 COPY PRODUCT INTO R4

The code then falls through to the “finish up” code at FDONE. Note the structure of
multiplication. Remember that an even–odd register pair, here (6, 7) is multiplied by another
register.

Sample Run for DOFACT


We shall now monitor the state of the stack for a typical call to the recursive function
DOFACT. Here is the basic structure for the problem. First we sketch the calling code.
LA 8,A1 STATEMENT AFTER CALL TO SUBROUTINE
STKPUSH R8,R PLACE RETURN ADDRESS ONTO STACK
B DOFACT BRANCH DIRECTLY TO SUBROUTINE
A1 The next instruction.

Page 423 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Here is the structure of the recursive function DOFACT
DOFACT Check value of argument
Branch to FDONE if the argument < 2.
Call DOFACT recursively
FRET Return address for the recursive call
FDONE Close–up code for the subroutine
More on the Stack
We now relate the idea of the Stack Top to our use of the SP (Stack Pointer).
The protocol used for stack management is called “post increment on push”.
In a high level programming language, this might be considered as follows.
PUSH ARG M[SP] = ARG POP ARG SP = SP – 1
SP = SP + 1 ARG = M[SP]

The status of the stack is always that the SP points to the


location into which the next item pushed will be placed.
On entry to the function, there is an argument on the top of the
stack. The return address is the value just below the argument.

When the argument is popped from the stack, we are left with
the SP pointing to the argument value that has just been popped.
The return address (RA) is now on the stack top and available
to be popped.

After the RA has been popped, the SP points to its value.


Whatever had been on the stack is now at the Stack Top.

Page 424 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Consider DOFACT For the Factorial of 3
Remember our notation for return addresses: A1 for the calling routine.
FR for the return in DOFACT.
This is the status of the stack when DOFACT is first called.

The return address (A1) of the main program was pushed


first, and then the value (3) was pushed.
The value in R4, used for the return value, is not important.

It is noted that 3 > 1 so DOFACT will be called with a value


of 2. When the first recursive call is made, the stack status is
shown at left. The top of the stack has the value 2.
The return address (FR) of the DOFACT function was
first pushed, followed by the argument value.

The Next Recursive Call To DOFACT


On the next call to DOFACT, the value at the top of the stack is found to be 2.

It is noted that 2 > 1.

The argument value for the next recursive call is computed,


and made ready to push on the stack.

The return address (FR) for DOFACT is pushed onto the stack.
Then the value of the new argument (1) is pushed onto the stack.

DOFACT is called again.

In this next call to DOFACT, the value at the top of the stack is
examined and found to be 1.

A return value is placed into the register R4, which has been
reserved for that use.

This is the status of the stack just before the first return.

It will return to address FRET in the function DOFACT.

Page 425 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The First Recursive Return
The first recursive return is to address FR (or FRET) in DOFACT. Here is the situation just
after the first recursive return.

The argument value for this invocation is


now at the top of the stack.

The value 2 is removed from the stack, multiplied


by the value in R4 (which is 1) and then stored in R4.

The return address (FR) had been popped from the


stack. The function returns to itself.

The Next Recursive Return


The next recursive return is to address FR (or FRET) in DOFACT.
Here is the situation just after the first recursive return.

Here is the status of the stack after this


return. The argument value is on the top
of the stack, followed by the return address
for the main routine.

On the final return, the value 3 has been removed


from the stack, multiplied by the value in R4, and
the new function value (6) is placed back into R4.

The return address (A1) has been popped from the


stack and the function returns there.

Page 426 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The Subroutine Linkage Problem
When a subroutine or function is called, control passes to that subroutine but must return
to the instruction immediately following the call when the subroutine exits. There are two
main issues in the design of a calling mechanism for subroutines and functions. These fall
under the heading “subroutine linkage”.
1. How to pass the return address to the subroutine so that, upon completion,
it returns to the correct address. We have just discussed this problem.
2. How to pass the arguments to the subroutine and return values from it.

A function is just a subroutine that returns a value. For functions, we have one additional
issue in the linkage discussion: how to return the function value. This presentation will be a
bit historical in that it will pose a number of linkage mechanisms in increasing order of
complexity and flexibility. We begin with a simple mechanism based on early CDC–6600
FORTRAN compilers.

Pass–By–Value and Pass–By–Reference


Modern high–level language compilers support a number of mechanisms for passing
arguments to subroutines and functions. These can be mimicked by an assembler.
Two of the most common mechanisms are:
1. Pass by value, and
2. Pass by reference.
In the pass–by–value mechanism, the value of the argument is passed to the subroutine. In
the pass–by–reference, it is the address of the argument that is passed to the subroutine,
which can then modify the value and return the new value. Suppose that we want to use
register R10 to pass an argument to a subroutine. That argument is declared as follows.
FW1 DC F‘35’
The operative code would be as follows:
Pass by value: L R10,FW1 Load the value at FW1
Pass by reference: LA R10,FW1 Load the address of FW1

Returning Function Values


There is a simple solution here that is motivated by two facts.
1. The function stores its return value as its last step.
2. The first thing the calling code should do is to retrieve that value.

This simple solution is to allocate one or more registers to return function values. There
seem to be no drawbacks to this mechanism. As we have seen above, it works rather well
with recursive functions. The solution used in these lectures was to use R7 to return the
value.

Page 427 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The CDC–6600 FORTRAN solution was to use one or two registers as needed.
Register R7 would return either a single–precision result or the
low–order bits of a double–precision result.
Register R6 would return the high–order bits of the double–precision result.
CDC Nerds note that the actual register names are X6 and X7.

Argument Passing: Version 1 (Based on Early CDC–6400 FORTRAN)


Pass the arguments in the general–purpose registers. Here we use the actual names of the
registers: X0 through X7. Register X0 was not used for a reason that I cannot remember.
Registers X1 through X5 are used to pass five arguments.
Registers X6 and X7 are used to return the value of a function.
This is a very efficient mechanism for passing arguments. The problem arises when one
wants more than five arguments to be passed. There is also a severe problem in adapting this
scheme to recursive subroutines. We shall not discuss this at present for two reasons.
1. We shall meet the identical problem later, in a more general context.
2. None of the CDC machines was designed to support recursion.

Argument Passing: Version 2 (Based on Later CDC–6400 FORTRAN)


In this design, only two values are placed on the stack. Each is an address.
The return address.
The address of a memory block containing the number of arguments
and an entry (value or address) for each of the arguments.

This method allows for passing a large number of arguments.

This method can be generalized to be compatible with the modern stack–based protocols.

Page 428 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Example Code Based on CDC–6600 FORTRAN
Here is IBM/System 370 assembly language written in the form that the CDC FORTRAN
compiler might have emitted. Consider a function with three arguments. The call in
assembly language might be.
LA R8,FRET ADDRESS OF STATEMENT TO BE
EXECUTED NEXT.
STKPUSH R8,R PLACE ADDRESS ONTO STACK
LA R8,FARGS LOAD ADDRESS OF ARGUMENT BLOCK
STKPUSH R8,R PLACE THAT ONTO THE STACK
B THEFUNC BRANCH DIRECTLY TO SUBROUTINE
A0 DC F‘3’ THE NUMBER OF ARGUMENTS
A1 DS F HOLDS THE FIRST ARGUMENT
A2 DS F HOLDS THE SECOND ARGUMENT
A3 DS F HOLDS THE THIRD ARGUMENT
FRET The instruction to be executed on return.
This cannot be used with recursive subroutines or functions.

The Solution: Use a Stack for Everything


We now turn our attention to a problem associated with writing a compiler. The
specifications for the high–level language state that recursion is to be supported, both for
subroutines and functions. It is very desirable to have only one mechanism for subroutine
linkage. Some architectures, such as the VAX–11/780 did support multiple linkages, but a
compiler writer would not find that desirable. Software designers who write compilers do
not like a complex assembly language; they want simplicity.
We have a number of issues to consider:
1. How to handle the return address. This, we have discussed.
2. How to handle the arguments passed to the subroutine or function.
We have just mentioned this one.
3. How to handle the arguments and values local to the subroutine or function.
The answer is simple: put everything on the stack.

Summary of Our Approach to Recursion


Here is an approach to recursive programming that is in step with the current practice. First,
we note that all recursive programming is to be written in a high–level language; thus, the
generation of the actual recursive code will be the job of a sophisticated compiler.
Consider a function call, such as Y = F1(A, B, C).
1. The compiler will generate code to push the return address onto the stack.
2. The compiler will generate code to push the arguments on the stack. Either order,
left to right or right to left is probably OK, but it must be absolutely consistent.
3. Optionally, the compiler generates code to push the argument count onto the stack.
4. The compiler will have a convention for use of registers to hold return values.
This might be R4 for 16–bit and 32–bit integers, the register pair (R4, R5) for
64–bit integers, and floating–point register 0 for real number results.

Page 429 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Mathematical Functions and Subroutines
We now consider a problem that occurs mostly in scientific programming and occasionally in
business programming. This is the evaluation of some of the standard functions, such as sine,
cosine, logarithm, square root, etc. There are two significant problems to be discussed.
1. The fact that the basic arithmetic instruction set of any computer includes only
the four basic operations: addition, subtraction, multiplication, and division.
2. The fact that no algorithm can be devised to produce the exact value of one of
these functions applied to an arbitrary input value.
A detailed discussion of our approach to addressing these difficulties is based on some results
from Intermediate Calculus. In this discussion, these results will only be asserted and not
justified. One should study the Calculus in order to fully appreciate our reasoning here.
Definition of an algorithm:
An algorithm is a sequence of unambiguous instructions for solving a problem.
The full definition must include the provision that the algorithm terminate for any
valid input. So we have the following definition of algorithm.
Definition: An algorithm is a finite set of instructions which, if followed, will accomplish a
particular task. In addition every algorithm must satisfy the following criteria:
i) input: there are zero or more quantities which are externally supplied;
ii) output: at least one quantity is produced;
iii) definiteness: each instruction must be clear and unambiguous;
iv) finiteness: if we trace out the instructions of the algorithm, then for
all valid cases the algorithm will terminate after a finite
number of steps;
v) effectiveness: every instruction must be sufficiently basic that it can in
principle be carried out by a person using only a pencil and
paper. It is not enough that each operation be definite as in
(iii), but it must be feasible. [page 2, R_26]
The effectiveness criterion might be restated as it being possible to map each step in the
algorithm to a simple instruction in the assembler language. In particular, only the basic
steps of addition, subtraction, multiplication and division may be used in the algorithm.
Admittedly, there are manual procedures for other processes, such as taking the square root
of an integer, but these are based on the four primitive algebraic operations.
Sample Problems
In order to illustrate a variety of system subprograms, your author has chosen the following.
1. Raising a real number to an integer power.
2. Computation of the cosine of an angle given in radian measure.
3. Computation of the square root of a non–negative real number.
In each of these cases, we shall first discuss the algorithm to be used by giving a description
in a high–level language. We then proceed to give the basis of a function, written in IBM
System 370 assembler language. As often is the case, certain necessary features related to
linkage to and from the calling program will be omitted.

Page 430 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Integer Exponentiation
We first consider the problem of raising a real number to an integer power. Unlike the more
general problem of raising a number to a real–number power (say X2.817), this procedure can
be completed using only the basic operations of addition and multiplication.
The only issue to be addressed in the discussion of this problem is that of the time efficiency
of the computation. System programmers must pay particular attention to efficiency issues.
The basic problem is to take a real number A and compute F(A, N) = AN for N ≥ 0. The
simplest algorithm is easy to describe, but not very efficient for large values of N. In terms
commonly used for algorithm analysis, this is called a “brute force” approach.
Brute Force
Function F(A, N)
R = 1 // R = Result, what a brilliant name!
For K = 1 to N Do
R = R * A
End Do
Return R
In assaying the computational complexity of this procedure, we note that the number of
multiplications is a linear function of the exponent power; specifically N multiplications are
required in order to compute the Nth power of a real number. Any competent system
programmer will naturally look for a more efficient algorithm.
We now present a more time-efficient algorithm to compute F(A, N) = AN for N ≥ 0.
This algorithm is based on representation of the power N as a binary number. Consider the
computation of A13. In 4-bit binary, we have 13 = 1101 = 18 + 14 + 12 + 11. What we
are saying is that A13 = A8A4A2A1. Our new algorithm is based on this observation.
Function F(A, N)
R = 1
AP = A // AP is a to the power P
While (N > 0) Do
NR = N mod 2
If NR = 1 Then R = R * AP
AP = AP * AP
N = N / 2 // Integer division: 1/2 = 0.
End While
Return R
One can show that the time complexity of this algorithm is log2(N). The implementation of
this algorithm in assembler language appears simple and straightforward. The efficient
implementation of this algorithm takes a bit more thought, but not much.
In our studies of algorithm analysis and design, we identify and count the primary operations
in any algorithm. Here the key operations appear to be multiplication and division. In actual
systems programming, we must pay attention to the amount of time that each operation takes
in order to execute; multiplication and division are costly in terms of time. Can we replace
either operation with a faster, but equivalent, operation?

Page 431 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
As the multiplication involves arbitrary real numbers, there is nothing to do but pay the time
cost and be happy that the number of these operations scales as log2(N) and not as N. But
note that the division is always of a non–negative integer by 2. Here we can be creative.
Consider the following code fragment, adapted from the algorithm above. Without changing
the effect of the code, we have rewritten it as follows.
NR = N mod 2
N = N / 2 // Integer division: 1/2 = 0.
If NR = 1 Then R = R * AP
AP = AP * AP
What we shall do in our implementation is replace the integer division by a logical right shift
(double precision), using an even–odd register pair. Let us assume that the integer power for
the exponentiation is in R4, the even register of the even–odd pair (R4, R5). Here is the code.
SR R5,R5 // Set register R5 to 0.
SRDL R4,1 // Shift right by 1 to divide by 2
CH R5,=H‘0’ // Is the old value of R4 even?
BE ISEVEN // N mod 2 was 0.
MDR F2,F4 // R = R * AP
ISEVEN MDR F4,F4 // AP = AP * AP
Let’s write a bit more of the code to see the basic idea of the algorithm. We all know that
any number raised to the power 0 gives the value 1; here we say AN = 1, if N  0. The only
general implementation of the algorithm will use the floating–point multiplication operator;
here I arbitrarily choose the double–precision operator MDR.
Here are the specifications for the implementation.
On entry Integer register R4 contains the integer power for the exponentiation.
Floating point register 2 contains the number to be raised to the power.
On exit Floating point register 0 contains the answer.
Here is a code fragment that reflects the considerations to this point. In this code fragment, I
assume that I have used the equate to set F0 to 0, F2 to 2, F4 to 4, and F6 to 6, in the same
manner in which the R symbols were equated to integer register numbers.
LD F0,=D‘0.0’ // Clear floating point register 0
CD F2,=D‘0.0’ // Is the argument zero?
BE DONE // Yes, the answer is zero.
LD F0,=D‘1.0’ // Default answer is now 1.0
LDR F4,F2 // Copy argument into FP register 4
CH R4,=H‘0’ // Is the integer power positive?
BLE DONE // No, we are done.
SR R5,R5 // Set register R5 to 0.
SRDL R4,1 // Shift right by 1 to divide by 2
CH R5,=H‘0’ // Is the old value of R4 even?
BE ISEVEN // N mod 2 was 0.
MDR F2,F4 // R = R * AP
ISEVEN MDR F4,F4 // AP = AP * AP

Page 432 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
All we have to do now is to put this within a loop structure. Here is what we have.
POWER LD F0,=D‘0.0’ // Clear floating point register 0
CD F2,=D‘0.0’ // Is the argument zero?
BE DONE // Yes, the answer is zero.
LD F0,=D‘1.0’ // Default answer is now 1.0
LDR F4,F2 // Copy argument into FP register 4
TOP CH R4,=H‘0’ // Is the integer power positive?
BLE DONE // No, we are done.
SR R5,R5 // Set register R5 to 0.
SRDL R4,1 // Shift right by 1 to divide by 2
CH R5,=H‘0’ // Is the old value of R4 even?
BE ISEVEN // N mod 2 was 0.
MDR F2,F4 // R = R * AP
ISEVEN MDR F4,F4 // AP = AP * AP
B TOP // Go back to the top of the loop
DONE BR R14 // Return with function value.
Again, we should note that the provision for proper subroutine linkage in the above code is
minimal and does not meet established software engineering standards. All we need is a
provision to save and restore the registers used in this calculation that were not set at the call.
Before we move to consideration of the common algorithm for computing the square root of
an arbitrary number, we shall consider the more general problem of raising a number (real or
integer) to an arbitrary real power. This is significantly more difficult that that of raising a
number to an integer power, or to a specific rational–number power such as ½.
Let A be an arbitrary positive number. Specifically, its value is not zero. We consider the
problem of computing F(A, X) = AX, where X is an arbitrary real number. The general way
is based on logarithms and exponents. Because the values are more easily computed, most
implementations use natural logarithms and the corresponding exponentiation.
Let B = ln(A), the natural logarithm of A.
Then AX = (eB)X = e(BX), where e  2.71818, is the base for the natural logarithms. Thus,
the basic parts of the general exponentiation algorithm are as follows.
1. Get rid of the obvious cases of A = 0.0 and X = 0.0.
Decide how to handle A < 0.0, as the following assumes A > 0.0.
2. Take the natural logarithm of A; call it B = ln(A).
3. Multiply that number by X, the power for the exponentiation.
4. Compute e(BX), and this is the answer. Note that there is a well–known algorithm
based on simple results from calculus to compute e to any power.
If it makes sense, adjust for the sign of A.
The point here is that the general exponentiation problem requires invocation of two fairly
complex system routines, one to calculate the natural logarithm and one to compute the value
of e(BX). This is much slower than the computation of an integer power. Remember that fact
when writing high–level languages that require exponentiation.

Page 433 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Evaluating Transcendental Functions
We now discuss one standard way of computing the value of a transcendental function, given
the restriction that only the basic four mathematical operations (addition, subtraction,
multiplication, and division) may be used in the implementation of any algorithm.
This standard way consists of computing an approximation to the result of an infinite series.
In effect, we sample a moderately large number of terms from the infinite sequence, sum
these terms, and arrive at a result that has acceptable precision. As noted above, the only
way to view evaluation of an infinite series as an algorithm is to state a required precision.
Here are some of the common infinite series representations of several transcendental
functions. Each series can be derived by use of a number of standard calculus techniques.
The basic idea here is that of convergence, which denotes the tendency of an infinite series to
approach a limiting value, and do so more exactly as the number of terms evaluated increases.
In more precise terms, consider a function F(X) which can be represented by the infinite
series F(X) = T0(X) + T1(X) + T2(X) + …. + TN(X) + …, representing the true function value.
Define FN(X) = T0(X) + T1(X) + T2(X) + …. + TN(X) as that value obtained by the
summation of the first (N + 1) terms of the infinite series.
A series is said to converge if for any positive number  > 0 (representing a desired accuracy),
we can find an integer N0 such that for all N > N0, we have |F(X) – FN(X)| < . There are a
few equivalent ways to state this property; basically it states that for any realistic precision,
one is guaranteed that only a finite number of the terms of the infinite series must be
evaluated. For the trigonometric functions, the input must be in radians (not degrees).
SIN(X) = X – X3/3! + X5/5! – X7/7! + X9/9! – ….+ (–1)NX2N+1/(2N+1)! …
COS(X) = 1 – X2/2! + X4/4! – X6/6! + X8/8! – ….+ (–1)NX2N/(2N)! …
EXP(Z) = 1 + Z + Z2/2! + Z3/3! + Z4/4! + …. + ZN/N! + ….
LN(1+Z) = Z – Z2/2 + Z3/3 – Z4/4 + …. – (–Z)N/N + …
Here either Z = 1 or |Z| < 1. Otherwise, the series is not useful.
Consider the problem of evaluating the sine of an angle. Here are a few of the well–known
values: SIN(0) = 0.00, SIN(90) = 1.00, SIN(180) = 0.00,and SIN(–90) = –1.00. As noted
just above, the formulae are specific to computations for angles in radians. For this reason,
some systems offer trigonometric functions in pairs. For the sine computation, we may have
SIN() sine of the angle, which is expressed in radians, and
SIND() sine of the angle, which is expressed in degrees.
Given an angle in degrees, the first thing that any computation will do is to convert the angle
to equivalent radian measure. The one exception to that would be first to translate the angle
into the range –180    180, by repeated additions or subtractions of 360. It is a well
known property of all trigonometric functions that, given any integer N (positive, negative, or
0) and angle  expressed in degrees, we have F() = F( + N360) = F( – N360). There
may be some numerical advantage to doing this conversion on the degree measure.

Page 434 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The next step, when handling an angle stated in degrees is an immediate conversion to radian
measure. As 180 =  radians, we multiply the degree measure of an angle by
( / 180)  0.0174 5329 2519 9432 9576 9237 to convert to radian measure.
Given an angle in radian measure, the first step would be to convert that measure into the
standard range –    , by repeated additions or subtractions of . This follows the
property stated above for trigonometric functions: F() = F( + 2N) = F( – 2N).
The attentive reader will note that each “standard range” listed above has an overlap at its
ends; basically –180 and 180 represent the same angle, as do – and .
Once the angle is expressed in radians and given by a measure in the standard range, which
is –    , the next step in computation of the sine is to reduce the range to the more
usable (– / 2)    ( / 2) by adapting the standard formula for SIN(X  Y), which is
SIN(X  Y) = SIN(X)COS(Y)  COS(X)SIN(Y). The common variants are:
SIN(/2 – ) = SIN(/2)COS() – COS(/2)SIN()
= 1COS() – 0SIN() = COS(); also COS(/2 – ) = SIN().
SIN( – /2) = SIN()COS(/2) – COS()SIN(/2)
= SIN()0 – COS()1 = – COS().
SIN( – ) = SIN()COS() – COS()SIN()
= 0COS() – (–1)SIN() = SIN().
SIN( – ) = SIN()COS() – COS()SIN()
= SIN()(–1) – COS()0 = – SIN()
The goal, and end result, of all of this trigonometry is to reduce the absolute value of the
radian measure of the angle to || < /2. This allows an easy computation of the number of
terms to be computed in the otherwise infinite series, depending on the required accuracy.
We have: SIN(X) = X – X3/3! + X5/5! – X7/7! + X9/9! – ….+ (–1)NX2N+1/(2N+1)! …
Note that the Nth term in this series is written as TN = (–1)NX2N+1/(2N+1)!. A standard result
of calculus indicated that the maximum error from terminating this series at TN is given by
TN = |X|2N+1/(2N+1)!, where |X| is the absolute value of X.
Put another way, let SIN() represent the exact value of the sine of the angle , represented
in radians and let SN() =  – 3/3! + 5/5! – 7/7! + 9/9! – ….+ (–1)N2N+1/(2N+1)!
represent the finite sum of the first (N + 1) terms in the infinite series. We are guaranteed
that the maximum error in using this finite sum as the sine of the angle is given by
|SIN() – SN()|  |X|2N+1/(2N+1)!.
More specifically, for || < /2, we are guaranteed that any computational error is bounded
by |SIN() – SN()|  (/2)2N+1/(2N+1)!. Given that the factor (/2) is a bit tedious to use,
and the fact that (/2) < 2, we can say that |SIN() – SN()|  (2)2N+1/(2N+1)!

Page 435 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
The results for our error analysis are given in the following table. Note that seven terms are
all that is required for a result to be expressed in the IBM E (Single Precision Floating Point)
format, while 13 terms are more than good enough for the IBM D (Double Precision Floating
Point) format. The extended precision floating point may require a few more terms.
N 2N + 1 (2)2N+1 (2N+1)! Max Error Significant Digits
3 7 128 5040 0.025 1
–5
5 11 2048 39,916,800 5.130710 4
12 –8
7 15 32,768 1.3076710 2.505910 7
17 –12
9 19 524,288 1.2164510 4.3099910 11
11 23 8,388,608 2.585201022 3.2448610–16 15
28 –20
13 27 134,217,728 1.0888810 1.23261410 19
As an example of the fast convergence of the series, I consider the evaluation of
the cosine of 1.0 radian, about 57.3 degrees.
Look at the terms in the infinite series, written as T0 + T2 + T4 + T6 + T8 + ...,
and construct the partial sums.
N=0 T0 = + 1.00000000
2
N = 2 X = 1.0 T2 = – 1 / 2 = – 0.50000000
4
N = 4 X = 1.0 T4 = + 1 / 24 = + 0.04166666
N = 6 X6 = 1.0 T6 = – 1 / 720 = – 0.00138889
N = 8 X8 = 1.0 T8 = + 1 / 40320 = + 0.00002480
The terms are decreasing fast. How many terms do we need to evaluate to get a specified
precision? Answer: Not many.
The answer for COS(1.0), after five terms in the series is 0.54030257.
My calculator computes the value as 0.540302306.
Note the agreement to six digits. Assuming that the value from my calculator is correct,
the relative error in this series sum approximation is 1.000 000 488 615, or a percentage
error of 4.8910–5%. After a few more terms, this result would be useable almost anywhere.
The absolute error in the above, assuming again that my calculator is correct,
is given by the difference: 0.000 000 264.
Comparison to the value 0.000 024 800, which is the maximum theoretical error,
shows that our series approximation will serve very well over a wide range of arguments.
As we have covered more than enough Assembler Language syntax to write the loop, there
is no need to write the code for this computation here. The reader may take this as an
exercise, which might actually be fun.
The structure of the computation would be a loop that sequentially builds the partial sums
from the terms as shown above. The only real question is the termination criterion for the
computation loop. There are two useable options.
1. Terminate after a fixed number of terms have been calculated.
Thirteen terms should be more than adequate.
2. Terminate after the absolute value of the calculated term drops below a given value.

Page 436 Chapter 23 Revised January 4, 2010


Copyright © by Edward L. Bosworth, Ph.D.
Chapter 24: Some Compilation Examples

In this chapter, we shall examine the output of a few compilers in order to understand the
assembler language code emitted by those compilers. We study this assembler code in order
to understand the structure of compilers and gain a deeper understanding of how to use them.
The high–level languages to be considered in this chapter are mostly the older and less used
languages, such as FORTRAN and COBOL. The reason for this choice is that they are easier
to discuss and do make the points that are the focus of this chapter.

Variable Type
We start with an immediate distinction between high–level languages and assembler
language, and then proceed to investigate the implications. The simple, true, and important
statement that forms the basic of this chapter is quite simple. Here it is.
Compiled languages use variables; assembler language does not.
Put another way, this chapter focuses on the simple question “What is a variable, and why is it
not proper to assume that an assembler language does not use variables?” In order to study
this, we must first discuss the idea of labels as used by an assembler and see how these labels
are generalized into variables as used by a high–level compiled language.
Assembler language evolved from machine language, which at its basic form is represented as
a sequence of binary numbers. Most discussions of machine language employ hexadecimal
notation (as pure binary is hard to read) and move towards Assembler Language by
substituting mnemonics for binary (or hexadecimal) operation codes. We shall use this hybrid
notation in order to investigate the use of labels by Assembler Language.
In our earlier discussions of IBM 370 Assembler Language, we have mentioned the idea of
labels and explained their usage. In this discussion of labels, we shall find it a bit easier to
first discuss them within the context of an extremely simple (and fictional) assembly
language, such as that for the MARIE, developed by Linda Null and Julia Lobur for their
excellent textbook The Essentials of Computer Organization and Architecture. This book
is published by Jones and Bartlett (Sudbury, MA). The version used as the basis for these
notes was published in 2003, with ISBN 0 – 7637 – 2585 – 4.
The MARIE is a single accumulator design, with a very simple instruction set. This single
accumulator holds the results of any input operation, as well as the results of any load from
memory or arithmetic operation. Here is a table describing the basic instruction set, copied
from the textbook by Null and Lobur.

Page 437 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

The MARIE uses 16–bit words, and has 16–bit instructions. The instructions have a uniform
4–bit operation code and possibly 12 bits for operand address; one hexadecimal digit to
denote the operation and three hexadecimal digits to denote the address.. While this
architecture is extremely restrictive, it suffices to present an excellent example of a stored
program computer. More to the point, it exactly illustrates the points important to this
chapter. For this reason, our early examples are based on the MARIE.
Consider now the following simple program written in MARIE assembler language. Note
that these notes assume that anything following “//” in a line is a comment; in this way it
follows the syntax of Java, C++, and possibly the MARIE assembler.
LOAD X // Value in X is placed into the accumulator
ADD Y // Add value in Y to that in the accumulator
STORE Z // Store value into location Z.
HALT // Stop the computer.
In a FORTRAN program, the equivalent statement would be Z = X + Y.
In order to understand the point of this chapter, we must give a plausible machine language
rendition of the above simple assembler language program. In order to read this, we must
recall the following operation codes, which are each single hexadecimal digits.
0x1 LOAD
0x2 STORE
0x3 ADD
0x7 HALT
Here is the machine language program, rendered with hexadecimal digits. While comments
never form a part of a machine language program, your author indulges himself a bit here.
1402 // Load the accumulator from address 0x402
3404 // Add the contents of address 0x404
2406 // Store the results into address 0x406
7000 // Stop the computer. The contents of the right
// three digits, here “000”, are irrelevant.
In the very first era of computer programming (late 1940’s), the above machine language
program was the standard. The programmer had to reserve specific addresses in the memory
for data storage, and be sure that these were properly used. This became tedious very quickly.
Almost immediately, assembler language (also called “assembly language”) was developed
and used. The first use was to allow programmers to identify storage locations by label and
have the assembler allocate addresses to these labels.
If the assembler is to allocate memory to these labels, the question of how much storage for
each symbol immediately suggests itself. More specifically, each label is supposed to denote
storage for some sort of data. How much storage is required?
The basic integer storage in the MARIE architecture is a 16–bit integer; this corresponds to
the halfword fixed–point binary in IBM 370 Assembler Language. For this reason, I elect to
extend the MARIE assembler language to use IBM–style data definitions. Also, I am using
byte addressability, though the MARIE is word addressable, in order to make the 16–bit word
addresses more similar to the IBM halfword addresses.

Page 438 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

The assembler language program above might now be written in the following way.
LOAD X // Value in X is placed into the accumulator
ADD Y // Add value in Y to that in the accumulator
STORE Z // Store value into location Z.
HALT // Stop the computer.

X DS H // Sixteen bits (two bytes) for label X


Y DS H // Sixteen bits (two bytes) for label Y
Z DS H // Sixteen bits (two bytes) for label Z
Look again at the raw machine code, written in hexadecimal. Assuming a load address of
0x100 (hexadecimal 100) for the code, the two fragments might resemble the following.
100 1402 // Load the accumulator from address 0x402
102 3404 // Add the contents of address 0x404
104 2406 // Store the results into address 0x406
106 7000 // Stop the computer.
More stuff
402 0000 // Two bytes associated with label X
404 0000 // Two bytes associated with label Y
406 0000 // Two bytes associated with label Z
In the early days of computer programming, one might write assembler in the fashion above
or in the IBM Assembler Language equivalent (to be used below), but one then needed to
decide on the storage allocation and convert everything to binary by hand.
The idea of an assembler that processed a slightly–higher–level language dates at least to the
late 1940’s (with the EDSAC), and probably predates that. The two main features of early
assembler languages both related to the interpretation of symbols, as either:
1. Operation labels to be translated into opcodes, or
2. Labels that were to identify addresses, either of data or locations in the code.
Most early assemblers used two passes. The first pass would identify the symbols and the
second pass would generate the machine language. Consider again the above code.
LOAD X // Value in X is placed into the accumulator
ADD Y // Add value in Y to that in the accumulator
STORE Z // Store value into location Z.
HALT // Stop the computer.
// More code here.
X DS H // Sixteen bits (two bytes) for label X
Y DS H // Sixteen bits (two bytes) for label Y
Z DS H // Sixteen bits (two bytes) for label Z
The first pass would identify the tokens (LOAD, ADD, STORE, and HALT) as instructions. It
would identify the labels (X, Y, and Z) as being associated with addresses. It is important to
note what the assembler will not do.

Page 439 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

Consider the processing of the three data definitions. In following the process, we need to
note what information the assembler can be considered to store in its symbol table, and how
it processes the explicit length for each type. Each declaration calls for two bytes.
The first pass of the assembler is based on a value called the location counter (LC). The
assembler assumes a start address (which will be adjusted by the loader), and allocates storage
for each instruction and data item relative to this start address. The above example is repeated
here, to show how the LC would be used if byte addressing were in use.
100 1402 // Load the accumulator from address 0x402
102 3404 // Add the contents of address 0x404
104 2406 // Store the results into address 0x406
106 7000 // Stop the computer.
The convention calls for the first instruction to be assigned to location 0x100. Remember that
all numbers in this discussion are shown in hexadecimal format. This instruction has a length
of two bytes, so it will occupy addresses 0x100 and 0x101.
The second instruction is to be placed at location 0x102. It also has two bytes.
The third instruction is to be placed at location 0x104, and the fourth at 0x106.
We assume that more code follows, so that by the time the labels (X, Y, and Z) are read, the
location counter has value 0x402; the next item is to be placed as address 0x402. Recall the
declarations, each of which states how many bytes are to be set aside.
X DS H // Sixteen bits (two bytes) for label X
Y DS H // Sixteen bits (two bytes) for label Y
Z DS H // Sixteen bits (two bytes) for label Z
Label X is associated with address 0x402. It calls for an allocation of two bytes, so that
the 16–bit number will be stored in bytes 0x402 and 0x403. The next available
location is 0x404.
Label Y is associated with address 0x404, and label Z is associated with address 0x406. The
address for each is generated by allowing the proper storage for the preceding label. After
this much of the assembler process, we have the following symbol table.
Label Address
X 0x402
Y 0x404
Z 0x406
But note that the table does not carry any information on the length of the storage space
allocated to each symbol, much less any on its data type. The only use made of the data
definitions is in the placement of the next label. Specifically, there is no indication of the
types of operations that are appropriate for data contained in these locations; the one writing
the program is responsible to see to that and to use only those operations that are appropriate.
The idea of a variable, as used in a higher level language, comprises far more information
than just the location to be associated with the data. It includes the type, which dictates not
only the size of the storage space, but also the operations appropriate for the data.

Page 440 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

Most high–level languages specify that each variable has a type associated. Early languages,
such as FORTRAN allowed the variable type to be explicit in the name. Names that began
with the letters I, J, K, L, M, or N were implicitly integers, the rest were implicitly single
precision floating point numbers. Explicit type declaration was available, but little used.
Experience in software engineering caused explicit data typing to take hold; a variable could
not be used until it had been explicitly declared and given a data type. The reason for this
change in policy can be seen in the following fragment of old–style FORTRAN code, which
represents a part of a commercial program that had been in use six years before the problem
was found. Folks, this was your defense dollars at work.
SUBROUTINE CLOUDCOLOR (LAT, LONG, C1, C2, C3)
C FIRST GET THE CLOUD COVER DENSITY
DENSITY = CLOUDDENSITY (LAT, L0NG)
C NOW GET THE COLOR OF THE REFLECTED LIGHT
GETCOLOR (DENSITY, C1, C2, C3)
RETURN
Before reading the explanation of the problem, the reader should attempt to scan the code
above and discover the problem. Code such as this would compile under the old FORTRAN,
and is unusual only for having comments (denoted by the “C” in column 1). While there is no
explicit variable typing, none was required. Variables beginning with “L” were integers and
those beginning with “C” and “D” were real numbers. This was as intended by the design.
This is a map–oriented problem. The variable “LAT” appears to reference a latitude (in
degrees) on a map, and is actually supposed to do so. But note the reference to longitude on
the map. It appears to be denoted by “LONG”, but a careful reader will note that there are
two variables associated longitude; these are “LONG” and “L0NG”. Reader, be honest. Did
you really note the two spellings, one with the letter “O” and the other with the digit “0”?
Within the context of a FORTRAN subroutine, the appearance of a variable as an argument in
the line defining the subroutine immediately gives it a definition. Thus, the appearance of the
variable LONG in the first line implicitly declared it as an integer and made it useable.
What about the stray variable L0NG? The semantics of older FORTRAN allowed a variable
to be declared by simple use. On first occurrence, it was initialized to a variant of zero and all
further use would develop that value. In the code fragment paraphrased above, there was only
one use of “L0NG”, which occurred in the call to the cloud map. So, while the simulation was
attempting to compute cloud covers and spectral densities over the mid Pacific, it was always
returning the data for either London or a location in Western Africa (Longitude = 0).
The problem, as noted above, could have been avoided by use of the cross reference map
provided by every FORTRAN compiler; indeed it was this tool that was used to find it. This
map has a list of every variable name and other label used in a module (program, subroutine,
or function), the line at which it was defined or assigned a value, and every line in which it
was used. Reading such a listing was tedious; most programmers did not do it. Had our
programmer read it, she would have discovered entries similar to the following.
L0NG 3*
LONG 1*

Page 441 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

In the above subroutine, with the incorrectly spelled “L0NG” replaced by “LONG”, the symbol
table would have an appearance that might be interpreted to contain the following.
Label Data Type Storage Address
C1 Single Float 4 bytes Some value
C2 Single Float 4 bytes Some value
C3 Single Float 4 bytes Some value
DENSITY Single Float 4 bytes Some value
LAT Integer 2 bytes Some value
LONG Integer 2 bytes Some value
It is the appearance of this type of symbol table, along with a data type reference for each of
the labels, that causes the appearance of true variables in a program as opposed to labels.
Once a label has been explicitly declared (and all proper declarations are now explicit), any
operation on that label will be appropriate for the data type. Put another way, the compiler
now has the responsibility for proper data typing; it has been taken from the programmer.
For the remainder of this chapter, we shall be using IBM 370 Assembler. The following
program is roughly equivalent to the MARIE code; the HALT has been removed.
LD 0,X LOAD REGISTER 0 FROM ADDRESS X
AD 0,Y ADD VALUE AT ADDRESS Y
STD 0,Z STORE RESULT INTO ADDRESS Z

More code

X DC D‘3.0’ DOUBLE-PRECISION FLOAT


Y DC D‘4.0’
Z DC D‘0.0’
The symbols LD, AD, and STD would be identified as assembler language operations, and
the symbol 0 would be identified as a reference to register 0. The S/370 had four floating
point registers, numbered 0, 2, 4, and 6. Each had a length of 64 bits, appropriate for double
precision floating point format. The symbols X, Y, and Z are declared as double precision
floating point, and each is initialized.
In the above fragments, we see two independent processes at work.
1) Use of data declarations to reserve space in memory to
be associated with labeled addresses.
2) Use of assembly code to perform operations on these data.
Note that these are inherently independent. It is the responsibility of the coder to apply the
operations to the correct data types. Occasionally, it is proper to apply a different (and
apparently inconsistent) operation to a data type. Consider the following.
XX DS D Double-precision floating point
All that really says is “Set aside an eight–byte memory area, and associate it with the symbol
XX.” Any eight–byte data item could be placed here, even a 15–digit packed decimal format.
(This is commonly done; check your notes on CVB and CVD.)

Page 442 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

To show what could happen, and commonly does in student programs, we rewrite the above
fragment, using some operations that are not consistent with the data types.
LD 0,X LOAD REGISTER 0 FROM ADDRESS X
AD 0,Y ADD VALUE AT ADDRESS Y
STD 0,Z STORE RESULT INTO ADDRESS Z
X DC E‘3.0’ SINGLE-PRECISION FLOAT, 4 BYTES
Y DC E‘4.0’ ANOTHER SINGLE-PRECISION
Z DC D‘0.0’ A DOUBLE PRECISION
The first instruction “LD 0,X” will go to address X and extract the next eight bytes. This
will be four bytes for 3.0 and four bytes for 4.0. The value retrieved, represented in raw
hexadecimal will be 0x4130 0000 4140 0000, which can represent a double–precision
number with value slightly larger than 3.0. Had X and Y been properly declared, the value
retrieved would have been 0x4130 0000 0000 0000.

Examples from a Modern Compiler


Consider the following fragments of Java code.
double x = 3.0; // 64 bits or eight bytes
double y = 4.0; // 64 bits or eight bytes
double z = 0.0; // 64 bits or eight bytes
// More declarations and code here.
z = x + y; // Do the addition that is
// proper for this data type.
// Here, it is double-precision
// floating point addition.
Note that the compiler will interpret the source–language statement
“z = x + y” according to the data types of the operands.
Here is more code, similar to the first fragment. Note the two data types involved.
float a = 3.0; // 32 bits or four bytes
float b = 4.0; // 32 bits or four bytes
float c = 0.0; // 32 bits or four bytes
double x = 3.0; // 64 bits or eight bytes
double y = 4.0; // 64 bits or eight bytes
double z = 0.0; // 64 bits or eight bytes
// More declarations and code here.
c = a + b; // Single-precision floating-point
// addition is done here
z = x + y; // Double-precision floating-point
// addition is done here
The operations “c = a + b” and “z = x + y” have no meaning, apart from the data
types recorded by the compiler.

Page 443 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

In order to elaborate the above claim that the operations have no meaning apart from the data
types, let us consider the assembler language that might be produced were the Java code
actually compiled on a S/370 and not interpreted by the JVM (Java Virtual Machine).
// c = a + b ;
LE 0,A Load single precision float
AE 0,B Add single precision float
STE 0,C Store single precision float
// z = x + y ;
LD 2,X Load double precision float
AD 2,Y Add double precision float
STD 2,Z Store double precision float
Note that, when possible, the compiler will avoid immediate reuse of registers, in an attempt
to keep as much data in local registers for later use. The code is more efficient, and is less
likely to give rise to “register spillage” in which the contents of a register are written back to
main memory. Memory reads and writes are time–consuming processes, each possibly taking
multiple tens of CPU clock cycles.
Modern compilers devote a large amount of computation to devising a register mapping
scheme (allocation of values to registers) that will minimize the register spillage in arithmetic
operations of moderate complexity. Consider the following example.
double v = 0.0, w = 0.0, x = 3.0, y = 4.0, z = 5.0 ;
w = x + y ;
v = x + y + z ;
The example below shows inefficient code of the type actually emitted by an early 1970’s era
compiler. The modern compiler keeps the sum x + y in register 0 and reuses it as a partial
sum in the next result x + y + z.
Older Compiler Modern Compiler
LD 0, X LD 0, X
AD 0, Y AD 0, Y
STD 0, W STD 0, W
LD 0, X
AD 0, Y
AD 0, Z AD 0, Z
STD 0, V STD 0, V
In the above example, code efficiency is obtained by retaining the partial sum “X + Y” in the
register and not repeating the two earlier assembly language instructions. Often times, in less
sophisticated compilers one may see code such as the following sequence.
STD 2, W Store the value
LD 2, W Now get the value back into the register.
Here we see the silliness of loading a register with a value that it must already contain. This
was the main flaw of the early simplistic compilers; each statement was treated individually.
Modern compilers are considerably more sophisticated.

Page 444 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
S/370 Assembler Examples from Compiled Languages

Summary
The most obvious conclusion is that it is not appropriate to discuss assembler language code
in terms of variables. The name “variable” should be reserved for higher–level compiled
languages in which a data type is attached to each data symbol. The data type at least
indicates the amount of storage space to be associated with the label and what operations are
appropriate for use with it; the type may contain much more information.
Here is a brief comparison.
Assembler Compiled HLL
Data type Operation, as indicated by Data declaration, which
the OP Code, such as A, AD, determines the operations
AE, AP, etc. applied to the data
Attributes of the label Address Address
(Storage size) This is used in Storage size
Pass 1 of the Assembler, but
not kept for future use.
Data type as declared

We closed this chapter with a brief discussion of compiler technology, focusing on the
simplicities of earlier compilers that lead to such inefficient code. As mentioned in the first
chapter of this textbook, some early compilers were very inefficient and considered each
statement of high–level code in isolation from all others. This lead to very inefficient
executable code, and encouraged the programmer to rewrite parts of the assembler code
emitted by the compiler in order to obtain acceptable performance.

Page 445 Chapter 24 Revised January 5, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Chapter 25: External Storage

Author’s Note: This chapter is copied almost verbatim from the material in
Chapter 17 of the textbook by Peter Abel. It is used by permission.
A file, or data set, is a collection of related data records. Most data processing applications
involve data files of such volume that they require large external magnetic tape and disk
storage devices. Tape and disk provide mass external permanent storage, extremely fast
input/output, reusability, and records of almost any reasonable length.
This chapter introduces the various file organization methods and describes the architecture
for magnetic tape and disk drives. The next three chapters cover the processing of files.

File Organization Methods


In any system, a set of related records is arranged into a file and organized according to the
way in which programs are intended to process them. Once you create a file under a
particular organization method, all programs that subsequently process the file must do so
according to the requirements of the method. Most commonly, this is done by using macros
and subroutine calls associated with the method that wrote the data: VSAM out, VSAM in.
Let’s take a brief look at the most common organization methods.

Sequential File Organization


Under sequential organization, records are stored one after another. Almost all commercial
data sets comprise records with an identifying element called the key. For example, consider
a data set holding student information. Each record would probably have a key value used to
associate that record with the student, most likely a student ID number.
The records in a commercial data set would normally be in ascending sequence (the usual) or
descending sequence by a particular key or keys (control word), such as customer number or
employee number within department, or, contrary to what the name “sequential organization”
implies, records need not be in any particular sequence.
In some data sets used to support scientific research, records do not have associated keys.
The record may be a list of measurements, such as temperatures or particle energies that have
been observed. All of these data are input to a program that processes them.
In commercial usage, we have the “old master/new master” scenario. A typical instance of
this would be inventory processing. The program that does such processing would have two
inputs, each a sequential data set.
1) An “old master” data set containing inventory information, with records sorted
by part number in ascending sequence.
2) A data set containing transaction records for the sales activity that day.
At the end of the day, the transaction records would be read into the computer and sorted by
part number in the same way as those records in the old master data set. The processing
would then apply the transactions to the old master data set, producing a “new master” data
set that represented the inventory at the end of the day (accounting for all sales in the
transaction records); this becomes the old master for the next day. Other processing may
produce a data set containing orders to be made in order to replenish the inventory.

Page 446 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

You can store a sequentially organized file on any type of device and for any type of file,
such as master, transaction, and archival. Such a file can even be stored on punch cards, such
as the 80–column punch cards that were once used to store programs and data. While punch
cards have not been much used to store data since about 1990 (due to the storage space
required), a data set on punched cards may be considered as being in unblocked form (see
below) on a magnetic tape (also little used since about 2000).

Indexed Sequential (ISAM) File Organization


Indexed sequential organization for master files lets one access records in ascending
sequence and also support indices that enable access of any record randomly by key. The
ISAM organization is very efficient, but not flexible when records are inserted and deleted at
random. The newer VSAM method is more flexible and provides equivalent services; for
this reason we mention ISAM only as an item of historical interest.

Direct File Organization


Direct file organization facilitates direct access for any record in a master file. The main
advantage is that this method provides fast access for records and is thus particularly useful
for online systems.

Virtual Storage Access Method (VSAM)


Virtual storage access method (VSAM) supports three organization types. Entry–sequenced
is equivalent to sequential organization, key–sequenced is equivalent to ISAM, and relative–
record is equivalent to direct. Disk storage devices, but not tape, support indexed sequential,
VSAM, and direct organization. Chapters 26, 27, and 28 cover sequential, ISAM, and
VSAM, respectively.

ACCESS METHODS
An access method is the means by which the system performs input/output requests. The
methods depend on the file organizations and the file type of accessing required.
DOS supports four methods and OS supports seven. The latest implementation of z/OS,
which is the Operating System for the z/10 and z/11, probably support more.

Processing of External Storage Devices


Major similarities between tape and disk are that records may be of virtually any length, of
fixed or variable length, and clustered together into one or more records per block. It should
be mentioned that disk records are not partitioned into fixed length sectors, as is the case for
computers running MS–DOS or its equivalent, MS–Windows. When we discuss the logical
disk architecture as implemented by modern IBM Mainframe (Enterprise Server) computers,
we shall have occasion to mention again this logical record architecture.

Page 447 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

There are, however, two major differences in processing tape and disk. First, each time you
read or write, the tape drive starts, transfers the data, and then stops, whereas a disk drive
rotates continuously. The sole exception to this is the now obsolete external “floppy disk” in
which the disk rotation is discontinued after a period of inactivity in order to avoid wear on
the motor. The second difference is that update of records on tape involves rewriting of the
entire changed file on another reel of tape. Disk records can be updated in place, but the
mechanical problems of tape movement mean that in–place replacement of records is likely
to be error prone and should be avoided.
Identification of External Devices
Both disk and tape have unique ways of identifying their contents to help in locating files and
in protecting them from accidental erasure.
Tape file identification. At the beginning of the tape reel is a volume label, which is a
record that identifies the reel being used. Immediately preceding each file on the tape is a
header label, which describes the file that follows. This record contains the name of the file
(for example, INVENTORY FILE) and the date the file was created. Following the header
label are the records that comprise the data file.
The last record following the file is a trailer label, which is similar to the header label but
also contains the number of blocks written on the reel. The operating system automatically
handles the header and trailer labels.
Disk file identification. To keep track of all the files it contains, a disk device uses a special
directory (volume table of contents, VTOC) at the beginning of its storage area. The
directory includes the names of the files, their locations on disk, and their present status.
Packed and Binary Data
Tape and disk records can contain numeric fields defined as zoned, binary, or packed. Packed
format involves two digits per byte plus a half-byte for the sign, such as
PAYMENT DS PL4
In this case, the field length is 4 bytes, stored as dd | dd | dd | ds, where d is a digit and s is
the sign. If the field is defined as binary, watch out for erroneous alignment of the field when
you read it into main storage. The following binary fields are both 4 bytes long:
Aligned on a fulIword boundary: PAYMENT1 DS F
Not aligned on a boundary: PAYMENT2 DS FLA
The assembler automatically aligns PAYMENT1 on a fullword boundary, whereas the
assembler defines PAYMENT2 at its proper (unaligned) location.
Unblocked and Blocked Records
Disk and tape devices recognize blocks of data, which consist of one or more records. A
blank space, known as an interblock gap (IBG), separates one block from another. The
length of an IBG on tape is 0.3 to 0.6 inches depending on the device, and the length of an
IBG on disk varies by device and by track location. The IBG has two purposes: (I) to define
the start and end of each block of data and (2) to provide space for the tape when the drive
stops and restarts for each read or write of a block.

Page 448 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Records that are stored one to a block are called unblocked. As shown in Fig. 25-1(a),
following each block is an IBG.
To reduce the amount of tape and disk storage and to speed up input/output, you may specify
a blocking factor, such as three records per block, as shown in Fig. 25-1(b). In this format,
the system writes an entire block of three records from main storage onto the device.
Subsequently, when the system reads the file,it reads the entire block of three records from
the device into storage. All programs that subsequently read the file must specify the same
record length and block length. Blocking records makes better use of disk and tape storage
but requires a larger buffer area in main storage to hold the block.

Figure 25–1 (a) Unblocked records. (b) Blocked records


Input Buffers
The action of an input operation depends on whether records are unblocked or blocked. If
unblocked, the operation transfers one record (block) at a time from the device into the
input/output buffer in your program. The following example of blocked records assumes
three records per block. Initially, the input operation transfers the first block from the device
into the buffer (I/O area) in your program and delivers the first record to your program's
work area:

For the second input executed, the operation does not have to access the device. Instead, it
simply delivers the second record from the buffer into your program’s work area:

Page 449 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

And for the third input executed, the operation delivers the third record from the buffer to
your program’s work area:

While the program processes the third record in the work area, the system can read ahead and
transfer the second block (containing records 4, 5, and 6) from the device into the buffer in
your program. For the fourth input executed, the operation delivers the first record from the
buffer into your program’s work area:

Output Buffers
The action of an output operation depends on whether records are unblocked or blocked. If
unblocked, the output operation transfers one record (block) at a time from your work area to
the buffer in your program and then to the output device. The following example of blocked
records assumes three records per block. The first output operation writes the record in the
work area to the first record location in the output buffer, but not to the output device:

No actual physical writing to the output device occurs at this time. The second output
operation writes the record in the work area to the second record location in the buffer:

Similarly, the third output operation writes its record from the work area to the third record
location in the buffer. Now the buffer is full, the system can physically write the contents of
the buffer, this block of three records, to the external device.
The CLOSE operation automatically writes the last block of data to the output device. This
last block may validly contain fewer records than the blocking factor specifies; consider a
program that writes ten records with a blocking factor of three. When the CLOSE operation
is called, the buffer will contain one valid record (record 10) and two empty slots.
NOTE ADDED BY Ed Bosworth
There is some security advantage to having each physical write, including the last CLOSE,
completely clear the buffer before any additional logical writes take place.

Page 450 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Fixed-Length and Variable-Length Records


Records and blocks may be fixed in length, where each has the same length throughout the
entire file, or variable in length, where the length of each record and the blocking factor are
not predetermined. There are five formats:
1. Fixed, unblocked: one record of fixed length per block
2. Fixed, blocked: more than one fixed-length record per block
3. Variable, unblocked: one variable-length record per block
4. Variable, blocked: more than one variable-length record per block
5. Undefined: contents of no defined format
(Not all systems support this format.)
MAGNETIC TAPE STORAGE
The magnetic tape used in a computer system is similar to the tape used by conventional
audiotape recorders; both use a similar coating of metallic oxide on flexible plastic, and both
can be recorded and erased. Its large capacity and its reusability make tape an economical
storage medium.
Data records on tape are usually, but not necessarily, stored sequentially, and a program that
processes the records stints with the first record and reads or writes each record
consecutively.
The main users of tape are installations such as department stores and utilities that require
large files that they process sequentially. Many installations use disk for most general
processing and use tape for backing up the contents of the disk master files at the end of each
workday. Consequently, if it is necessary to rerun a job because of errors or damage, backup
tapes are always available.
Characteristics of Tape
The most common width of a reel of magnetic tape is 1/2 inch, and its length ranges from
200 feet to the common 2,400 feet, with lengths as long as 3,600 feet. A tape drive records
data as magnetic bits on the oxide side of the tape.
Storage format. Data is stored on tape according to tracks. The tape in Fig. 25–3 shows the
arrangement of a nine–track tape; it has nine horizontal tracks, each of which represents a
particular bit position. Each vertical set of 9 bits constitutes a byte, of which 8 bits are for
data and 1 bit is for parity. In the 1950’s and 1960’s, the seven–track format was also
popular, having six bits for data and 1 bit for parity. By the mid–1970’s, this format was
becoming unpopular, and seven–track tape
readers were hard to find.
The picture at left (Fig. 25–2) shows the first
magnetic tape drive produced by IBM. This was
the IBM 729, a 7–track device, first released in
1952. The novelty of the design is reflected by an
actual incident at the IBM receiving dock. The
designers were expecting a shipment of magnetic
tape when they were called by the foreman of the
dock with the news that “We just received a
shipment of tape from 3M, but are going to send
it back … It does not have any glue on it”

Page 451 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Figure 25–3 Data on Tape, with Bytes in Vertical Stripes


As you can see, the tracks for each of the bits are not in the expected sequence. The tracks
for bits 4 and 5, the least used, are in the outer area where the tape is more easily damaged.
The first byte, on the left, would appear in main storage as follows:
Bit Number 0 1 2 3 4 5 6 7 P
Bit Value 1 0 1 0 0 0 0 0 1
The data value stored in the byte is “1010 0000” or hexadecimal “A0”. The parity bit is set
for odd parity, in which each byte will be represented with an odd number of 1 bits in its
vertical stripe. Here, the data byte contains an even number of 1 bits, so P is set to 1.
Storage density. Tape density is measured by the number of stored characters, or bytes, per
inch (bpi), such as 800, 1,600, or 6,250 bpi. Therefore, a 2,400-foot reel with a recording
density of 1,600 bpi could contain 46 million bytes, which is equal to over a half-million
80-byte records. Double-density tape stores data on 18 tracks, representing 2 bytes for each
set of 18 vertical bits. This however is an unusual format.
Tape speed. Tape read/write speeds vary from 36 to 200 or more inches per second. Thus a
tape drive that reads 1,600 bpi records at 200 inches per second would be capable of reading
320,000 bytes per second. Other high-speed cartridge drives transfer data at up to 3 million
bytes per second.
Tape markers. A reflective strip, called a load point marker, located about 15 feet from the
beginning of a tape reel, indicates where the system may begin reading and writing data.
Another reflective strip, an end-of-tape marker, located about 14 feet from the end of the reel,
warns the system that the end of the reel is near and that the system should finish writing
data. Both the load point marker and the end-of-tape marker are on the side of the tape
opposite the recording oxide.
Tape File Organization
A file or data set on magnetic tape is typically stored in sequence by control field or key,
such as inventory number. For compatibility with disks, a reel of tape is know as a volume.
The simplest case is a one-volume file, in which one file is entirely and exclusively stored on
one reel (volume).

Page 452 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

An extremely large file, known as a multivolume file, requires more than one reel. Many
small files may be stored on a multifile volume, one after the other. The primary problem
here is that you may have to rewrite the entire reel just to update one of the files.
Unblocked and Blocked Tape Records
As an example of the effect of blocking records on tape, consider a file of 1,000 records each
800 bytes long. Tape density is 1,600 bytes per inch, and each IBG is 0.6 inches. How much
space does the file require given (a) unblocked records and (b) a blocking factor of 5?
Calculate the size of a record of 800 bytes as 800 / 1,600 = 0.5 inches.
(a) Unblocked records
One block = one record = 800 bytes
Length of one block = 800 bytes/1,600 bpi = 0.5”
Length of one mG = 0.6”
Space required for one block = 1.1"
Space required for file = 1,000 blocks x 1.1" = 1,100"
(b) Blocked records
One block = five records = 4;000 bytes
Length of one block = 4,000 bytes/1,600 bpi = 2.5"
Length of one IBG = 0.6”
Space required for one block = 3.1"
Space required for file = 200 blocks x 3.1" = 620"
As can be seen, the blocked records require considerably less space because there are fewer
Interblock Gaps.
Standard Labels
Under the various operating systems, tape reels require unique identification. Each reel, and
each file on a reel, usually contains descriptive standard labels supported by the operating
systems (1) to uniquely identify the reel and the file for each program that processes it and
(2) to provide compatibility with other IBM systems and (to some degree) with systems of
other manufacturers.
Installations typically use standard labels. Nonstandard labels and unlabeled tapes are
permitted but are not covered in this text. The two types of standard labels are volume and
file labels. Figure 25–4 illustrates standard labels for one file on a volume, a multivolume
file, and a multifile volume. In the figure, striped lines indicate IBGs, and TM (for tape mark)
is a special marker that the system writes to indicate the end of a file or the end of the reel.
Volume Labels
The volume label is the first record after the load point marker and describes the volume
(reel). The first 3 bytes contain the identification VOL. Although some systems support more
than one volume label, this text describes only the common situation of one label.
On receipt of a new tape reel, an operator uses an IBM utility program to write a volume
label with a serial number and a temporary header file label. When subsequently processing
the reel, the system expects the volume label to be the first record. it checks the tape serial
number against the number supplied by the job control command, TLBL under DOS
or DD under OS.

Page 453 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Figure 25–4 Magnetic Tape Standard Labels


The following describes each field in the 80–byte standard volume label:
Positions Name Description
01 – 03 Label identifier Contains the three characters “VOL” to
identify the label.
04 Volume label number Some systems permit more than one volume
label; this field contains their numeric sequence.
05 – 10 Volume serial number The permanent unique number assigned when
the reel is received. This number also becomes
the file serial number in the header label.
11 Volume security code A special security code supported by the OS
12 – 41 Unused Reserved for use by IBM.
42 – 51 Owner’s identification May be used under OS to identify the owner’s
name and address.
52 – 80 Unused Reserved/

File Labels
A tape volume contains a file of data, part of a file, or more tban one file. Each file has a
unique identification to ensure, for example, that the system is processing the correct file and
that the tape being used to write on is validly obsolete [presumably meaning that its contents
can be overwritten – ELB]. Two file labels for each file, a header label and a trailer label,
provide this identification.

Page 454 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

The following describes each field in the standard file label for both header and trailer labels.
(This table, accurate for the late 1970’s, must now be obsolete; note the two digit “yy” format
for the year number in the Creation Date and Expiration Date fields. – ELB)
Position Name Description
01 – 03 Label HDR if a header label, EOF if the end of a file,
identifier EOV if the end of a volume. Three EBCDIC characters.
04 File label Specifies the sequence of file labels for systems that support
number more than one. OS supports 2 labels each for
HDR, EOF, and EOV.
05 – 21 File identifier A unique name that identifies the file.
22 – 27 File serial The same identification as the volume serial number for the
number first or only volume of the file.
28 – 31 Volume sequence Sequence of volume numbers for multivolume files. The
number first volume for a file contains 0001, the second 0002, etc.
32 – 35 File sequence The sequence of file numbers for multifile volumes. The
number first file in a volume contains 0001, the second 0002, etc.
36 – 39 Generation Each time the system rewrites a file, it increments this
number number by 1 to identify the edition of the file.
40 – 41 Version number Specifies the version of the generation number of the file.
of generation (Whatever that means – ELB)
42 – 47 Creation Date The year and day when the file was written. Format is
“ yyddd”, with two digit year and 3 digit day number.
Note the leading blank, to make six characters.
48 – 53 Expiration Date The year and day when the file may be overwritten.
The format is identical to that for the creation date.
54 File security code A special security code used by OS.
55 – 60 Block count Used in trailer labels for the number of blocks since
the previous header label.
61 – 73 System code An identification for the operating system.
74 – 80 Unused Reserved, but probably now used to expand the year
numbers for Creation & Expiration date. Corrections for the
Y2K problem cannot invalidate older file formats.
Header label. A header label precedes each file. If the file requires more than one reel,
each reel contains a header label, numbered from 001. If a reel contains more than
one file, a header label precedes each file.
The header label contains HDR in the first 3 bytes; the file identification (such as
CUSTOMER RECORDS), the date the file may be deleted, and so forth. The system
expects a header label to follow the volume label immediately and checks the file
identification, date, and other details against information supplied by job control.
OS supports two header labels, HDRI and HDR2, with the second label, also 80 bytes,
immediately following the first. Its contents include the record format (fixed, variable, or
undefined), block length, record length, and density of writing on the tape.

Page 455 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Trailer label. A trailer label is the last record of every file. (OS supports two trailer labels.)
The first 3 bytes contain EOV if the file requires more than one reel and the trailer label is
the end of a reel but not end of the file. The first 3 bytes contain EOF if the trailer label is the
end of the file.
The trai1er label is otherwise identical to the header label except for a block count field. The
system counts the blocks as it writes them and stores the total in the trailer label.
Subsequently, when reading the reel, the system counts the blocks and checks its count
against the number stored in the trailer label.
IOCS FOR MAGNETIC TAPE
The system (IOCS for DOS and Data Management for OS) performs the following
functions for input and for output.
Reading a Tape File
The processing for reading a tape file is as follows:
1. Processing the Volume Label. On OPEN, IOCS reads the volume label and
compares its serial number to that on the TLBL or DD job control entry.
2. Processing the Header Label. IOCS next reads the header label and checks that
the file identification agrees with that on the job control entry to ensure that it is
reading the correct file. For a multivolume file, the volume sequence numbers
are normally in consecutive, ascending. sequence.
3. Reading Records. The GET macro reads records, specifying either a work area or IOREG.
If the tape records are unblocked, each GET reads one record (a block) from tape into
storage. If records are blocked, IOCS performs the required deblocking.
4. End-of-Volume. If IOCS encounters the end-of-volume label before the end–of–file
(meaning that the file continues on another reel), IOCS checks that the block count is correct.
It rewinds the reel, opens a reel on an alternate tape drive, checks the labels, and resumes
reading this new reel.
5. End-of-File. Each GET operation causes IOCS to transfer a record to the work area. Once
every record has been transferred and processed and you attempt to perform another GET,
IOCS recognizes an end-of-file condition. It then checks the block count, (usually) rewinds
the reel, and transfers control to your end-of-file address designated in the DTFMT or DCB
macro. You should now CLOSE the tape file. To attempt further reading of a rewound tape
file, you must perform another OPEN.
Writing a Tape File
The processing for writing a tape file is as follows:
1. Processing the Volume Label. On OPEN, IOCS checks the volume label (VOL) and
compares its serial number to the serial number (if any) on the job control entry.
2. Processing the Header Label. IOCS next checks the header label for the expiration date. If
this date has passed, IOCS backspaces the tape and writes a new header (HDR) over the old
one, based on data in job control. If this is a multivolume file, IOCS records the volume
sequence number for the volume. It then writes a tape mark.

Page 456 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

3. Writing Records. If the tape records are unblocked, each PUT writes one record (a block)
from tape into storage. If records are blocked, IOCS performs the required blocking.
4. End-of-Volume. If10CS detects the end-of-tape marker near the end of the reel, it writes
an EOV trailer label, which includes a count of all blocks written, followed by a tape mark.
Since the reflective marker is on the opposite side of the tape, data may be recorded through
its area. If an alternate tape drive is assigned, IOCS opens the alternate volume, processes its
labels, and resumes writing this new reel.
5. End-of-File. When a program closes the tape file, 10CS writes the last block of data, if
any. The last block may contain fewer records than the blocking factor specifies. IOCS then
writes a tape mark and an EOF trailer label with a block count. Finally, IOCS writes two tape
marks and deactivates the file from further processing.

DISK STORAGE
A direct access storage device (DASD), which includes magnetic disk storage and the less
common drum storage, is a device that can access any record on a file directly. Diskettes, a
common and familiar storage medium on micro- and minicomputers, store data in a similar
manner. This section describes the details of the larger magnetic disk devices used in data
processing installations. (ELB: Basically, a DASD is any device that can be addressed and
used as if it were a disk. Today, this might include USB Drives, which are formatted as disks
in order to facilitate their portability among computer systems. A CD–ROM, though called a
disk, is formatted and accessed more like a magnetic tape; it is not a DASD.
Historically, the first DASD built was a magnetic drum memory, which was invented in 1932
for use in early calculating machines. A drum is a large metal cylinder that is coated on the
outside surface with a ferromagnetic recording material. This surface is divided into parallel
tracks, each of which would resemble a circle, or line that encircles the cylinder. A row or
read–write heads runs along the axis of the drum, one for each track.
The figure below shows magnetic drums from two commercial firms, IBM and UNIVAC.
The magnetic drum on the left is one for the IBM 650, from about 1954. This drum was four
inches in diameter, 16 inches long, and stored 2,000 10–digit numbers (possibly 20 KB).
The drum rotated at 12,500 rpm. The drums on the right are probably variants of the Model
1124, made by UNIVAC beginning in about 1953. These would store between 18 KB and
36 KB on 133 to 270 parallel tracks. The picture on the right probably dates to 1958.

Figure 25–5 Magnetic Drum Memories

Page 457 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

The “golden era” of magnetic drum memories seems to have begun in the early 1950’s, when
they replaced the smaller and much more fragile Williams–Kilburn tubes, to the middle of
the 1960’s, when magnetic disk technology as we know it became more cost effective. The
technology persisted because it was useful; as late as 1980, PDP–11/45 computers that used
drums for swapping (management of virtual memory) were still in use.
The first commercial disk drive seems to have been the IBM 350, an integral part of the IBM
RAMAC 305 System (Random Access Method for Accounting and Control) introduced in
1956. The figure below shows two views, one showing the mechanism of the disk drive
itself and one showing the IBM 350 as a part of the RAMAC 305. The RAMAC disk had
fifty aluminum disks, each twenty–four inches in diameter. Its total storage capacity was
variously quoted at either 4.4 MB or five million characters. The disks spun at 1200 rpm,
yielding an average latency of 1/20 second), and transferred data at 8,800 characters per
second. According to IBM, the disk would store the equivalent of 64,000 punched cards.
The standard punched card of the time was the IBM 5081, which was usually 0.007 inches
thick. Thus the system would store about the same amount of data as 37 feet of cards, as
64,000  0.007 = 64,000  7/1000 = 64  7 = 448 inches = 37 feet, 4 inches.

Figure 25–6 Two Views of the IBM RAMAC: IBM 305 and IBM 350
Each disk storage device contains a number of thin circular plates (or disks) stacked one on
top of the other. Both sides of each plate (except the outer top and bottom on some devices)
have a coat of ferrous oxide material to permit recording. (ELB: Before the introduction of
the IBM “Winchester technology” in 1973, disk packs were often removed from the disk
drives. This resulted in possible damage to the outer top and outer bottom recording surface,
which were not used in order to avoid data corruption. A disk pack with six platters, as
shown in the figure below, would have either ten or twelve recording surfaces.
I have decided to include more on the history of this disk drive. This was officially named
the IBM 3340 Direct Access Storage Facility, but unofficially named “Winchester”. The
early design focused on two removable 30 megabyte disk modules; the name was selected
after the famous Winchester 30–30 rifle. The design was changed, but the code name stuck.
The significance of this technology was it was the first to package the disk packs, read heads,
and read arm assembly in a sealed unit that could be removed as a single module. With
reduced possibility of contamination of the recording surfaces of the disk, it became possible
to increase recording densities and use all of the available surfaces. The
IBM 3340 was introduced in March 1973 for use with the IBM System/370.)

Page 458 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

As Fig. 25–7 shows, each disk contains circular tracks for storing data records as magnetized
bits. Each track contains the same number of bits (and bytes) because the bits are spaced
more closely together on the innermost tracks. (ELB: Modern designs partition the surface
into a number of zones. Within each zone, each track contains the same number of bytes, but
tracks in an outer zone contain more bytes than those in an inner zone.)

Figure 25–7 Disk Surface and Tracks


The disks are constantly rotating on a vertical shaft. As Fig. 25–8 shows, the disk device has
a set of access arms that move read/write heads from track to track. The heads read data
blocks from a disk track into main storage and write data blocks from main storage onto a
disk track. Because the disks spin continually, the system has to wait for a required data
block to reach the read/write heads. (ELB: Note that this configuration does not use the top
surface of the top platter or the bottom surface of the bottom platter; it has six platters and ten
recording surfaces. A Winchester unit would use all twelve surfaces.)

Figure 25–8 Disk read/write mechanism (Non Winchester)


Disk storage devices permit processing of records both sequentially and randomly (directly).
As a result, programs can read unsorted records from a transaction file and use them to
randomly update matching master records on disk. Disk storage therefore facilitates online
processing where users can at any time make inquiries into a file and can enter transactions
for updating as they occur.
(ELB: There are two factors of importance when considering a disk: maximum transfer rate
and disk access times. The maximum transfer rate is computed simply: it is the number of
bytes on a disk track divided by the time to read the entire track. Consider a disk rotating at
15,000 rpm, or one revolution every 1/250 = 0.004 second. If the track holds 4 MB of data,
the transfer rate is 4MB /0.004 second = 1 GB/second.

Page 459 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Times of importance when assessing disk speed, the average latency and the track access
time, commonly called “seek time”. The latency is computed as the time for the disk to spin
one half of a turn; if the read/write heads are on the correct track, this is the average wait time
for the desired sector to rotate under the heads. For example, a disk rotating at 12,000 rpm
would make 200 revolutions per second. This corresponds to 5 milliseconds per revolution
or an average latency of 2.5 milliseconds.
The track access time is that time to move the heads from one track to another. Remember
that each disk surface is divided into a number of concentric circles, called tracks. There are
two times routinely quoted: move to next track, and move to average track. The first is the
time to move the read/write heads to an adjacent track; the second is the average time to
move from any one track to any other track. The two measures typically yield similar values,
with 2 milliseconds being seen in high–end servers, and 15 milliseconds being common for
standard servers. Common systems quote an average seek time of 9 milliseconds.
The final topic in this aside is the concept of a cylinder. It is best defined by illustration.
Consider Figure 25–8 above, in which the disk drive is shown as having ten usable recording
surfaces. The read/write heads move as a unit, so that a single move places each of the ten
heads on a specific track on its recording surface. The collection of these tracks is called a
cylinder. The cylinder, comprising one track per recording surface, is the set of all disk
sectors that can be read without physically moving the read/write heads.)
Disk Format
The amount of data that a disk device can store varies considerably by model, ranging from
small disks with a few million bytes to large disks with more than one billion bytes. Some
disk models use fixed-length sectors on each track to store one or more records; the system
addresses a record by disk number, track number, and sector number. On other disk models,
tracks are not sectored, and records may be of almost any length; the system addresses
records by disk surface number and track number.
Like magnetic tape, disk storage contains gaps between one block of data and the next, but
the size of the gap is greater on the outermost tracks and smaller on innermost tracks. You
may also store records on disk as unblocked or blocked. However, because of the fixed
capacity of a disk track, the optimum blocking factor depends on the record length and track
capacity. Special formulas are available for calculating optimum blocking factors for
different disk devices.
(ELB: The design suggested in Figure 25–7 calls for each track to hold the same number of
bits. More specifically, every track holds the same number of sectors, and each sector holds
the same number of bits. The sectors, hence bits, are more densely packed on the inner
tracks than the outer tracks, which have greater linear circumference. Thus, the linear
density is specified by the maximum density allowable on the innermost track; the outer
tracks may be viewed as being “under–populated”. Having a fixed number of sectors per
track greatly simplifies the design of the disk controller, but leads to excess unused capacity.
A more modern design divides the tracks into a number of zones, each holding a number of
tracks with the same number of sectors per track. However, an outer zone will have more
sectors per track than an inner zone. This allows more efficient use of the linear density of
each of the zones, while allowing for a relatively simple disk controller.)

Page 460 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Figure 25–9 Multiple Zones Increase Disk Density


In the above figure, the disk surface is divided into three zones, each zone having a constant
number of sectors per track contained. This allows a better use of linear track density, while
maintaining a reasonably simple disk controller.)
As a simplified example, consider a file containing 1,000–byte records and a disk track with
a capacity of 10,000 bytes. If the blocking factor is 5, one block is 5,000 bytes and you can
store two blocks (ten records) on a track. If the blocking factor is 6, one block is 6,000 bytes
and a track has space for only one block (six records).
The storage of data on disk begins with the top outermost track (track 0) and continues
consecutively down, surface by surface, through to the bottom outermost track. Storage of
data then continues with the next inner set of tracks (track 1), starting with the top track
through to the bottom track. The set of vertical tracks is known as a cylinder. As a result, for
sequential processing the system reduces access motion of the read/write heads: It reads and
writes blocks, for example, on track 5 of every surface (cylinder 5) before moving the arm.

DISK ARCHITECTURE
The two main types of IBM disk devices are count–key–data (CKD) architecture and
fixed–block architecture (FBA). (ELB: There is an interesting design compromise that
appears on later disks, such as more recent implementations of the IBM 3390 that continue to
use the CKD architecture. The newer devices implementing the 3390 architecture are
actually large RAID (Redundant Array of Independent Disks) arrays, each of which
implements the FBA architecture that is common among disks for commodity computers,
such as the Intel x86 and Intel Pentium servers that are quite common.
The 3390 controller has an interface that allows it to appear to the Mainframe Computer
(such as a z/11) as a CKD architecture while actually using FBA devices, which are very
reliable, but commodity market, and therefore less expensive. This design choice shows how
IBM has evolved to maintain its architecture while using commodity items.)
CKD Architecture
In this design, records and blocks may be of almost any length, subject to limitations of the
disk device. A count (C) area contains the block size and an optional key (K) area contains
the key of the last record in the block, both of which precede the actual data (D) area; hence
CKD. If a disk contains 20 surfaces, the outer set of tracks (all track 0) is called cylinder 0,
the next inner vertical set of tracks is cylinder 1, the next is cylinder 2, and so forth. If the
device contains 200 sets of tracks, there are 200 cylinders numbered 0 through 199, each
with 20 tracks. If a disk contains 20 surfaces, each cylinder contains 20 tracks. If the disk
contains 200 cylinders, then each surface contains 200 sets of tracks.

Page 461 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Examples of disk devices using CKD architecture include IBM models 3330, 3340, 3350,
and 3380. The basic format for a track on a CKD device is
Index Point Home Address Track Descriptor Data Data
Record Record (R1) Record (R2)
(a) (b) (c) (d)
(a) Index Point. The index point tells the read/write device that this point is the physical
beginning of the track.
(b) Home Address. The home address tells the system the address of the track (the cylinder,
head, or surface number) and whether the track is primary, alternate, or defective.
(c) Track Descriptor Record (R0). This record stores information about the track and
consists of two separate fields: a count area and a data area. The count area contains 0 for
record number and 8 for data length and is otherwise similar to the count area described next
for data record under item (d). The data area contains 8 bytes of information used by the
system. The track descriptor record is not normally accessed by user programs.
(d) Data Record Formats (Rl through Rn). The users' data records, or technically, blocks,
consist of the following:
Address Count Key Data
Marker Area Area Area
(optional)
The I/O control unit stores the 2-byte address marker before each block of data, which it uses
subsequently to locate the beginning of data. The count area includes the following:
• An identifier field that provides the cylinder and head number (like that in the home
address) and the sequential block number (0-255) in binary, representing R0 through
R255. (The track descriptor record, R0, contains 0 for record number.)
• The key length (to be explained shortly).
• The data length, a binary value 0 through 65,535 that specifies the number of bytes in the
data area field (the length of your data block). For end–of–file, the system generates a
last dummy record containing a length of 0 in this field. When the system reads the file,
the zero length indicates that there are no more records.
• The optional key area contains the key, or control field, for the records in the file, such
as part number or customer number. The system uses the key area to locate records
randomly. If the key area is omitted, the file is said to be formatted without keys and is
stored as count-data format. The key length in the count area contains O. If the file is
formatted with keys, it is stored as count-data format. The key length in the count area
contains the length of the key area.
• The data area contains the users' data blocks, in any format, such as unblocked or blocked
and fixed or variable length. The system stores as many blocks on a track as possible,
usually complete and intact on a track. A record overflow feature permits the overlapping
of a record from one track to the next. Figure 25–10 provides the capacities and speeds
of a number of IBM CKD devices.
Figure 25–11, added in 2009, shows more modern disks.

Page 462 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Under normal circumstances, you won't be concerned with the home address, the track
descriptor record, or the address marker, count area, and key area portions of the data record
field. You simply provide appropriate entries in your file definition macros and job control
commands.

Figure 25–10 Capacity Tables for CKD Devices

Figure 25–11 DASD Speeds and Data Rates, November 2009

Fixed–Block Architecture
In this design, the recording tracks contain equal–length blocks of 512 bytes, although your
records and blocks need not fit a sector exactly. (ELB: This is the format commonly
used by MS–DOS and MS–Windows file systems).
Device Bytes/block Blocks/track Number of Tracks per Total
Cylinders Cylinder Bytes
3310 512 32 358 11 64, 520, 192
3370 512 64 2 of 750 12 571, 392, 000

Page 463 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

Disk Capacity
Knowing the length of records and the blocking factor, you can calculate the number of
records on a track and on a cylinder. Knowing the number of records, you can also calculate
the number of cylinders for the entire file. Based on the values in Figure 25–12, the formula
for the number of blocks of data per track is

In the formula, C is a constant overhead value for keyed records, KL means Key Length, and
DL is Data (Block) Length. These values vary by disk device, as shown below.

Figure 25-12 Track Capacity Table


The following two examples illustrate.
Example 1: Device is a 3350, records are 242 bytes, five records per block,
(block size = 1,210), and formatted without keys.

Example 2: Same as Example 1, but formatted with keys (key length is 12).

Note that a disk stores a full block, not a fraction of one. Therefore, even if you calculate
13.8 or 12.9 blocks per track, the disk stores only 13 or 12 blocks, respectively.
To determine the number of records on a cylinder, refer to Fig. 25–10, which discloses that a
3350 has 30 tracks per cylinder. Based on Example 1 where the number of records per track
is 65, a cylinder on the 3350 could contain 65 x 30 = 1,950 records.
Using these figures, you can now calculate how much disk storage a file of, say, 100,000 of
these records would require. Based on the figure of 1,950 records per cylinder, the file would
require 100,000  1,950 = 51.28 cylinders.

DISK LABELS
Disks, like magnetic tape, also use labels to identify a volume and a file. The system reserves
cylinder 0, track 0 for standard labels, as Fig. 25–13 shows.

Page 464 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

The following describes the contents of track 0:


Record 0: The track descriptor, R(0) record.
Records 1 and 2: If the disk is SYSRES, which contains the operating system, certain
devices reserve R(l) and R(2) for the Initial Program Load (IPL) routine.
For all other cases, R(l) and R(2) contain zeros.
Record 3: The VOL1 label. OS supports more than one volume label, from
R(3) through R(10).
Record 4 through the end of the track: The standard location for the volume table of
contents (VTOC). The VTOC contains the file labels for the files on the device. Although
you may place a VTOC in any cylinder, its standard location is cylinder 0, track 0.

Figure 25–13 Disk Volume Layout


Volume Labels
The standard volume label uniquely identifies a disk volume. A 4–byte key area immediately
precedes the 80–byte volume data area. The volume label is the fourth record (R3) on
cylinder 0. The 80 bytes are arranged like a tape volume label, with one exception: Positions
12-21 are the "data file directory," containing the starting address of the VTOC.

File Labels
File labels identify and describe a file, or data set, on a volume. The file label is 140 bytes
long, consisting of a 44–byte key area and a 96–byte file data area. Each file on a volume
requires a file label for identification. In Fig. 25–13, all file labels for a volume are stored
together in the VTOC. There are four types of file labels:
1. The format 1 label is equivalent to a file label on tape. The format 1 label differs, however,
in that it defines the actual cylinder and track addresses of each file's beginning and end (its
extent). Further, a file may be stored intact in an extent or in several extents in the same
volume. Format 3 is used if a file is scattered over more than three extents.
2. The format 2 label is used for indexed sequential files.
3. The format 3 label is stored if a file occupies more than three extents.
4. The format 4 label is the first record in the VTOC and defines the VTOC for the system.

Page 465 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

The format 1 file label contains the following information:


Position Name Description
01 – 44 File Identification Unique identifier consisting of the file ID, optional
generation number, and version number. These fields
are separated by periods.
45 Format Identifier ‘1’ for format 1
46 – 51 File Serial Number Volume serial number from the volume label.
52 – 53 Volume sequence Sequence number if the file is stored on
number more than one volume.
54 – 56 Creation date Three bytes: ydd. y = year (0 – 99) and
dd = day (1 – 366). Not Y2K compliant
57 – 59 Expiration date Same as format for creation date.
60 Extent count Number of extents for this file on this volume.
number
61 Bytes in last block Used by OS.
of directory
62 Unused Reserved
63 – 75 System code Name of the operating system (OS)
76 – 82 Unused Reserved
83 – 84 File Type Code to identify is SD (sequential), DA (direct),
or IS (indexed) file organization.
85 Record Format Used by OS
86 Option Codes ISAM – indicates if master index is
present and type of overflow area.
87 – 88 Block Length ISAM – length of each block.
89 – 90 Record Length ISAM – length of each record.
91 Key Length ISAM – length of key area.
92 – 93 Key Location ISAM – position of key within the record
94 Data Set SD – indicates if last volume
Indicators
95 – 98 Used by OS None of your business.
99 – 103 Last record pointer Used by OS
104 – 105 Unused Reserved
106 Extent type
107 Extent sequence
Descriptors for the first or only
number
extent for the file. Ten bytes.
108 – 111 Extent lower limit
112 – 115 Extent upper limit
116 – 125 Descriptors for a second extent. Same format
as the firs extent, described in positions 106 – 115.
126 – 135 Descriptors for a third extent. Same format as above.
136 – 140 Pointer Address of the next label.

Page 466 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler External Storage

KEY POINTS
• Sequential file organization provides only for sequential processing of records. Indexed and
direct organization provides for both sequential and random processing of records.
• At the beginning of the tape reel is a volume label, which identifies the reel being used.
Immediately preceding each file on the tape is a header label, which contains the name of
the file and the date the file was created. Following the header label are the records that
comprise the data file. The last record is a trailer label, which is similar to the header label
but also contains the number of blocks written on the reel.
• To keep track of all the files it contains, a disk device uses a special directory (volume table
of contents, VTOC) at the beginning of its storage area. The directory includes the names
of the files, their locations on disk, and their present status.
• If you define a tape or disk field as packed on an IBM system, the field contains
two digits per byte plus a half-byte for the sign.
• The set of vertical tracks on a disk device is known as a cylinder.
• An interblock gap (IBG) separates each block of data from the next on tape and disk. The
length of an IBG on tape is 0.3 to 0.6 inches depending on the device, and the length of an
IBG on disk varies by device and by track location. The IBG defines the start and end of
each block of data and provides space for the tape when the drive stops and restarts for
each read or write.
• Blocking of records helps conserve space on storage devices and reduces the number of
input/output operations. The number of records in a block is known as the blocking factor.
• The system reads an entire block into the computer's storage and transfers one record
at a time to the program.
• All programs that process a file should use the same record length and blocking factor.
• Records and blocks may be fixed in length, where each has the same length throughout the
entire file, or variable in length, where the length of each record and the blocking factor
are not predetermined.
• The two main types of disk devices are count-key-data (CKD) architecture, which stores
records according to count, key, and data area, and fixed-block architecture (FBA), which
stores data in fixed-length blocks.

Page 467 Chapter 25 Revised January 5, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 26: Sequential File Organization

Author’s Note: This chapter is copied almost verbatim from the material in
Chapter 18 of the textbook by Peter Abel. It is used by permission.
In this chapter, you examine sequential file organization for DOS and OS and learn how to
create and read such files. You will also examine the definition and processing of variable-
length records.
The processing of sequential files involves the same imperative macros used up to now:

al
OPEN, CLOSE, GET, and PUT. IOCS (data management) handles all the necessary label
processing and blocking and deblocking of records. Other than job control commands, the

i
only major difference is the use of blocked records.

com Tr
An installation has to make a (perhaps arbitrary) choice of a blocking factor when a file is
created, and all programs that subsequently process the file define the same blocking factor.
A program may also define one or more I/O buffers; if records are highly blocked, a second
buffer involves more space in main storage with perhaps little gained in processing speed.

rd. F
CREATING A TAPE FILE
iza D
The first two examples create a tape file for DOS and OS. The programs accept input data
from the system reader and write four records per block onto tape.
dfw P
For both programs, OPEN checks the volume label and header label, and CLOSE writes the
last block (even if it contains fewer than four records) and writes a trailer label.
w.p m

DOS Program to Create a Tape File


The DOS DTFMT file definition macro defines a magnetic tape file. You define a DTFMT
macro with a unique name for each tape input or output file that the program processes. The
ww Co

parameters that you code are similar to those for the DTFCD and DTFPR macros.
In Fig. 26–1, the program reads records into RECDlN and transfers required fields to a tape
work area named TAPEWORK. The program then writes this work area to a tape output file
named FILOTP. Based on the BLKSIZE entry in the DTFMT, IOCS blocks four records
cu

before physically writing the block onto tape. Thus for every four input records that the
program reads, IOCS writes one block of four records onto tape.
The following explains the DTFMT entries:
Do

BLKSIZE=360 means that each block to be written from the IOAREA is 360 bytes long,
based on four records at 90 bytes each.
DEVADDR= SYS025 denotes the logical address of the tape device to write the file.
FILABL = STD indicates that the tape file contains standard labels, described in Chapter 25.
IOAREAl and IOAREA2 are the two IOCS buffers, each defined with the same length
(360) as BLKSIZE. If your blocks are especially large, you may omit defining a second
buffer to reduce program size.
RECFORM=FIXBLK defines output records as fixed-length and blocked. Records on
tape and disk may also be variable–length or unblocked.

Page 468 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
RECSIZE= 90 means that each fixed-length record is 90 bytes in length, the same as the
work area.
TYPEFLE=OUTPUT means that the file is output, that is, for writing only. Other
options are INPUT and WORK (for a work file). .
WORKA=YES means that the program is to process output records in awork area. In
this program, TAPEWORK is the work area and has the same length as RECSIZE, 90
bytes. Alternatively, you may code IOREG and use the macro PUT FILEOTP with no
work area coded in the operand.

al
The DTFMT file definition macro for tape input requires an entry EOFADDR=address
to indicate the name of the routine where IOCS links on reaching the end of the tape file.

com Tr
i
OS Program to Create a Tape File
For OS, you define a DCB macro with a unique name for each tape input or output file
that the program processes. The parameters that you code are similar to those for the
DCB macros covered earlier.

rd. F
In Fig. 26–2, the program reads records into RECDIN and transfers required fields to a
tape work area named TAPEWORK. The program then writes this work area to a tape
iza D
output file named FILOTP. Based on the BLKSIZE entry in job control, the system
blocks four records before physically writing the block onto tape. Thus for every four
dfw P
input records that the program reads, the system writes one block of four records.
The DD job commands for the files appear first in the job stream and provide some entries
that could also appear in the DCB. This common practice enables users to change entries
w.p m

without reassembling programs. The DD entries for the tape file, TAPEOT, are as follows:
DSNAME=TRFILE provides the data set name.
ww Co

DISP=(NEW,PASS) means that the file is new (to be created) and is to be kept temporarily.
Note that “(NEW,PASS)” is written without spaces.
UNIT=3420 provides the tape drive model.
cu

BLKSIZE=360 means that each block to be written from-the IOAREA is


360 bytes long, based on four records at 90 bytes each.
RECFM=FB defines output records as fixed–length and blocked. Records on tape and disk
Do

may also be variable–length (V) or unblocked.


DEN= 3 indicates tape density as 1,600 bpi. (DEN=2 would mean 800 bpi.)

Page 469 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The following explains the DCB entries:
DDNAME=TAPEOT relates to the same name in the DD job control command:
//GO.TAPEOT …
DSORG= PS defines output as physical sequential.
LRECL=90 provides the logical record length for each record.
MACRF=(PM) defines the type of output operation as put and move from a work area.
MACRF=(PL) would allow you to use locate mode to process records directly in the

al
buffers.
The DCB file definition macro for tape input requires an entry EOFADDR=address to

i
indicate the name of the routine where IOCS links on reaching the end of the tape file.

com Tr
Also, another DCB entry, EROPT, provides for an action if an input operation encounters
problems. The options are as follows:
=ACC Accept the possibly erroneous block of data.

rd. F
=SKP Skip the data block entirely and resume with the next one.
=ABE
iza D
Abend (abnormal end of program execution), the standard default
if you omit the entry.
dfw P
ACC and SKP can use a SYNAD entry for printing an error message and continue
processing. If the error message routine is named RIOTPERR, the DCB coding could be
EROPT=SKP,
w.p m

SYNAD=Rl0TPERR
Since the use of ACC and SKP may cause invalid results, it may be preferable for important
ww Co

production jobs to use ABE (or allow it to default). See the OS supervisor manuals for other
DCB options.
Figures 26–1 and 26–2 now follow, one per page.
The rest of this page is left blank.
cu
Do

Page 470 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 26 – 1 Program: Writing a Tape File under DOS

Page 471 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 26 – 2 Program: Writing a Tape File under OS

Page 472 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
CREATING A SEQUENTIAL DISK FILE
The next two examples create a disk file for DOS and OS. The programs accept input data
from the system reader and write four records per block onto disk. For both programs,
OPEN checks the disk label, and CLOSE writes the last data block (even if it contains fewer
than four records) and writes a last dummy block with zero length.

DOS Program to Create a Sequential Disk File


The DOS file definition macro that defines a sequential disk file is DTFSD. The parameters
that you code are similar to those for the DTFMT macro.

al
The program in Fig. 26–3 reads the tape records from the file created in Fig. 26–1 and
transfers required fields to a disk work area named DISKWORK. The program then writes

i
this work area named SDISK. Based on the BLKSIZE entry in the DTFMT and DTFSD, the

com Tr
system both reads and writes blocks of four records, though the blocking factor need not be
the same. The following explains the DTFSD entries.
BLKSIZE=368 means that the block size for output is 360 bytes (4 x 90) plus 8 bytes for the
system to construct a count field. You provide for the extra 8 bytes only for output; for input,

rd. F
the entry would be 360.

iza D
DEVICE= 3380 means that the program is to write blocks on a 3380 disk device.
VERIFY = YES tells the system to reread each output record to check its validity. If the
dfw P
record when reread is not identical to the record that was supposed to be written, the system
rewrites the record and performs another reread. If the system eventually cannot perform a
valid write, it may advance to another area on the disk surface. Although this operation
w.p m

involves more accessing time, it helps ensure the accuracy of the written records.
DEVADDR, IOAREA1, RECFORM, RECSIZE, TYPEFLE, and WORKA are the same
as for previous D1Fs. You omit the FILABL entry because disk labels must be standard. If
ww Co

you omit the entry for DEVADDR, the system uses the SYSnnn address from the job control
entry.
cu
Do

Page 473 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 26–3 Program: Writing a sequential disk file under DOS

Page 474 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 26–4 Program: Writing a sequential disk file under OS

Page 475 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
OS Program to Create a Sequential Disk File
For OS, you define a DCB macro with a unique name for each disk input or output file that
the program processes. The parameters that you code are similar to those for the DCB macros
covered earlier.
The program in Fig. 26–4 reads the tape records from the file created in Fig. 26–2 and
transfers required fields to a disk work area named DISKWORK. The program then writes
this work area to a disk output file named SDISK. Based on the BLKSIZE entry in job
control, the system both reads and writes blocks of four records, although the two blocking

al
factors need not be the same.
The DD entries for the disk file, DISKOT, are as follows:

i
DSNAME=&TEMPDSK provides the data set name.

com Tr
DISP=(NEW,PASS) means that the file is new and is to be kept temporarily.
UNIT= 3380 provides the disk drive model.
SPACE= (TRK,10) allocates ten tracks for this file.

rd. F
BLKSIZE= 360 means that each block to be written from the buffer is 360

iza D
bytes long, based on four records at 90 bytes each.
RECFM= FB defines output records as fixed-length and blocked. Records on disk may also
dfw P
be variable-length (V) or unblocked.
The following explains the DCB entries:
w.p m

DDNAME=DISKOT relates to the same name in the DD job control command:


//GO.DISKOT
ww Co

DSORG=PS defines output as physical sequential.


LRECL= 90 provides the logical record length for each record.
MACRF=(PM) defines the type of output operation as put and move from a work area.
cu

MACRF=(PL) would allow you to use locate mode to process records directly in the buffers.
The DCB file definition macro for disk input requires an entry EOFADDR=address to
indicate the name of the routine where the system links on reaching the end of the disk file.
Do

VARIABLE-LENGTH RECORDS
Tape and disk files provide for variable-length records, either unblocked or blocked. The use
of variable-length records may significantly reduce the amount of space required to store a
file. However, beware of trivial applications in which variations in record size are small or
the file itself is small, because the system generates overhead that may defeat any expected
savings. A record may contain one or more variable–length fields or a variable number of
fixed–length fields.
1. Variable–Length Fields. For fields such as customer name and address that vary
considerably in length, a program could store only significant characters and delete trailing
blanks. One approach is to follow each variable field with a special delimiter character such
as an asterisk.

Page 476 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
The following example illustrates fixed-length name and address of 20 characters each,
compressed into variable length with an asterisk replacing trailing blanks:
Fixed length: Norman Bates Bates Motel
Variable length: Norman Bates*Bates Motel*
(ELB – Does anybody remember the Alfred Hitchcock movie Psycho?)
To find the end of the field, the program may use a TRT instruction to scan for the delimiter.
Another technique stores a count of the field length immediately preceding each variable-

al
length field. For the preceding record, the count for the name would be 12 and the count for
the address would be 11: |12|Norman Bates|11|Bates Motel|

i
2. Variable Number of Fixed-Length Fields. Records may contain a variable number of

com Tr
fields. For example, an electric utility company may maintain a large file of customer records
with a fixed portion containing the customer name and address and optional subrecords for
their electric account, natural gas account, and budget account.

rd. F
VARIABLE·LENGTH RECORD FORMAT
Immediately preceding each variable-length record on tape or disk is a 4-byte record control

iza D
word (RCW) that supplies the length of the record. Immediately preceding each block is a 4-
byte block control word (BCW) that supplies the length of the block. As a consequence, both
dfw P
records and blocks may be variable length. You have to supply a maximum block size into
which the system is to fit as many records as possible.

Unblocked Records
w.p m

Variable-length records that are unblocked contain a BCW and an RCW before each block.
Here are three unblocked records:
ww Co

|BCW|RCW|Record 1|•••|BCW|RCW|Record 2|•••|BCW|RCW|Record 3|


Suppose that three records are to be stored as variable-length unblocked. Their lengths are
310, 260, and 280 bytes, respectively:
cu
Do

The RCW contains the length of the record plus its own length of 4. Since the first record has
a length of 310, its RCW contains 314. The BCW contains the length of the RCW(s) plus its
own length of 4. Since the only RCW contains a length of 314, the BCW contains 318.

Blocked Records
Variable-length records that are blocked contain a BCW before each block and an RCW
before each record. The following shows a block of three records:
|BCW|RCW|Record 1|BCW|RCW|Record 2|BCW|RCW|Record 3|

Page 477 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Suppose that the same three records with lengths of 310, 260, and 280 bytes are to be stored
as variable-length blocked and are to fit into a maximum block size of 900 bytes:

The length of the block is the sum of one BCW, the RCWs, and the record lengths:
Block control word: 4 bytes

al
Record control words: 12
Record lengths: + 850
Total length: 866 bytes

com Tr
i
The system stores as many records as possible in the block up to (in this example) 900 bytes.
Thus a block may contain any number of bytes up to 900, and both blocks and records are
variable length. The system automatically handles all blocking, unblocking, and control of
BCWs.

rd. F
Your BLKSIZE entry tells the system the maximum block length. For example, if the
BLKSIZE entry in the preceding example specified 800, the system would fit only the first

iza D
two records in the block, and the third record would begin the next block.
dfw P
Programming for Variable-Length Records
Although IOCS performs most of the processing for variable–length records, you have to
provide the record length. The additional programming steps are concerned with the record
and block length:
w.p m

Record length. As with fixed-length records, a program may process variable–length records
in a work area or in the buffers (I/O areas). You define thework area as the length of the
ww Co

largest possible record; including the 4–byte record control word. When creating each record,
calculate and store the record length in the record control word field. This field must be 4
bytes long, with the contents in binary format, as
VARRCW DS F
cu

DOS uses only the first 2 bytes of this field.


Block length. You define the I/O area as the length of the largest possible block, including
Do

the 4-byte block control word. On output, IOCS stores as many complete records in the block
as will fit. IOCS performs all blocking and calculating of the block length. On input, IOCS
deblocks, all records, similar to its deblocking of fixed-length records.
Sample Program: Reading and Printing Variable-Length Records
Consider a file of disk records that contains variable-length records, with fields defined as
follows:
01-04 Record length
05-09 Account number
10-82 Variable name and address

Page 478 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
To indicate the end of a name, it is immediately followed by a delimiter, in this case a plus
sign (hex ‘4E’). Another delimiter terminates the next field, the address, and a third
terminates the city. Here is a typical case:
JP Programmer+1425 North Basin Street+Kingstown+
The program in Fig. 26–5 reads and prints these variable-length records. Note that in the
DTFSD, RECFORM= VARBLK specifies variable blocked. The program reads each input
record and uses TRT and a loop to scan each of the three variable-length fields for the record
delimiter. It calculates the length of each field and uses EX to move each field to the output

al
area. The program also checks for the absence of a delimiter.
Output would appear as

i
JP Programmer

com Tr
1425 Horth Basin Street
Kingstown
The DTFSD omits RECSIZE because IOCS needs to know only the maximum block length.

rd. F
For OS, the DCB entry for variable blocked format is RECFM= VB. You could devise some
records and trace the logic of this program step by step.


iza D KEY POINTS
dfw P
Entries in a program file definition macro should match the job control commands.
 The block size for a file must be a multiple of record size, and all programs
that process the file must specify the same record and block size.
w.p m

 For variable-length files, the work areas and buffers should be aligned on an
even boundary. When creating the file, you calculate and store the record
ww Co

length, whereas the system calculates the block length. Your designated
maximum block size must equal or exceed the size of any record.
cu
Do

Page 479 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 26–5 Program: Printing variable–length records

Page 480 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
i al
com Tr
rd. F
iza D
dfw P
Figure 26–5 Program: Printing variable–length records (Continued)
w.p m
ww Co
cu
Do

Page 481 Chapter 26 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 27: Indexed Sequential Access Method (ISAM)

Author’s Note: This chapter is copied almost verbatim from the material in
Chapter 20 of the textbook by Peter Abel. It is used by permission.
Indexed sequential access method (ISAM) is available in many variations on
microcomputers, minicomputers, and mainframes, although the preferred method
under DOS/VS and OS/VS is the newer VSAM. (ELB: It is a fact that VSAM, to
be discussed in the next chapter, can perform all of the services of ISAM. For this

al
reason, many instructors prefer not to cover ISAM, but skip to VSAM. ISAM is
included for historical reasons.)

i
A significant way in which ISAM (and other nonsequential file organization methods)

com Tr
differs from sequential organization is that the record keys in an indexed file must be
unique; this is a system requirement, not just a programming practice. Consequently, an
indexed file is typically a master file. Also, there is a clear difference between updating a
sequential file and updating an indexed file. When you update a sequential file, you rewrite

rd. F
the entire file; this practice leaves the original file as a convenient backup in case the job
must be rerun. When you update an indexed file, the system rewrites records in the file

iza D
directly in place, thereby providing no automatic backup file. To create a backup, you
periodically copy the file onto another device.
dfw P
The flexibility of indexed sequential access method is realized at some cost in both storage
space and accessing time. First, the system requires various levels of indexes to help locate
records in the file. Second, the system stores new, added records in special reserved
w.p m

overflow areas. Check that your system supports ISAM before attempting to use it.

CHARACTERISTICS OF INDEXED SEQUENTIAL FILES


ww Co

ISAM initially stores records sequentially and permits both sequential and random
processing. The features that provide this flexibility are indexes to locate a correct
cylinder and track and keys to locate a record on a track.
Keys
cu

A key is a record control field such as customer number or stock number. Records in an
indexed file are in sequence by key to permit sequential processing and to aid in locating
records randomly, and blocks are formatted with keys. That is, ISAM writes each block
Do

immediately preceded by the highest key within the block, namely, the key of the last or only
record in the block. The key is usually also embedded within each data record, as normal.
Unblocked Records
This is the layout of keys for unblocked records:
Key 201 Record 201 Key 205 Record 205 Key 206 Record 206
The records could represent, for example, customer numbers, and the keys could be for
customer numbers 201, 20S, and 206. In this example, the key is 3 characters long and the
data record is the conventional size. Under unblocked format, a key precedes each block
containing one record.

Page 482 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

Blocked Records
This is the layout of keys for blocked records based on the preceding unblocked example:
Key 206 Record 201 Record 205 Record 206
Under blocked format, the key for the last record in the block, 206, precedes the block.
ISAM automatically handles this use of keys, and when you perform a read operation,
the system delivers the block, not the separate key, to main storage.
Indexes

al
To facilitate locating records randomly, ISAM maintains three levels of indexes on disk:
track index, cylinder index, and an optional master index.

i
Track index. When ISAM creates a file, it stores a track index in track 0 of each cylinder

com Tr
that the file uses. The track index contains the highest key number for each track on the
cylinder. For example, if track 4 on cylinder 12 contains records with keys 201,205,206,
and 208, the track index contains an entry for key 208 and a reference to cylinder 12, track 4.
If a disk device has ten tracks per cylinder, there are ten key entries for each track index, in

rd. F
ascending sequence.
Cylinder index. When ISAM creates a file, it stores a cylinder index on a separate cylinder
iza D
containing the highest key for each cylinder. For example, if the file is stored on six
cylinders, the cylinder index contains six entries.
dfw P
Master index. An optional master index facilitates locating an appropriate cylinder index.
This index is recommended if the entries in the cylinder index exceed four cylinders,
which is a very large file.
w.p m

PROCESSING AN INDEXED FILE


Consider a small indexed file containing 14 records on cylinder 5, with tracks 1 and 2
ww Co

containing five records and track 3 containing four. This area is known as the prime data
area. Track 1, for example, contains records with keys 205, 206, 208, 210, and 213.
Assume that records are suitably blocked.
Track Data Records on Cylinder 5
cu

1 205 206 208 210 213


2 214 219 220 222 225
3 226 227 230 236 unused
Do

Track 0 of cylinder 5 contains the track index, with an entry indicating the high key for each
track. The track index entries specify that the highest keys on cylinder 5, tracks 1, 2, and 3
are 213, 225, and 236, respectively:

Page 483 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

The cylinder index contains an entry for each cylinder that contains data, indicating the high
key for each cylinder. In this case, the only index entry is a key 236 on cylinder 5 (the track
number is not important in this index):

As an example of processing, a program has to locate randomly a record with key 227.

al
The read statement directs the system to perform the following steps:
1. Check the cylinder index (assuming no master index), comparing key 227 against its

com Tr
i
first entry, 236. Since 227 is lower, the required record should be on cylinder 5.
2. Access the track index in cylinder 5, track 0, comparing key 227 successively against
each entry: 213 (high), 225 (high), and 236 (low). According to the entry for 236,
the required record should be on cylinder 5, track 3.

rd. F
3. Check the keys on track 3; find key 227 and deliver the record to the program's input
area. If the key and the record do not exist, ISAM signals an error.
iza D
As you can see, locating a record randomly involves a .number of additional processing
steps, although little extra programming effort is required. Even more processing steps are
dfw P
involved if a new record has to be added. If ISAM has to insert the record within the file,
it may have to "bump" a record into an overflow area.
w.p m

Overflow Areas
When a program first creates a file, ISAM stores the records sequentially in a prime data
area. If you subsequently add a new record; ISAM stores it in an overflow area and maintains
ww Co

links to point to it. (ELB: In what follows, the reader should recall that a disk cylinder can
be defined functionally as a set of records that the read/write heads can access without being
physically moved. Track–to–track head motion is time consuming, taking about 10 msec.)
There are two types of overflow areas: cylinder and independent:
cu

1. For a cylinder overflow area, each cylinder has its own overflow track area. ISAM
reserves tracks on the same cylinder as the prime data for all of its overflow records
stored on a specific cylinder. The advantage of cylinder overflow is that less disk seek
Do

time is required to locate records on a different cylinder. The disadvantage is an uneven


distribution of overflow records: Some of the overflow cylinders may contain many
records, whereas other overflow cylinders may contain few or none.
2. For an independent overflow area, ISAM reserves a number of separate cylinders for all
overflow records in the file. The advantage is that the distribution of overflow records is
unimportant. The disadvantage is in the additional access time to locate records
in the overflow area.
A system may adopt both types: the cylinder overflow area for initial overflows and the
independent overflow area in case cylinder overflow areas overflow.

Page 484 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

In our most recent example, adding a record with key 209 causes ISAM to bump record 213
from track 1 into an overflow area, move 210 in its place, and insert 209 in the place vacated
by 210. The following assumes a cylinder overflow area in track 9:
Track Data Records on Cylinder 5 Comments
1 205 206 208 209 210
2 214 219 220 222 225
Prime Data Area
3 226 227 230 236 unused

al
9 213 Overflow Area
The track index now becomes 210, with a pointer (not shown) to key 213

i
in the overflow area.

com Tr
rd. F
Reorganizing an Indexed File
Because a large number of records in overflow areas cause inefficient processing, an

iza D
installation can use a program periodically to rewrite or reorganize the file. The program
simply reads the records sequentially and writes them into another disk area. ISAM
automatically follows its indexes for the input file and delivers the records sequentially from
dfw P
the prime and overflow areas. It stores all the output records sequentially in the new prime
data area and automatically creates new indexes. At this time, the program may drop records
coded for deletion.
w.p m

PROCESSING DOS INDEXED SEQUENTIAL FILES


Since ISAM automatically handles indexes and overflow areas, little added programming
ww Co

effort is involved in the use of indexed files. There are four approaches to processing:
1 Load or Extend. The initial creation of an ISAM file is known as loading. Once a file
is loaded, you may extend it by storing higher-key records at the end of the file.
cu

2 Adding Records. New records have keys that do not currently exist on the file.
You have to insert or add these records within the file.
3. Random Retrieval. To update an ISAM file with data (such as sales and payments
Do

on customer records), you use the key to locate the master record randomly
and rewrite the updated record.
4. Sequential Processing. If you have many records to update and the new transactions
are in sequence, you can sequentially read, change, and rewrite the ISAM master.
Load or Extend a DOS ISAM File
Loading a file creates it for the first time, and extending involves storing records at the end.
Input records must be in ascending sequence by a predetermined key, and all keys must be
unique. For load and extend, you code the usual OPEN and CLOSE to activate and
deactivate the file. Figure 27-1 uses sequential input records to load an ISAM file named
DISKIS. The new macros for this purpose are SETFL, WRITE, ENDFL, and DTFIS.

Page 485 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

The prototypes for these macros are as follows:


Name Operation Operand
[label] SETFL filename
[label] WRITE filename, NEW_KEY
[label] ENDFL filename
Let's examine the imperative macros and the DTFIS file definition macro.
SETFL (Set File Load Model. SETFL initializes an ISAM file by preformatting the last

al
track of each track index. The operand references the DTFIS name of the ISAM file to
be loaded. In Fig. 27–1, SETFL immediately follows the OPEN macro.
WRITE. The WRITE macro loads a record into the ISAM file. Operand 1 is your DTFIS

com Tr
i
filename, and operand 2 is the word NEWKEY. You store the key and data area in a work
area (named ISAMOUT in Fig. 27–1). DTFIS knows this area through the entry
WORKL=ISAMOUT. For the WRITE statement, ISAM checks that the new key is in
ascending sequence. ISAM then transfers the key and data area to an I/O area (named

rd. F
IOARISAM in the figure and known to DTFIS by IOAREAL=IOARISAM).
Here ISAM constructs the count area:

iza D
dfw P
ENDFL (End File Load Model. After all records are written and before the CLOSE,
ENDFL writes the last data block (if any), an end-of-file record, and any required index
w.p m

entries.
ww Co
cu
Do

Page 486 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co

Figure 27–1 Program: Loading a DOS ISAM File

The DTFIS Macro


cu

The maximum length for an ISAM filename is 7 [characters]. In Fig. 27–1, the DTFIS entries
for the file being loaded are as follows:
CYLOFL= 1 gives the number of tracks on each cylinder to be reserved for each cylinder
Do

overflow area (if any).


DEVICE= 3340 is the disk device containing the prime data area or overflow area.
DSKXTNT= 2 provides the number of extents that the file uses: one for each data extent and
one for each index area and independent overflow area extent. The program in Fig. 27–1 has
one extent for the prime data area and one for the cylinder index.
IOAREAL=IOARISAM provides the name of the ISAM I/O load area. The symbolic name,
IOARISAM, references the OS buffer area. For loading blocked records, you calculate the
field length as Count area (8) + key length (6) + block length (90 x 3) = 284
IOROUT=LOAD tells the assembler that the program is to load an ISAM file.
KEYLEN=6 gives the length of each record's key.

Page 487 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

KEYLOC= 1 tells ISAM the starting location of the key in the record,
where 1 is the first position.
NRECDS=3 provides the number of records per block.
RECFORM=FIXBLK indicates fixed, blocked record format.
RECSIZE =90 gives the length of each record.
VERIFY= YES tells the system to check the parity of each record as it is written.
WORKL=ISAMOUT gives the name of your load work area, which is a OS defined

al
elsewhere in the program. For blocked records, you calculate the field length as
Key length (6) + data area (90 X 3) = 284 [ELB. I say 276]

i
For unblocked records, you would calculate the field length as

com Tr
Count area (8) + key length + “sequence link field” (10) + record length.
Status Condition
On execution, ISAM macros may generate error conditions, which you may test. After each

rd. F
I/O operation, ISAM places its status in a one-byte field. named “filenameC”. For example,
if your DTFIS name is DISKIS, ISAM calls the status byte DISKISC. Following is a list

BIT iza D
of the 8 bits in filenameC tbat the system may set when loading an ISAM file:
LOAD STATUS ERROR CONDITION
dfw P
0 Any uncorrectable disk error except wrong length record.
1 Wrong length record detected on output.
2 The prime data area is full.
w.p m

3 SETFL has detected a full cylinder index.


ww Co

4 SETFL has detected a full master index.


5 Duplicate record – the current key is the same as the one previously loaded.
6 Sequence error – the current key is lower than the one previously loaded.
cu

7 The prime data area is full, and ENDFL has no place to store the end-of-file record.
The program in Fig. 27–1 uses TM operations to test DISKIS after execution of the macros
SETFL, WRITE, and ENDFL. After SETFL, for example, TM tests whether bits 0, 3, and 4
Do

are on. If any of the conditions exist, the program executes an error routine (not coded)
where the program may isolate the error and issue an error message.
The job control commands also vary. First, the DLBL job entry for "codes" contains ISC,
meaning indexed sequential create, and second, there is an EXTENT command for both
the cylinder index and the data area.
Random Retrieval of an ISAM File
The main purpose of organizing a file as indexed sequential is to facilitate the random
accessing of records. For this, there are a number of special coding requirements. The
program in Fig. 27–2 randomly retrieves records in the file created in Figure 27–1. The
program reads a file of modification records in random sequence, with changes to the ISAM
master file. For each modification record, the program uses the account number (key) to
locate the correct ISAM record, correct it, and then update the record on the ISAM file.

Page 488 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

ISAM Macros for Random Retrieval


The new macros for random retrieval are:
Name Operation Operand
[label] READ filename, KEY
[label] WAITF filename
[label] WRITE filename, KEY
READ causes ISAM to access a required record from the file. Operand 1 contains the DTFIS
filename, and operand 2 contains the word KEY. You store the key in the field referenced by

al
the DTFIS entry KEYARG. In Fig. 27–2, KEYARG=KEYNO. For each modification record
processed, the program transfers the account key number to KEYNO.

i
WAITF allows completion of a READ or WRITE operation before another is attempted.

com Tr
Since a random retrieval reads and rewrites the same record, you must ensure that the
operation is finished. Code WAITF anywhere following a READ or WRITE and preceding
the next READ or WRITE.

rd. F
WRITE rewrites an ISAM record. Operand 1 is the DTFIS filename, and operand 2 is the
word KEY, which refers to your entry in KEYARG.

The DTFIS Macro


iza D
In Fig. 27–2, the DTFIS entries for the random retrieval include these:
dfw P
IOAREAR=IOARISAM provides the name of the ISAM I/O retrieval area. The symbolic
name, IOARISAM, references the DS retrieval area for unblocked records. For blocked
records, the buffer size is given by: Record length (including keys) x blocking factor
w.p m

For unblocked records, the buffer size is given by:


Key length + "sequence link field" (10) + record length
ww Co

TYPEFLE= RANDOM means that the system is to retrieve records randomly by key.
Other entries are SEQNIL for sequential and RANSEQ for both random and sequential.
WORKR=ISAMOUT gives the name of your retrieval work area.
cu

Status Condition
The status byte for add and retrieve is different from load. The following is a list of the
8 bits in finenameC that the system may set.
Do

BIT ADD AND RETRIEVE STATUS ERROR CONDITION


0 Any uncorrectable disk error except wrong length record.
1 Wrong length record detected on output.
2 End–of–file during sequential retrieval (not an error).
3 The requested record is not in the file.
4 The ID given to SETFL for SEQNTL is outside the prime data limits.
5 Duplicate record – an attempt to add a record that already exists in the file.
6. The cylinder overflow area is full.
7 A retrieval operation is trying to process an overflow record.

Page 489 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

i al
com Tr
rd. F
iza D
dfw P
w.p m
ww Co
cu
Do

Figure 27–2 Program: Random retrieval of a DOS ISAM file

Page 490 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

The program in Fig. 27–2 uses TM operations to test DISKIS after execution of the macros
READ and WRITE. Once again, the program would isolate the error and issue a message.
Sequential Reading of an ISAM File
Sequential reading of an ISAM file involves the use of the SETL, GET, and ESETL macros.
SETL (Set Low) establishes the starting point of the first record to be processed. Its options
include these:
• Set the starting point at the first record in the file:
SETL filename,BOF

al
• Set the starting point at the record with the key in the field defined by the
DTFIS KEYARG entry: .

com Tr
i
SETL filename,KEY
• Set the starting point at the first record within a specified group. For example, the
KEYARG field could contain "B480000" to indicate all records with
key beginning with B48:

rd. F
SETL filename,GKEY

iza D
The ESETL macro terminates sequential mode and is coded as ESETL,filename.
dfw P
DTFIS entries include these:
IOAREAS=buffername for the name of the buffer area. You calculate the buffer size just
as you do for random retrieval.
w.p m

IOROUT=RETRVE to indicate sequential retrieval.


TYPEFLE=SEQNTL or RANDOM for sequential or random retrieval.
ww Co

KEYLOC=n to indicate the first byte of the key in a record; if processing begins with
a specified key or group of keys and records are blocked.
To delete a record, you may reserve a byte in the record and store a code in it. A practice
cu

is to use the first byte to match OS requirements. Subsequently, your program may
test for the code when retrieving records and when reorganizing the file.

PROCESSING OS INDEXED SEQUENTIAL FILES


Do

Processing ISAM files under OS is similar to DOS processing, except that QISAM
(Queued Indexed Sequential Access Method) is used for sequential processing and BISAM
(Basic Indexed Sequential Access Method) is used for random processing.
The Delete Flag
Under OS, the practice is to reserve the first byte of each record with a delete flag, defined
with a blank when you create the file. You also code OPTCD=L in the DCB macro or the
DD command. When you want to delete a record, store X'FF' in this byte. QISAM
subsequently will not be able to retrieve the record. QISAM automatically drops the
record when the file is reorganized. Let's examine some features of OS ISAM processing.

Page 491 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

Load an ISAM File


The OS imperative macros concerned with loading an ISAM file are the conventional
OPEN, PUT, and CLOSE. DCB entries are as follows:
DDNAME Name of the data set.
DSORG Set to “IS” for Indexed Sequential.
MACRF (PM) for move mode or (PL) for locate mode.
BLKSIZE Length of each block.

al
CYLDFL Number of overflow tracks per cylinder.
KEYLEN Length of the key area.

com Tr
i
LRECL Length of each record.
NTM Number of tracks for the master index, if any.
OPTCD Options required, such as MYLU in any sequence:

rd. F
M establishes a master index (or omit M).
Y controls use of cylinder overflow areas.

iza D
I controls use of an independent area.
L is a delete flag to cause bypassing records with X'FF' in the first byte.
U (for fixed length only) establishes the track index in main storage.
dfw P
RECFM Record format for fixed/variable and unblocked/blocked:
F, FB, V, and VB.
w.p m

RKP Relative location of the first byte of the key field, where 0 is the first location.
(For variable-length records, the value is 4 or greater.)
ww Co

Sequential Retrieval and Update


Under OS, sequential retrieval and update involve the OPEN, SETL, GET, PUTX,
ESETL, and CLOSE macros. Once the data has been created with standard labels, many
DCB entries are no longer required. DDNAME and DSORG=IS are still used,
and the following entries are available:
cu

MACRF=(entry) The entries are


(GM) or (GL) for input
(PM) or (PL) for output
Do

(GM,SK,PU) if read and rewrite in place, where


S is use of SETL, K is key or key class,
and PU is use of PUTX macro
EODAD=eofaddress Used for input, if reading to end-of-file.
SYNAD=address Requests optional error checking.

Page 492 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

The SETL macro. SETL (Set Low Address) establishes the first sequential record to be
processed anywhere within the data set. The general format is the following:
Name Operation Operand
[label] SETL dcb–name, start–position, address
The start–position operand has the following options:
B Begin with the first record in the data set. (Omit operand 3 for B or BD.)
K Begin with the record with the key in the operand 3 address.

al
KC Begin with the first record of the key class in operand 3. A key class is any group of
keys beginning with a common value, such as all keys H48xxxx. If the first record

i
is "deleted," begin with the first non–deleted record.

com Tr
I Begin with the record at the actual device address in operand 3.
BD, KD, KDH, KCD, and ID cause retrieval of only the data portion of a record.
Here are some examples of SETL to set the first record in a file named DISKIS,

rd. F
using a 6–character key:
• Begin with the first record in the data set:
iza D
SETL DISKIS,B
dfw P
• Begin with the record with the key 012644:
SETL DISKIS,K,KEYADDl
w.p m

• Begin with the first record of the key class 012:


SETL DISKIS,KC,KEYADD2
ww Co

KEYADD1 DC C'012644' 6-character key


KEYADD2 DC C'012',XL3'00' 3-character key class
cu

The ESETL macro, used as ESETL DCB–name, terminates sequential retrieval. If there
is more than one SETL, ESETL must precede each one.
The program in Fig. 27–3 reads an ISAM file sequentially and inserts a delete code
Do

in any record that is more than five years old. The TIME macro delivers the standard
date from the communication region as packed OOyyddd+, and the date in the record
(positions 26-28) is in the same format. The PUTX macro rewrites an obsolete
record with a delete byte in the first position.

Page 493 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

i al
com Tr
rd. F
iza D
dfw P
Figure 27–3 Program: Sequential retrieval of an OS ISAM file
w.p m
ww Co
cu
Do

Page 494 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler ISAM

KEY POINTS
• The indexed system writes a key preceding each block of records. The key
is that of the highest record in the block.
• The track index, cylinder index, and master index help the system locate
records randomly.
• The track index is in track 0 of each cylinder of the file and contains the
highest key number for each track of the cylinder.
• The cylinder index is on a separate cylinder and contains the key number of

al
the highest record on the cylinder.
• The optional master index is recommended if the cylinder index exceeds four

com Tr
i
cylinders in size.
• The master index facilitates locating keys in the cylinder index, the cylinder
index facilitates locating keys in the track index, and the track index facilitates
locating the track containing the required record.

rd. F
• ISAM creates a file sequentially in a prime data area. Subsequent additions
of higher keys append to the end, and additions of lower keys cause records


iza D
to bump into an overflow area.
Cylinder overflow areas reserve tracks on a cylinder for all overflows in that
dfw P
cylinder. This method reduces disk access time.
• Independent overflow areas reserve separate cylinders for overflows from the
w.p m

entire file. This method helps if there is an uneven distribution of overflow records
– that is, many overflow records in some cylinders and few or none in others.
ww Co
cu
Do

Page 495 Chapter 27 Revised January 9, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 28: Virtual Storage Access Method (VSAM)

Author’s Note: This chapter is copied almost verbatim from the material in
Chapter 19 of the textbook by Peter Abel. It is used by permission.
Virtual Storage Access Method (VSAM) is a relatively recent file organization method
for users of IBM OS/VS and DOS/VS. VSAM facilitates both sequential and random
processing and supplies a number of useful utility programs.
The term file is somewhat ambiguous since it may reference an I/O device or the records
that the device processes. To distinguish a collection of records, IBM OS literature uses
the term data set. VSAM provides three types of data sets:
1. Key-sequenced Data Set (KSDS). KSDS maintains records in sequence of key, such as
employee or part number, and is equivalent to indexed sequential access method (ISAM).
2. Entry-sequenced Data Set (ESDS). ESDS maintains records in the sequence in which
they were initially entered and is equivalent to sequential organization.
3. Relative-Record Data Set (RRDS). RRDS maintains records in order of relative record
number and is equivalent to direct file organization.
Both OS/VS and DOS/VS handle VSAM the same way and use similar support programs
and macros, although OS has a number of extended features.
Thorough coverage of assembler VSAM would require an entire textbook. However, this
chapter supplies enough information to enable you to code programs that create, retrieve,
and update a VSAM data set. For complete details, see the IBM Access Methods Services
manual and the IBM DOS/VSE Macros or OS/VS Supervisor Services manuals.
In the table below, RBA stands for “Relative Byte Address”, the byte’s displacement
from the start of the data set.

Feature Key–Sequenced Entry–Sequenced Relative–Record


KSDS ESDS RRDS
Record sequence By key In sequence in In sequence of
which entered relative record
number
Record length Fixed or variable Fixed or variable Fixed only
Access of records By key via By RBA By relative
index or RBA record number
Change of address Can change record Cannot change Cannot change
RBA record RBA relative record
number
New records Distributed free Space at end of Empty slot in
space for records data set. data set.
Recovery of space Reclaim space if No delete, but can Can reuse
record is deleted. overwrite old record. deleted space.
Figure 28–1 Features of VSAM organization methods

Page 496 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

CONTROL INTERVALS
For all three types of data sets, VSAM stores records in groups (one or more) of control
intervals. You may select the control interval size, but if you allow VSAM to do so, it
optimizes the size based on the record length and the type, of disk device being used. The
maximum size of a control interval is 32,768 bytes. At the end of each control interval is
control information that describes the data records:
Rec–1 Rec–2 Rec–3 …. Control Information
A control interval contains one or more data records, and a specified number of control
intervals comprise a control area. VSAM addresses a data record by relative byte address
(RBA)-its displacement from the start of the data set. Consequently, the first record of a
data set is at RBA 0, and if records are 500 bytes long, the second record is at RBA 500.
The list in Fig. 28–1 compares the three types of VSAM organizations.

ACCESS METHOD SERVICES (AMS)


Before physically writing (or "loading") records in a VSAM data set, you first catalog its
structure. The IBM utility package, Access Method Services (AMS), enables you to
furnish VSAM with such details about the data set as its name, organization type, record
length, key location, and password (if any). Since VSAM subsequently knows the
physical characteristics of the data set, your program need not supply as much detailed
information as would a program accessing an ISAM file.
The following describes the more important features of AMS. Full details are in the IBM
OS/VS and DOS/VS Access Methods Services manual. You catalog a VSAM structure
using an AMS program named IDCAMS, as follows:
OS: //STEP EXEC PGM=IDCAMS
DOS: //EXEC IDCAMS,SIZE=AUTO
Immediately following the command are various entries that DEFINE the data set. The
first group under CLUSTER provides required and optional entries that describe all the
information that VSAM must maintain for the data set. The second group, DATA, creates
an entry in the catalog for a data component, that is, the set of all control area and
intervals for the storage of records. The third group, INDEX, creates an entry in the
catalog for a KSDS index component for the handling of the KSDS indexes.
Figure 28–2 provides the most common DEFINE CLUSTER entries. Note that to
indicate continuation, a hyphen (–) follows every entry except the last. The following
notes apply to the figure.
Note: SYMBOL MEANING
[] Optional entry, may be omitted
{} Select one of the following options
() You must code these parentheses
| "or", indicates one of the choices listed in the brackets
{A | B} means to select either A or B

Page 496 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Cluster Level

Figure 28–2 Entries for defining a VSAM data set


• DEFINE CLUSTER (abbreviated DEF CL) provides various parameters all contained
within parentheses.
• NAME is a required parameter that supplies the name of the data set. You can code
the name up to 44 characters with a period after each 8 or fewer characters, as
EMPLOYEE.RECORDS.P030. The name corresponds to job control, as follows:
OS: //FILEVS DD DSNAME=EMPLOYEE.RECORDS.P030 ...
DOS: // DLBL FILEVS,'EMPLOYEE.RECDRDS.P030',0,VSAM
The name FILEVS in this example is whatever name you assign to the file definition
(ACB) in your program, such as
filename ACB DDNAME=FILEVS
• BLOCKS. You may want to load the data set on an FBA device (such as 3310 or
3370) or on a CKD device (such as 3350 or 3380). For FBA devices, allocate the
number of 512–byte BLOCKS for the data set. For CKD devices, the entry
CYLINDERS (or CYL) or TRACKS allocates space. The entry RECORDS allocates
space for either FBA or CKD. In all cases, indicate a primary allocation for a
generous expected amount of space and an optional secondary allocation for
expansion if required.

Page 497 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

• Choose one entry to designate the type of data set: INDEXED designates
key–sequenced, NONINDEXED is entry–sequenced, and NUMBERED is
relative–record.
• KEYS for INDEXED only defines the length (from 1 to 255) and position of the key
in each record. For example, KEYS (6 0) indicates that the key is 6 bytes long
beginning in position 0 (the first byte).
• RECORDSIZE (or RECSZ) provides the average and maximum lengths in bytes of
data records. For fixed–length records and for RRDS, the two entries are identical.
For example, code (120b120) for l20–byte records.
• VOLUMES (or VOL) identifies the volume serial number(s) of the DASD volume(s)
where the data set is to reside. You may specify VOLUMES at any of the three
levels; for example, the DATA and INDEX components may reside on different
volumes.
DEFINE CLUSTER supplies a number of additional specialized options described in the
IBM AMS manual.

ACCESSING AND PROCESSING


VSAM furnishes two types of accessing, keyed and addressed, and three types of
processing, sequential, direct, and skip sequential. The following chart shows the legal
accessing and processing by type of organization:
Type Keyed Access Addressed Access
KSDS Sequential Sequential
Direct Direct
Skip sequential
ESDS Sequential
Direct
RRDS Sequential
Direct
Skip sequential
In simple terms, keyed accessing is concerned with the key (for KSDS) and relative
record number (for RRDS). For example, if you read a KSDS sequentially, VSAM
delivers the records in sequence by key (although they may be in a different sequence
physically).
Addressed accessing is concerned with the RBA. For example, you can access a record in
an ESDS using the RBA by which it was stored. For either type of accessing method, you
can process records sequentially or directly (and by skip sequential for keyed access).
Thus you always use addressed accessing for ESDS and keyed accessing for RRDS and
may process either type sequentially or directly. KSDS, by contrast, permits both keyed
access (the normal) and addressed access, with both sequential and direct processing.

Page 498 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

KEY–SEQUENCED DATA SETS


A key-sequenced data set (KSDS) is considerably more complex than either ESDS or
RRDS but is more useful and versatile. You always create ("load") a KSDS in ascending
sequence by key and may process a KSDS directly by key or sequentially. Since KSDS
stores and retrieves records according to key, each key in the data set must be unique.

Figure 28–3 Key–sequenced organization


'Figure 28–3 provides a simplified view of a key-sequenced data set. The control
intervals that contain the data records are depicted vertically, and for this example three
control intervals comprise a control area. A sequence set contains an entry for each
control interval in a control area. Entries within a sequence set consist of the highest key
for each control interval and the address of the control interval; the address acts as a
pointer to the beginning of the control interval. The highest keys for the first control area
are 22, 32, and 40, respectively. VSAM stores each high key along with an address
pointer in the sequence set for the first control area.
At a higher level, an index set (various levels depending on the size of the data set)
contains high keys and address pointers for the sequence sets. In Fig. 28–3, the highest
key for the first control area is 40. VSAM stores this value in the index set along with
an address pointer for the first sequence.
When a program wants to access a record in the data set directly, VSAM locates the
record first by means of the index set and then the sequence set. For example, a program
requests access to a record with key 63. VSAM first checks the index set as follows:
RECORD KEY INDEX SET ACTION
63 40 Record key high, not in first control area.
63 82 Record key low, in second control area.

Page 499 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

VSAM has determined that key 63 is in the second control area. It next examines the
sequence set for the second control area to locate the correct control interval.
These are the steps:
RECORD KEY SEQUENCE SET ACTION
63 55 Record key high, not in
first control interval.
63 65 Record key low, in second control interval.
VSAM has now determined that key 63 is in the second control interval of the second
control area. The address pointer in the sequence set directs VSAM to the correct control
interval. VSAM then reads the keys of the data set and locates key 63 as the first record
that it delivers to the program.

Free Space
You normally allow a certain amount of free space in a data set for VSAM to insert new
records. When creating a key–sequenced data set, you can tell VSAM to allocate free
space in two ways:
1. Leave space at the end of each control interval.
2. Leave some control intervals vacant.
If a program deletes or shortens a record, VSAM reclaims the space by shifting to the left
all following records in the control interval. If the program adds or lengthens a record,
VSAM inserts the record in its correct space and moves to the right all following records
in the control interval. VSAM updates RBAs and indexes accordingly.
A control interval may not contain enough space for an inserted record. In such a case,
VSAM causes a control interval split by removing about half the records to a vacant
control interval in the same control area. Although records are now no longer physically
in key order, for VSAM they are logically in sequence. The updated sequence set
controls the order for subsequent retrieval of records.
If there is no vacant control interval in a control area, VSAM causes a control area split,
using free space outside the control area. Under normal conditions, such a split seldom
occurs. To a large degree, a VSAM data set is self-organizing and requires reorganization
less often than an ISAM file.

ENTRY·SEQUENCED DATA SETS


An entry-sequenced data set (ESDS) acts like sequential file organization but has the
advantages of being under control of VSAM, some use of direct processing, and
password facilities. Basically, the data set is in the sequence in which it is created, and
you normally (but not necessarily) process from the start to the end of the data set.
Sequential processing of an ESDS by RBA is known as addressed access, which is the
method you use to create the data set. You may also process ESDS records directly by
RBA. Since ESDS is not concerned with keys, the data set may legally contain duplicate
records.

Page 500 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Assume an ESDS containing records with keys 001, 003, 004, and 006. The data set
would appear as follows:
| 001 | 003 | 004 | 006 |
You may want to use ESDS for tables that are to load into programs, for small files that
are always in ascending sequence, and for files extracted from a KSDS that are to be
sorted.

RELATIVE-RECORD DATA SETS


A relative-record data set (RRDS) acts like direct file organization but also has the
advantages of being under control of VSAM and offering keyed access and password
facilities. Basically, records in the data set are located according to their keys. For
example, a record with key 001 is in the first location, a record with key 003 is in the
third location, and so forth. If there is no record with key 002, that location is empty,
and you can subsequently insert the record.
Assume an RRDS containing records with keys 001, 003, 004, and 006. The data set
would appear as follows:
| 001 | ... | 003 | 004 | ... | 006 |
Since RRDS stores and retrieves records according to key, each key in the data set must
be unique.
You may want to use RRDS where you have a small to medium-sized file and keys are
reasonably consecutive so that there are not large numbers of spaces. One example
would be a data set with keys that are regions or states, and contents are product sales
or population and demographic data.
You could also store keys after performing a computation on them. As a simple example,
imagine a data set with keys 101, 103, 104, and 106. Rather than store them with those
keys, you could subtract 100 from the key value and store the records with keys 001, 003,
004, and 006.

VSAM MACRO INSTRUCTIONS


VSAM uses a number of familiar macros as well as a few new ones to enable you to
retrieve, add, change, and delete records. In the following list, for macros marked with an
asterisk, see the IBM DOS/VS or OS/VS Supervisor and I/O Macros manual for details.
 To relate a program and the data:
ACB (access method control block)
EXLST (exit list)
 To connect and disconnect a program and a data set:
OPEN (open a data set)
CLOSE (close a data set)
TCLOSE (temporary close)

Page 501 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

 To define requests for accessing data:


RPL (request parameter list)
 To request access to a file:
GET (get a record)
PUT (write or rewrite a record)
POINT* (position VSAM at a record)
ERASE (erase a record previously retrieved with a GET)
ENDREQ* (end a request)
 To manipulate the information that relates a program to the data:
GENCB* (generate control block)
MODCB* (modify control block)
SHOWCB (show control block)
TESTCB* (test control block)
A program that accesses a VSAM data set requires the usual OPEN to connect the
data set and CLOSE to disconnect it, the GET macro to read records, and PUT to
write or rewrite records. An important difference in the use of macros under VSAM
is the RPL (Request for Parameter List) macro. As shown in the following relationship,
a GET or PUT specifies an RPL macro name rather than a file name. The RPL in
turn specifies an ACB (Access Control Block) macro, which in its turn relates
to the job control entry for the data set:

The ACB macro is equivalent to the OS DCB or DOS DTF file definition macros. As
well, the OPEN macro supplies information about the type of file organization, record
length, and key. Each execution of OPEN, CLOSE, GET, PUT, and ERASE causes
VSAM to check its validity and to insert a code into register 15 that you can check.
A return code of X'00' means that the operation was successful. You can use the
SHOWCB macro to determine the exact cause of the error.

THE ACB MACRO: ACCESS METHOD CONTROL BLOCK


The ACB macro identifies a data set that is to be processed. Its main purpose is to
indicate the proposed type of processing (sequential or direct) and the use of exit
routines, if any. The DEFINE CLUSTER command of AMS has already stored much of
the information about the data set in the VSAM catalog. When a program opens the data
set via the ACB, VSAM delivers this information to virtual storage.

Page 502 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Entries for an ACB macro may be in any sequence, and you may code only those that
you need. Following is the general format, which you code like a DCB or DTF,
with a comma following each entry and a continuation character in column 72.
All operands are optional.
ACB AM=VSAM +
DDNAME=filename, +
EXLST=address +
MACRF=([ADR][,KEY]
[,DIR][,SEQ][,SKP]
[,IN][,OUT]
[,NRM][,AIX]) +
STRND=number
name The name indicates the symbolic address for the ACB when assembled.
If you omit the DDNAME operand from the ACB definition, this name
should match the filename in your DLBL or DD job statement.
AM=VSAM Code this parameter if your installation also uses VTAM;
otherwise, the assembler assumes VSAM.
DDNAME This entry provides the name of your data set that the program is to
process. This name matches the filename in your DLBL
or DD job statement.
EXLST The address references a list of your addresses of routines that provide
exits. Use the EXLST macro to generate the list, and enter its name as
the address. A common use is to code an entry for an end–of–file exit for
sequential reading. If you have no exit routines, omit the operand.
MACRF The options define the type of processing that you plan.
In the following, an underlined entry is a default:
ADR|KEY Use ADR for addressed access (KS and ES)
and KEY for keyed access (KS and RR).
DIR|SEQ|SKP DIR provides direct processing, SEQ
provides sequential processing, and SKP
means skip sequential (for KS and RR).
IN|OUT IN retrieves records and OUT permits retrieval,
insertion, add–to–end, or update for keyed
access and retrieval, update, or
add–to–end for addressed access.
NRM|AIX The DDNAME operand supplies the name of
the data set (or path). NRM means normal
processing of the data set, whereas AIX means
that this is an alternate index.
Other MACRF options are RST|NRS for resetting catalog
information and NUB|UBF for user buffers.

Page 503 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

STRNO The entry supplies the total number of RPLs (request parameter
lists) that your program will use at the same time (the default is 1).
ACB also has provision for parameters that define the number and size of buffers;
however, the macro has standard defaults.
In the program example in Fig. 28–4, the ACB macro VSMFILOT has only two entries
and allows the rest to default. Access is keyed (KEY), processing is sequential (SEQ),
and the file is output (OUT). There is no exit list, STRNO defaults to 1, and MACRF
defaults to NRM (normal path).
The assembler does not generate an I/O module for an ACB, nor does the linkage editor
include one. Instead, the system dynamically generates the module at execute time.
THE RPL MACRO: REQUEST PARAMETER UST
The request macros GET, PUT, ERASE, and POINT require a reference to an RPL
macro. For example, the program in Fig. 28–4 issues the following GET macro:
GET RPL=RPLISTIN
The operand supplies the name of the RPL macro that contains the information needed to
access a record. If your program is to access a data set in different ways, you can code an
RPL macro for each type of access; each RPL keeps track of its location in the data set.
The standard format for RPL is as follows. The name for the RPL macro is the one that
you code in the GET or PUT operand. Every entry is optional. (ELB: Note the
non–blank character in column 72 to indicate continuation on the next line.)
Name field Operation Operands Column 72
RPLname RPL AM=VSAM, +
ACB=address, +
AREA=address, +
AREALEN=length, +
ARG=address, +
KEYLEN=length, +
OPTCD=(options), +
RECLEN = length
AM The entry VSAM specifies that this is a VSAM (not VTAM)
control block.
ACB The entry gives the name of the associated ACE that
defines the data set.
AREA The address references an I/O work area in which a record
is available for output or is to be entered on input.
AREALEN The entry supplies the length of the record area.
ARG The address supplies the search argument-a key, including
a relative record number or an RBA.
KEYLEN The length is that of the key if processing by generic key.
(For normal keyed access, the catalog supplies the key length.)

Page 504 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

OPTCD Processing options are SEQ, SKP, and DIR; request options are UPD
(update) and NUP (no update). For example, a direct update
would be (DIR,UPD).
RECLEN For writing a record, your program supplies the length to VSAM, and
for retrieval, VSAM supplies the length to your program. If records are
variable length, you can use the SHOWCB and TESTCB macros to
examine the field (see the IBM Supervisor manual).

THE OPEN MACRO


The OPEN macro ensures that your program has authority to access the specified data set
and generates VSAM control blocks.
[label] OPEN address [,address ...... ]
The operand designates the address of one or more ACBs, which you may code either as
a macro name or as a register notation (registers 2–12); for example:
OPEN VSFILE
or LA 6,VSFILE
OPEN (6)
You can code up to 16 filenames in one OPEN and can include both ACB names and
DCB or D1F names. Note, however, that to facilitate debugging, avoid mixing them in
the same OPEN. OPEN sets a return code in register 15 to indicate success (zero) or
failure (nonzero), which your program can test:
X'00' Opened all ACBs successfully.
X'04' Opened all ACBs successfully but issued a
warning message for one or more.
X'08' Failed to open one or more ACBs.
On a failed OPEN or CLOSE, you can also check the diagnostics following program
execution for a message such as OPEN ERROR X'6E', and check Appendix K
of the IBM Supervisor manual for an explanation of the code.
THE CLOSE MACRO
The CLOSE macro completes any I/O operations that are still outstanding, writes any
remaining output buffers, and updates catalog entries for the data set.
[label ] CLOSE address [,address ... ]
You can code up to 16 names in one CLOSE and can include both ACB names
and DCB or DTF names. CLOSE sets a return code in register 15 to indicate
success or failure, which your program can test:
X'00' Closed all ACBs successfully.
X'04' Failed to close one or more ACBs successfully.
X'08' Insufficient virtual storage space for close routine
or could not locate modules.

Page 505 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

THE REQUEST MACROS: GET. PUT. ERASE


The VSAM request macros are GET, PUT, ERASE, POINT, and ENDREQ. For each
of these, VSAM sets register 15 with a return code to indicate success or failure of the
operation, as follows:
X'00' Successful operation.
X'04' Request not accepted because of an active request from
another task on the same RPL.
End-of-file also causes this return code.
X'08' A logical error; examine the specific error code in the RPL.
X'0C' Uncorrectable I/O error; examine the specific error code in the RPL.

The GET Macro


GET retrieves a record from a data set. The operand specifies the address of an RPL that
defines the data set being processed. The entry may either (1) cite the address by name
or (2) use register notation, any register 2–12, in parentheses.
You may use register 1; its use is more efficient, but GET does not preserve its address.
1. GET RPL=RPLname
2. LA reg,RPLname
GET RPL=(reg)
The RPL macro provides the address of your work area where GET is to deliver an input
record. Register 13 must contain the address of a save area defined as 18·fullwords.
Under sequential input, GET delivers the next record in the data set. The OPTCD entry in
the RPL macro would appear, for example, as OPTCD=(KEY,SEQ) or
OPTCD=(ADR,SEQ). You have to provide for end–of–file by means of an EXLST
operand in the associated ACB macro; see Fig. 28–4 for an example.
For non–sequential accessing, GET delivers the record that the key or relative record
number specifies in the search argument field. The OPTCD entry in the RPL macro
would appear, for example, as OPTCD = (KEY,SKP) or OPTCD= (KEY,DIR), or as
an RBA in the search argument field, as OPTCD = (ADR,DIR).
You also use GET to update or delete a record.
The PUT Macro
PUT writes or rewrites a record in a data set. The operand of PUT specifies the address
of an RPL that defines the data set being processed. The entry may either (1) cite the
address by name or (2) use register notation, any register 2-12, in parentheses. You may
use register 1; its use is more efficient, but PUT does not preserve its address.
1. PUT RPL=RPLname
2. LA reg,RPLname
PUT RPL=(reg)

Page 506 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

The RPL macro provides the address of your work area containing the record that
PUT is to add or update in the data set. Register 13 must contain the address of a
save area defined as 18 fullwords.
To create (load) or extend a data set, use sequential output. The OPTCD entry in the
RPL macro would appear, for example, as OPTCD=(SEQ or SKP). SKP means
"skip sequential" and enables you to start writing at any specific record.
For writing a KSDS or RRDS, if OPTCD contains any of the following, PUT stores
a new record in key sequence or relative record sequence:
OPTCD=(KEY,SKP,NUP) Skip, no update
OPTCD=(KEY,DIR,NUP) Direct, no update
OPTCD=(KEY,SEG,NUP) Sequential, no update
Note that VSAM does not allow you to change a key in a KSDS (delete the record and
write a new one). To change a record, first GET it using OPTCD= UFD, change its
contents (but not the key), and PUT it, also using OPTCD=UFD. To write a record
in ESDS, use OPTCD=(ADR, ….).

The ERASE Macro


The purpose of the ERASE macro is to delete a record from a KSDS or an RRDS.
To locate an unwanted record, you must previously issue a GET with an RPL
specifying OPTCD=(UFD...).
[label] ERASE RPL=address or =(register)
For ESDS, a common practice is to define a delete byte in the record. To "delete" a
record, insert a special character such as X'FF'; all programs that process the data set
should bypass all records containing the delete byte. You can occasionally rewrite
the data set, dropping all deletes.
THE EXLST MACRO
If your ACB macro indicates an EXLST operand, code a related EXLST macro. EXLST
provides an optional list of addresses for user exit routines that handle end–of–file and
error analysis. All operands in the macro are optional.
When VSAM detects the coded condition, the program enters your exit
routine. Register 13 must contain the address of your register save area. For example,
if you are reading sequentially, supply an end–of–data address (EODAD) in the EXLST
macro-see the ACB for VSMFILIN in Fig. 28–4.

Page 507 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Name field Operation Operands Column 72


[label] EXLST AM=VSAM, +
EODAD=address, +
LERAD=address, +
SYNAD=address
Here are explanations of the operands for EXLST:
VSAM Indicates a VSAM control block.
EODAD Supplies the address of your erid-of-data routine. You may also read
sequentially backward, and VSAM enters your routine when reading
past the first record. The request return code for this condition is X'04'.
LERAD Indicates the address of the routine that analyzes logical errors that
occurred during GET, PUT, POINT, and ERASE. The request return
code for this condition is X'08'.
SYNAD Provides the address of your routine that analyzes physical I/O errors
on GET, PUT, POINT, ERASE, and CLOSE. The request return code
for this condition is X'OC'.
Other operands are EXCPAD and JRNAD.

THE SHOWCB MACRO


The original program in Fig. 28–4 contained an error that caused it to fail on a PUT
operation. The use of the SHOWCB macro in the error routine for PUT (R30PUT)
helped determine the actual cause of the error.
The purpose of SHOWCB is to display fields in an ACB, EXLST, or RPL.
Code SHOWCB following a VSAM macro where you want to identify errors that
VSAM has detected. The SHOWCB in the PUT error routine in Fig. 28–4 is as follows:
SHOWCB RPL=RPLISTOT,AREA=FDBKWD,FIELDS=(FDBK),LENGTH=4
….
FDBKWD DC F'O'
AREA Designates the name of a fullword where VSAM is to place an error code.
FIELDS Tells SHOWCB the type of display; the keyword FDBK (feedback) causes
a display of error codes for request macros.
LENGTH Provides the length of the area in bytes.

Page 508 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

On a failed request, VSAM stores the error code in the rightmost byte of the fullword
area. These are some common error codes:
X‘08’ Attempt to store a record with a duplicate key.
X‘0C’ Out-of-sequence or duplicate record for KSDS or RRDS.
X‘10’ No record located on retrieval.
X‘1C’ No space available to store a record.
Your program can test for the type of error and display a message. For nonfatal errors, it
could continue processing; for fatal errors, it could terminate.
The original error in Fig. 28–4 was caused by the fact that the RPL macro RPLISTOT did
not contain an entry for RECLEN; the program terminated on the first PUT error, with
register 15 containingX'08' (a "logical error"). Insertion of the SHOWCB macro in the
next run revealed the cause of the error in FDBKWD: 00006C. Appendix K of the IBM
Supervisor manual explains the error (in part) as follows: "The RECLEN value specified
in the RPL macro was [either] larger than the allowed maximum [or] equal to zero...."
Coding a RECLEN operand in the RPL macro solved the problem, and the program then
executed through to normal termination. One added point: Technically, after" each
SHOWCB, you should test register 15 for a successful or failed operation.

SAMPLE PROGRAM: LOADING A KEY-SEQUENCED DATA SET


The program in Fig. 28–4 reads records from the system reader and sequentially creates a
key-sequenced data set. A DEFINE CLUSTER command has allocated space for this
data set as INDEXED (KSDS), with three tracks, a 4-byte key starting in position 0, and
an 80–byte record size. The program loads the entire data set and closes it on completion.
For illustrative (but not practical) purposes, it reopens the data set and reads and prints
each record. The PUT macro that writes records into the data set is:
PUT RPL=RPLISTOT
RPLISTOT defines the name of the ACB macro (VSMFILOT), the address of the output
record, and its length. Although the example simply duplicates the record into the data
set, in practice you would probably define various fields and store numeric values as
packed or binary.
The ACB macro defines VSMFILOT for keyed accessing, sequential processing, and
output. The DDNAME, VSAMFIL, in this example relates to the name for the data set
in the DLBL job control entry (DD under OS).
For reading the data set, the GET macro is
GET RPL=RPLISTIN
RPLISTIN defines the name of the ACB macro (VSMFILIN), the address in which
GET is to read an input record, and the record length.

Page 509 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Figure 28–4 Loading a key–sequenced data set

Page 510 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

Figure 28–4 Loading a key–sequenced data set (continued)

Page 511 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

The ACB macro defines VSMFILIN for keyed access, sequential processing, and input.
The DDNAME, VSAMFIL, relates to the name for the data set in the DLBL job control
entry. Note that there is an ACB and RPL macro for both input and output, but both
ACB macros specify the same DDNAME: VSAMFIL.
Error routines are for failures on OPEN, GET, and PUT. These rather primitive routines
supply an error code and the contents of the declaratives; in practice, you may want to
enlarge these routines. If you fail to provide error routines, your program may crash with
no clear cause.
During testing, you may have changed the contents of a VSAM data set and now want
to reload (re-create) the original data set. Except for updating with new keys, VSAM
does not permit overwriting records in a data set. You have to use IDCAMS to DELETE
and again DEFINE the data set as follows:
DELETE(data-set-name) CLUSTER PURGE …
DEFINE CLUSTER(NAME(data-set-name) ….)

Loading an ESDS
To convert the program in Fig. 19-4 from KSDS to ESDS, change DEFlNE CLUSTER
from INDEXED to NONINDEXED and delete the KEYS and INDEX entries.
Change the ACB MACRF from KEY to ADR, and change the RPL OPTCD from
KEY to ADR – that's all.

KEYED DIRECT RETRIEVAL


Key-sequenced data sets provide for both sequential and direct processing by key.
For direct processing, you must supply VSAM with the key of the record to be accessed.
If you use a key to access a record directly, it must be the same length as the keys in the
data set (as indicated in the KEYS operand of DEFINE CLUSTER), and the key must
actually exist in the data set. For example, if you request a record with key 0028 and
there is no such record, VSAM returns an error code in register 15.
Using the data set in Fig. 19-4, assume that a program is to access records directly. A user
enters record key numbers via a terminal, and the program is to display the record on the
screen. In this partial example, the RPL macro specifies the name (ARG) of the key to
be in a 4-byte field named KEYFLD. These are the specific coding requirements for the
ACB, RPL, and GET macros:
For updating a KSDS record, change the MACRF from IN to OUT, and change the
OPTCD from NUP to UPD. GET the record, make the required changes to it (but
not the key!), and PUT the record using the same RPL.

Page 512 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

VSMFILE ACB DDNAME=name, +


MACRF=(KEY,DIR,IN)
RPLIST RPL ACB=VSMFILE, +
AREA=DCBREC, +
AREALEN=80, +
ARG=KEYFLD, +
OPTCD=(KEY,DIR,NUP)
KEYFLD DS CL4
DCBREC DS CL80
[Accept a key number from the terminal]
MVC KEYFLD,keyno
GET RPL=RPLI ST
LTR 15,15
BNZ error
[Display the record on the screen]

SORTING VSAM FILES


You can sort VSAM records into either ascending or descending sequence. You must
first use DEFINE CLUSTER to allocate a vacant data set (NONINDEXED) for SORT to
write the sorted data set. Here is a typical SORT specification:
// EXEC SORT,SIZE=256K
SORT FIELDS=(1,4,CH,A,9,4,PD,D)
RECORD TYPE=F,LENGTH=(150)
INPFIL VSAM
OUTFIL ESDS
END
/*
SORT causes the SORT program to load into storage and begin execution.
SORT FIELDS defines the fields to be sorted, indicated by major control to minor,
from left to right. In this example, the major sort field begins in position 1 (the first
position), is 4 bytes long, is in character (CH) format, and is to be sorted in ascending
(A) sequence. The minor sort field begins in position 9, is 4 bytes long, is in packed (PD)
format, and is to be sorted in descending (0) sequence. The example could be a sort of
departments in ascending sequence, and within each department are employee salaries
in descending sequence.
RECORD TYPE indicates fixed (F) length and record length (150 bytes).
INPFIL informs SORT that the input file is VSAM; SORT can determine the type
of data set from the VSAM catalog.
OUTFIL defines the type of output file, in this case entry-sequenced. This entry
should match the DEFINE CLUSTER for this data set, NONINDEXED.
Job control commands for SORTIN and SORTOUT provide the names of the data sets.
Since job control varies by operating system and by installation requirements, check
with your installation before attempting the SORT utility.

Page 513 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

VSAM UTILITY PRINT


IDCAMS furnishes a convenient utility program named PRINT that can print the
contents of a VSAM, SAM, or ISAM data set. The following provides the steps for
OS and for DOS:
OS: //STEP EXEC PGM=IDCAMS
PRINT INFILE(filename) CHARACTER or HEX or DUMP
/*
DOS: // EXEC IDCAMS,SIZE=256K
PRINT INFILE(filename) CHARACTER or HEX or DUMP
/*
The options for PRINT indicate the format of the printout, in character, hexadecimal,
or both (DUMP prints hex on the left and character format on the right).
INFILE(fiIename) matches the name in the OS DD or DOS DLBL job statement with
any valid filename as long as the two are identical. The DD or DLBL statement notifies
VSAM which data set is to print.
PRINT lists KSDS and ISAM data sets in key sequence and lists ESDS, RRDS, and
SAM data sets in physical sequence. You can also print beginning and ending at a
specific record.

KEY POINTS
• A key-sequenced data set (KSDS) maintains records in sequence of key, such as
employee or part number, and is equivalent to indexed sequential access method.
• An entry-sequenced data set (ESDS) maintains records in the sequence in which they
were initially entered and is equivalent to sequential organization.
• A relative-record data set (RRDS) maintains records in order of relative record
number and is equivalent to direct file organization.
• For the three types of data sets, VSAM stores records in groups (one or more) of
control intervals. At the end of each control interval is control information that
describes the data records.
• Before physically writing (loading) records in a VSAM data set, you must first
catalog its structure. Access method services (AMS) enables you to furnish VSAM
with such details about the data set as its name, organization type, record length, key
location, and password (if any).
• VSAM furnishes two types of accessing, keyed and addressed, and three types of
processing, sequential, direct, and skip sequential.
• The most common errors in processing VSAM data sets occur because of the need to
match definitions in the program, job control, and the cataloged VSAM data set.

Page 514 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
S/370 Assembler VSAM

• The data-set-name in job control (such as CUSTOMER.INQUIRY) must agree with


the NAME(data–set–name) entry in DEFJNE CLUSTER. This name is the only one
by which VSAM recognizes the data set. VSAM relates the ACB DDNAME in the
program to the job control name and the job control name to the data-set-name.
• If a data set is cataloged as KSDS, ESDS, or RRDS, each program must access it
accordingly.
• For KSDS, the length and starting position of the key in a record must agree with the
KEYS entry in DEFINE CLUSTER and, for direct input, with the defined
ARG in the OPTCD.
• Every program that references the data set defines the fields with identical formats
and lengths in the same positions; the actual field names need not be identical. You
may define as character any input field in a record that the program does not
reference. The simplest practice is to catalog all record definitions in the assembler
source library and COPY the definition into the program during assembly.
• After each OPEN, CLOSE, GET, PUT, and SHOWCB, test register 15 for success or
failure, and use SHOWCB (as well as TESTCB) as a debugging aid.

Page 515 Chapter 28 Revised January 19, 2010


Copyright © 2009 by Edward L. Bosworth, Ph.D.
Chapter 29: Operating Systems

Author’s Note: This chapter is copied almost verbatim from the material in
Chapter 21 of the textbook by Peter Abel. It is used by permission.
This chapter introduces material that is suitable for more advanced assembler programming.
The first section examines general operating systems and the various support programs.
Subsequent sections explain the functions of the program status word and the interrupt
system. Finally, there is a discussion of input/output channels, physical IOCS, and the
input/output system.
These topics provide an introduction to systems programming and the relationship between
the computer hardware and the manufacturer's software. A knowledge of these features can
be a useful asset when serious bugs occur and when a solution requires an intimate
knowledge of the system.
In an installation, one or more systems programmers, who are familiar with the computer
architecture and assembler language, provide .support for the operating system. Among the
software that IBM supplies to support the system are language translators such as assembler,
COBOL, and PL/I and utility programs for cataloging and sorting files.

OPERATING SYSTEMS
Operating systems were developed to minimize the need for operator intervention during the
processing of programs. An operating system is a collection of related programs that provide
for the preparation and execution of a user's programs. The system is stored on disk, and part
of it, the supervisor program, is loaded into the lower part of main storage.
You submit job control commands to tell the system what action to perform. For example,
you may want to assemble and execute a source program. To this end, you insert job control
commands before and after the source program and submit it as a job to the system. In simple
terms, the operating system performs the following steps:
1. Preceding the source program is a job control command that tells the operating system to
assemble a program. The system loads the assembler program from a disk library into storage
and transfers control to it for execution.
2. The assembler reads and translates the source program into an object program and stores it
on disk.
3. Another job control command tells the system to link–edit the object program. The system
loads the linkage editor from a disk library into storage and transfers control to it for
execution.
4. The linkage editor reads and translates the object program, adds any required input/output
modules, and stores it on disk as an executable module.
5. Another job control command tells the system to execute the executable module. The
system loads the module into storage and transfers control to it for execution.

Page 516 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
6. The program executes until normal or abnormal termination, when it returns
processing control to the system.
7. A job command tells the system that this is the end of the job, since a job may
consist of any number of execution steps. The system then terminates that job and
prepares for the next job to be executed.
Throughout the processing, the system continually intervenes to handle all input/output,
interrupts for program checks, and protecting the supervisor and any other programs
executing in storage.
IBM provides various operating systems, depending on users' requirements, and they
differ in services offered and the amount of storage they require. These are some
major operating systems:
DOS Disk Operating System Medium-sized systems
DOS/VSE Disk Operating System Medium-sized systems with virtual storage
OS/VSl Operating System Large system
OS/VS2 Operating System Large system
OS/MVS Operating System Large system
Systems Generation
The manufacturer typically supplies the operating system on reels of magnetic tape, along
with an extensive set of supporting manuals. A systems programmer has to tailor the
supplied operating system according to the installation's requirements, such as the
number and type of disk drives, the number and type of terminals to be supported, the
amount of processing time available to users, and the levels of security that are to prevail.
This procedure is known as systems generation, abbreviated as sysgen.
Operating System Organization
Figure 29–1 shows the general organization of Disk Operating System (DOS), on
which this text is largely based. The three main parts are the control program,
system service programs, and processing programs.

Figure 29–1 Disk Operating System Organization

Page 517 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Control Program
The control program, which controls all other programs being processed, consists
of initial program load (IPL), the supervisor, and job control. Under OS, the
functions are task management, data management, and job management.
IPL is a program that the operator uses daily or whenever required to load the supervisor
into storage. On some systems, this process is known as booting the system.
Job control handles the transition between jobs run on the system. Your job commands
tell the system what action to perform next.
The supervisor, the nucleus of the operating system, resides in lower storage, beginning
at location X'200'. The system loads user (problem) programs in storage following the
supervisor area, resulting in at least two programs in storage: the supervisor program
and one or more problem programs. Only one is executing at any time, but control
passes between them.
The supervisor is concerned with handling interrupts for input/output devices, fetching
required modules from the program library, and handling errors in program execution.
An important part of the supervisor is the input/output control system (IOCS), known
under OS as data management.

Figure 29–2 Supervisor areas

Figure 29–2 (not an exact representation) illustrates the general layout of the supervisor
in main storage. Let's examine its contents.

Page 518 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
1. Communication Region. This area contains the following data:
LOCATION CONTENTS
00 – 07 The current date, as mm/dd/yy or dd/mm/yy
08 – 11 Reserved
12 – 22 User area, set to zero when a JOB command is read to provide
communication within a job step or between job steps
23 User program status indicator (UPSI)
24 – 31 Job name, entered from job control
32 – 35 Address: highest byte of problem program area
36 – 39 Address: highest byte of current problem program phase
40 – 43 Address: highest byte of phase with highest ending address
44 – 45 Length of label area for problem program
2. Channel Scheduler. The channels provide a path between main storage and the
input/output devices for all I/O interrupts and permit overlapping of program execution
with I/O operations. If the requested channel, control unit, and device are available, the
channel operation begins. If they are busy, the channel scheduler places its request in a
queue and waits until the device is available. The channel notifies the scheduler when
the I/O operation is complete or that an error has occurred.
3. Storage Protection. Storage protection prevents a problem program from erroneously
moving data into the supervisor area and destroying it. Under a multiprogramming
system, this feature also prevents a program in one partition from erasing a program in
another partition.
4. Interrupt Handling. An interrupt is a signal that informs the system to interrupt the
program that is currently executing and to transfer control to the appropriate supervisor
routine. A later section on the program status word covers this topic in detail.
5. System Loader. The system loader is responsible for loading programs into main
storage for execution.
6. Error Recovery Routines. A special routine hancl1es error recovery for each I/O
device or class of devices. When an error is sensed, the channel scheduler invokes
the required routine, which attempts to correct the error.
7. Program Information Block (PIB). The PIB contains information tables that the
supervisor needs to know about the current programs in storage.
8. I/O Devices Control Table. This area contains a table of I/O devices that relate
physical unit addresses (X'nnn') with logical addresses (SYSxxx).
9. Transient Area. This area provides temporary storage for less used routines that the
supervisor loads as required, such as OPEN, CLOSE, DUMP, end–of– job handling,
some error recovery, and checkpoint routines.

Page 519 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
System Service Programs
System service programs include the linkage editor and the librarian.
Linkage editor. The linkage editor has two main functions:
1. To include input/output modules. An installation catalogs I/O modules in the system
library (covered next). When you code and assemble a program, it does not yet contain
the complete instructions for handling input/output. On completion of assembly, the
linkage editor includes all the required I/O modules from the library.
2. To link together separately assembled programs. You may code and assemble a
number of subprograms separately and link-edit these subprograms into one executable
program. The linkage editor enables data in one subprogram to be recognized in another
and facilitates transfer of control between subprograms at execution time.

Librarian. The operating system contains libraries on a disk known as SYSRES to


catalog both IBM programs and the installation's own commonly used programs and
subroutines. DOS/VS supports four libraries:
1. The source statement library (SSL) catalogs as a book any program, macro, or
subroutine still in source code. You can use the assembler directive COPY to include
cataloged code into your source program for subsequent assembling.
2. The relocatable library (RL) catalogs frequently used modules that are assembled but
not yet ready for execution. The assembler directs the linkage editor to include I/O
modules automatically, and you can use the INCLUDE command to direct the linkage
editor to include your own cataloged modules with your own assembled programs.
3. The core image library (CIL) contains phases in executable machine code, ready for
execution. The CIL contains; for example, the assembler, COBOL, PL/I, and other
translator programs, various utility programs such as LINK and SORT, and your own
production programs ready for execution. To request the supervisor to load a phase from
the CIL into main storage for execution, use the job control command
// EXEC phasename.
4. The procedure library (PL) contains cataloged job control to facilitate automatic
processing of jobs.
The OS libraries vary by name according to the version of OS, but basically the OS
libraries equivalent to the DOS source statement, relocatable, and core image are,
respectively, source library, object library, and load library, and they serve the same
functions.
Processing Programs
Processing programs are cataloged on disk in three groups:
1. Language translators that IBM supplies with the system include assembler, PL/I,
COBOL, and RPG.
2. Utility programs that IBM supplies include such special-purpose programs as disk
initialization, copy file–to–file, and sort/merge.

Page 520 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
3. User–written programs that users in the installation write and that IBM does not
support. All the programs in this text are user–written programs. For example, the job
command // EXEC ASSEMBLY causes the system to load the assembler from the CIL
into an available area ("partition") in storage and begins assembling a program. The job
command // OPTION LINK directs the assembler to write the assembled module on
SYSLNK in the relocatable library.
Once the program is assembled and stored on SYSLNK, the job command
// EXEC LNKEDT tells the linkage editor to load the module from SYSLNK into
storage, to complete addressing, and to include I/O modules from the RL. Assuming that
there was no job command to catalog it, the linkage editor writes the linked phase in
the CIL in a non–catalog area. If the next job command is // EXEC with no specified
phase name, the supervisor loads the phase from the non–catalog area into storage for
execution. The next program that the linkage editor links overlays the previous one in
the CIL non–catalog area.
The job command // OPTION CATAL instead of // OPTION LINK tells the system both
to link the program and to catalog the linked phase in the catalog area of the CIL. You
normally catalog production programs in the CIL and for immediate execution use the
job command // EXEC phase name.
MULTIPROGRAMMING
Multiprogramming is the concurrent execution of more than one program in storage.
Technically, a computer executes only one instruction at a time, but because of the fast
speed of the processor and the relative slowness of I/O devices, the computer's ability
to service a number of programs at the same time makes it appear that processing is
simultaneous. For this purpose, an operating system that supports multiprogramming
divides storage into various partitions and is consequently far more complex than a
single–job system.
The number and size of partitions vary according to the requirements of an installation.
One job in each partition may be subject to execution at the same time, although only one
program is actually executing. Each partition may handle jobs of a particular nature. For
example, one partition handles relatively short jobs of high priority, whereas another
partition handles large jobs of lower priority.
The job scheduler routes jobs to a particular partition according to its class. Thus a
system may assign class A to certain jobs, to be run in the first partition.
In Fig. 29–4, the job queue is divided into four classes, and main storage is divided into
three user partitions. Jobs in class A run in partition 1, jobs in classes B and C run in
partition 2, and jobs in class P run in partition 3.
Depending on the system, storage may be divided into many partitions, and a job class
may be designated to run in anyone of the partitions. Also, a partition may be designated
to run any number of classes.
When an operator uses the IPL procedure to boot the system, the supervisor is loaded
from the CIL into low storage. The supervisor next loads job control from the CIL into
the various partitions. The supervisor then scans the system readers and terminals for
job control commands.

Page 521 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
FIXED STORAGE LOCATIONS
As mentioned earlier, the first X'200' (decimal 512)bytes of storage are reserved for use
by the CPU. Figure 29–3 lists the contents of these fixed storage locations.

Figure 29–3 Fixed Storage Locations

Page 522 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
When a job completes processing, the job scheduler selects another job from the queue
to replace it. For example, if partition 1 is free, the job scheduler in Fig. 29–4 selects
from the class A queue either the job with the highest priority or, if all jobs have the
same priority, the first job in the queue.
The system has to provide a more or less equitable arrangement for processing jobs in
each partition. Under time slicing, each partition is allotted in turn a time slice of so many
milliseconds of execution. Control passes to the next partition when the time has expired,
the job is waiting for an I/O operation to complete, or the job is finished.

Figure 29–4 Job queue and partitions

VIRTUAL STORAGE
In a multiprogramming environment, a large program may not fit entirely in a partition.
As a consequence, both DOS/VS and OS/VS support a virtual storage system that divides
programs into segments of 64K bytes, which are in turn divided into pages of 2K or
(usually) 4K bytes. On disk, the entire program is contained as pages in a page data set,
and in storage VS arranges a page pool for as much of the program as it can store, as
shown in Fig. 29–5. As a consequence, a program that is 100K in size could run in a 64K
partition. If the executing program references an address for a part of the program that is
not in storage, VS swaps an unneeded page into the page data set on disk and pages in
the required page from disk into the page pool in storage. (Actually, VS swaps onto disk
only if the program has not changed the contents of the page.) The 16 control registers
handle much of the paging operations. Since a page from disk may map into any page in
the pool, VS has to change addresses; this process is known as dynamic address
translation (DAT).

Figure 29–5: Page Pool

Page 523 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
When running a real–time application such as process control, a data communications
manager, or an optical scan device, you may not want VS to page it out. It is possible to
assign an area of nonpageable (real) storage for such jobs or use a "page fix" to lock
certain pages into real storage.

PROGRAM STATUS WORD: PSW


The PSW is a doubleword of data stored in the control section of the CPU to control an
executing program and to indicate its status. The two PSW modes are basic control (BC)
mode and extended control (EC) mode. A 0 in PSW bit 12 indicates BC mode, and a 1
indicates EC mode. EC mode provides an extended control facility for virtual storage.
One of the main features of the PSW is to control the state of operation.

Figure 29–6: Two Variants of the PSW (Program Status Word)

Page 524 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
[Note by ELB: In the original S/360 design, bit 12 of the PSW was the ASCII bit, with
settings to allow running the computer with either EBCDIC characters (PSW12 = 0) or
ASCII characters PSW12 = 1.) The ASCII option was so little used that most system
managers were completely unaware that it existed. When the S/370 design with support
for virtual memory was introduced, the designers needed a bit to indicate what was
essentially “S/370 mode” rather than the older “S/360 mode”. Bit 12 was reassigned.]
Users of the system have no concern with certain operations such as storage management
and allocation of I/O devices, and if they were allowed access to every instruction, they
could inadvertently access other users' partitions or damage the system. To provide
protection, certain instructions, such as Start I/O and Load PSW, are designated as
privileged.
The PSW format is the same in only certain positions for .each mode. Figure 29–6, just
above, illustrates the two modes, in which the bits are numbered 0 through 63 from left to
right. Some of the more relevant fields are explained next.
Bit 14: Wait state. When bit 14 is 0, the CPU is in the running state and executing
instructions. When bit 14 is 1, the CPU is in wait state; which involves waiting for an
action such as an I/O operation to be completed.
Bit 15: State. For both modes, 0 = supervisor state and 1 = problem state. When the
computer is executing the supervisor program, the bit is 0 and all instructions are valid.
When in the problem state, the bit is 1 and privileged instructions cannot be executed.
Bits 16–31: Program interrupt code (BC mode). When a program interrupt occurs, the
computer sets these bits according to the type. The following list shows the interrupt
codes in hex format:
0001 Operation exception
0002 Privileged operation exception
0003 Execute exception
0004 Protection exception
0005 Addressing exception
0006 Specification exception
0007 Data exception
0008 Fixed–point overflow exception
0009 Fixed–point divide exception
000A Decimal overflow exception
000B Decimal divide exception
000C Exponent overflow exception
000D Exponent underflow exception
000E Significance exception
000F Floating–point divide exception
0010 Segment translation exception
0011 Page translation exception
0012 Translation specification exception
0013 Special operation exception
0040 Monitor event
0080 Program event (may be combined with another code)

Page 525 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Bits 34–35: Condition code. BC mode only; the condition code under EC mode is in bits
18–19. Comparisons and certain arithmetic instructions set this code.
Bits 40–63: Instruction address [Often called the PC, or Program Counter]. This area
contains the address of the next instruction to be executed. The CPU accesses the
specified instruction from main storage, decodes it in the control section, and executes it
in the arithmetic/logic section. The first 2 bits of a machine instruction indicate its length.
The CPU adds this length to the instruction address in the PSW, which now indicates the
address of the next instruction. For a branch instruction, the branch address may replace
the PSW instruction address.

INTERRUPTS
An interrupt occurs when the supervisor has to suspend normal processing to
perform a special task. The six main classes of interrupts are as follows:
1. Program Check Interrupt. This interrupt occurs when the computer cannot execute an
operation, such as performing arithmetic on invalid packed data.
This is the common type of interrupt when a program terminates abnormally.
2. Supervisor Call Interrupt. A problem program may issue a request for input/output or
to terminate processing. A transfer from the problem program to the supervisor requires
a supervisor call (SVC) operation and causes an interrupt.
3. External Interrupt. An external device may need attention, such as the operator
pressing the request key on the console or a request for communications.
4. Machine Check Interrupt. The machine–checking circuits may detect a hardware error,
such as a byte not containing an odd number of on bits (odd parity). [Note by ELB:
This refers to parity memory, in which an 8–bit byte is stored as 9 bits in memory, with
the extra bit (not transferred to the CPU) being the parity bit.]
5. Input/Output Interrupt. Completion of an I/O operation making a unit available or
malfunction of an I/O device (such as a disk head crash) cause this interrupt.
6. Restart Interrupt. This interrupt permits an operator or another CPU to invoke
execution of a program.
The supervisor region contains an interrupt handler for each type of interrupt. On an
interrupt, the system alters the PSW as required and stores the PSW in a fixed storage
location, where it is available to any program for testing.
The PSW discussed to this point is known as the current PSW. When an interrupt occurs,
the computer stores the current PSW and loads a new PSW that controls the new
program, usually the supervisor. The current PSW is in the control section of the CPU,
whereas the old and new PSWs are stored in main storage, as the following indicates:

Page 526 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
The interrupt replaces the current PSW in this way. (1) It stores the current PSW into
main storage as the old PSW, and (2) it fetches a new PSW from main storage, to become
the current PSW. The old PSW now contains in its instruction address the location
following the instruction that caused the interrupt. The computer stores the Program
Status Words in 12 doubleword locations in fixed storage; 6 are for old PSWs and 6 are
for new PSWs, depending on the class of interrupt. There are eight bytes allocated for
each PSW; for this reason the following addresses appear to be decimal numbers.
Interrupt Type Old PSW New PSW
Restart 0008 0000
External 0024 0088
Supervisor Call 0032 0096
Program Old PSW 0040 0104
Machine Check 0048 0112
Input/Output 0056 0120
Let's trace the sequence of events following a supervisor interrupt. Assume that the
supervisor has stored the address of each of its interrupt routines as bits 40–63 of the
PSW that is stored in the address associated with its interrupt type. Loading the CPU
Program Status Word with the “New PSW” associated with an interrupt type essentially
starts the interrupt handler on the next instruction.
Remember also that when an instruction executes, the computer updates the instruction
address and the condition code in the current PSW (in the CPU) as required.
1. A program requests input from disk. The GET or READ macro contains a
SVC (Supervisor Call) to link to the supervisor [ELB: a part of the Operating
System] for input/output. This is a supervisor interrupt.
2. The instruction address in the current PSW contains the address in the
program immediately following the SVC that caused the interrupt. The CPU
stores this current PSW in the old PSW for supervisor interrupt, location 32.
The new PSW for supervisor interrupt, location 96, contains supervisor state
bit = 0 and the address of the supervisor interrupt routine. The CPU moves
this new PSW to the current PSW and is now in the supervisor state.
3. The PSW instruction address contains the address of the supervisor I/O
routine, which now executes. The channel scheduler requests the channel for
disk input.
4. To return to the problem program, the supervisor loads the old PSW from
location 32 back into the current PSW. The instruction links to the PSW
instruction address, which is the address in the program following the
original SVC that caused the interrupt. The system switches the PSW from
supervisor state back to problem state.
[ELB Note: This design reflects some older strategies that had yet to take full advantage
of dynamic memory organizations, based on use of the stack and heap.]

Page 527 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
In the event of a program check interrupt, the computer sets its cause on PSW bits 16-31,
the program interrupt code. For example, if the problem program attempts arithmetic on
invalid data, the computer senses a data exception and stores X'0007' in PSW bits 16-31.
The computer then stores the current PSW in old PSW location 0040 and loads the new
PSW from 0104 into the current PSW. This PSW contains the address of the supervisor's
program check routine, which tests the old PSW to determine what type of program
check caused the interrupt.
The supervisor displays the contents of the old PSW in hexadecimal and the cause of the
program check (data exception), flushes the interrupted program, and begins processing
the next job. Suppose that the invalid operation is an MP [Multiply Packed] at location
X'6A320'. Since MP is 6 bytes long, the instruction address in the PSW and the one
printed will be X'6A326'. You can tell from the supervisor diagnostic message that the
error is a data exception and that the invalid operation immediately precedes the
instruction at X'6A326'.
CHANNELS
A channel is a component that functions as a separate computer operated by channel
commands to control I/O devices. It directs data between devices and main storage and
permits attaching a great variety of I/O devices. The more powerful the computer model,
the more channels it may support. The two types of channels are multiplexer and selector.
1. Multiplexer channels are designed to support simultaneous operation of more than one
device by interleaving blocks of data. The two types of multiplexer channels are byte-
multiplexer and block-multiplexer. A byte-multiplexer channel typically handles low-
speed devices, such as printers and terminals.
A block-multiplexer can support higher-speed devices, and its ability to interleave blocks
of data facilitates simultaneous I/O operations.
2. Selector channels, no longer common, are designed to handle high–speed devices,
such as disk and tape drives. The channel can transfer data from only one device at a
time, a process known as burst mode.
Each channel has a 4–bit address coded as in the following example:
CHANNEL ADDRESS TYPE
0 0000 byte-multiplexer
1 0001 block-multiplexer
2 0010 block-multiplexer
3 0011 block-multiplexer
4 0100 block-multiplexer
5 0101 block-multiplexer
6 0110 block-multiplexer
A control unit, or controller, is required to interface with a channel. A channel is
basically device–independent, whereas a control unit is device–dependent.

Page 528 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Thus a block-multiplexer channel can operate many type of devices, but a disk drive
control unit can operate only a disk drive. Figure 29–7 illustrates a typical configuration
of channels, control units, and devices.

Figure 29–7: Channels, Control Units, and Devices


For example, a computer uses a multiplexer channel to connect it to a printer's control
unit. The control unit has a 4–bit address. Further, each device has a 4–bit address and is
known to the system by a physical address. The device address is therefore a 12–bit code
that specifies:
DEVICE CODE
Channel 0CCC
Control unit UUUU
Device DDDD
If the printer's device number is 1110 (X'E') and it is attached to channel 0, control unit 1,
then to the system its physical address is 0000 00011110, or X'01E'. Further, if two disk
devices are numbered 0000 and 0001 and they are both attached to channel 1, control unit
9, their physical addresses are X'190' and X'191', respectively.
This physical address permits the attaching of 28 , or 256 devices.

Symbolic Assignments
Although the supervisor references IJO devices by their physical numbers, your programs
use symbolic names. You may assign a symbolic name to any device temporarily or
(more or less) permanently, and a device may have more than one symbolic name
assigned. The operating system uses certain names, known as system logical units, that
include the following.
In addition, you may reference programmer logical units, SYS000-SYSnnn.

Page 529 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
SYSIPT
The terminal, system reader, or disk device used as input for programs
SYSRDR
The terminal, system reader, or disk device used as input for job control for the system
SYSIN
The system name to assign both SYSIPT and SYSRDR to the same terminal, system
reader, or disk device
SYSLST
The printer or disk used as the main output device for the system
SYSPCH
The device used as the main unit for output
SYSOUT
The system name to assign both SYSLST and SYSPCH to the same output device
SYSLNK
The disk area used as input for the linkage editor
SYSLOG
The console or printer used by the system to log operator messages and job control
statements
SYSRES
The disk device where the operating system resides
SYSRLB
The disk device for the relocatable library
SYSSLB
The disk device for the system library
For example, you may assign the logical address SYS025 to a disk drive with physical
address X'170'. The supervisor stores the physical and logical addresses in an I/O devices
control table in order to relate them. A simplified table could contain the following:
I/O Device Physical Address Logical Units
Reader X‘00C’ SYSIPT, SYSRDR
Printer X‘00E’ SYSLST
Disk Drive X‘170’ SYSLNK, SYSRES, SYS025
Tape Drive X‘280’ SYS031, SYS035
A reference to SYSLST is to the printer, and a reference to SYSLNK, SYSRES, or
SYS025, depending on its particular use, is to disk device X'170'. You may assign a
logical address permanently or temporarily and may change logical addresses from job to
job. For instance, you could use an ASSGN job control command to reassign SYS035 for
a program from a disk device X'170' to another disk device X'l72'.

Page 530 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
I/O LOGIC MODULES
Consider a program that reads a tape file named TAPEFL. The program would require a
DTFMT or DCB file definition macro to define the characteristics of the file and tape
device to generate a link to an I/O logic module. The assembler determines which
particular logic module, based on (1) the kind of DTF and (2) the specifications within
the file definition, such as device number, an input or output file, the number of buffers,
and whether processing is in a work area (WORKA) or a buffer (IOREG). In the
following example, the assembler has generated a logic module named DFFBCWZ (the
name would vary depending on specifications within the DTFMT).

When linking a program, the linkage editor searches for addresses in the external symbol
dictionary that the assembler generates. For this example, the ESD would contain entries
at least for the program name and UFFBCWZ. The linker accesses the named module
cataloged on disk (provided it was ever cataloged) and includes it at the end of the
assembled object program. One role of a system programmer is to define and catalog
these I/O modules.
On execution of the program, the GET macro links to the specified file definition macro,
DTFMT. This macro contains the address of the I/O logic module at the end of the object
program where the linker included it. The module, combined with information from the
DTFMT, contains all the instructions necessary to notify the supervisor as to the actual
type of I/O operation, device, block size, and so forth.
The only remaining information is to determine which tape device; the supervisor derives
it from the job control entry, which in this example assigns X'281' as the physical
address. The supervisor then (at last) delivers the physical request for input via a channel
command.
For example, the printer module, PRMOD, consists of three letters (IJD) and five option
letters (abcde), as IJDabcde. The options are based on the definitions in the DTFPR
macro, as follows:
a RECFORM: FlXUNB (F), VARUNB (V), UNDEF (U)
b CILCHR: ASA (A), YES (Y), CONTROL (C)
c PRINTOV=YES and ERROPT=YES (B), PRINTOV=YES and
ERROPT not specified (Z), plus 14 other options
d IOAREA2: defined (I), not defined (Z)
e WORKA: YES (W), YES and RDONLY= YES (V), neither specified (Z)
A common printer module for IBM control character; two buffers, and a work area would be
IJDFYZIW. For one buffer, the module is IJDFYZZW.

Page 531 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
PHYSICAL IOCS
Physical I0CS (PIOCS), the basic level of I0CS, provides for channel scheduling, error
recovery, and interrupt handling.. When using PIOCS, you write a channel program (the
channel command word) and synchronize the program with completion of the I/O
operation. You must also provide for testing the command control block for certain
errors, for checking wrong–length records, for switching between I/O areas where two
are used, and, if records are blocked, for blocking and deblocking.
PIOCS macros include CCW, CCB, EXCP, and WAIT.
Channel Command Word (CCW)
The CCW macro causes the assembler to construct an 8–byte channel command word that defines
the I/O command to be executed.
Name Operation Operand
[LABEL] CCW command–code, data–address, flags, count–field
• command-code defines the operation to be performed, such as 1 = write, 2 = read,
X'09' = print and space one line.
• data-address provides the storage address of the first byte where data is to be read or
written.
• flag bits determine the next action when the channel completes an operation defined in a
CCW. You can set flag bits to 1 to vary the channel's operation (explained in detail
later).
• count-field provides an expression that defines the number of bytes in the data block
that is to be processed.
Command Control Block (CCB)
You define a CCB macro for each I/O device that PIOCS macros reference. The CCB
comprises the first 16 bytes of most generated DTF tables. The CCB communicates
information to PIOCS to cause required I/O operations and receives status information
after the operation.
Name Operation Operand
[LABEL] CCB SYSnnn, command–list–name
• blockname is the symbolic name associated with the CCB, used as an old PSW for the
EXCP and WAIT macros.
• SYSnnn is the symbolic name of the 110 device associated with the CCB.
• command-list-name is the symbolic name of the first CCW used with the CCB.
Execute Channel Program (EXCP)
The EXCP macro requests physical I0CS to start an I/O operation, and PIOCS relates the block
name to the CCB to determine the device. When the channel and the device become available, the
channel program is started. Program control then returns to your program.
Name Operation Operand
[LABEL] EXCP block–name or (1)
The operand gives the symbolic name of the CCB macro to be referenced.
Page 532 Chapter 29 Revised March 13, 2010
Copyright © 2010 by Edward L. Bosworth, Ph.D.
The WAIT Macro
The WAlT macro synchronizes program execution with completion of an I/O operation, since the
program normally requires its completion before it can continue execution. (When bit 0 of byte 2 of
the CCB for the file is set to 1, the WAlT is completed and processing resumes.) For example, if you
have issued an EXCP operation to read a data block, you now WAlT for delivery of the entire block
before you can begin processing it.
Name Operation Operand
[LABEL] WAIT block–name or (1)

CCW Flag Bits


You may set and use the flag bits in the CCW as follows:
• Bit 32 (chain data flag), set by X'80', specifies data chaining. When the CCW has
processed the number of bytes defined in its count field, the I/O operation does not
terminate if this bit is set. The operation continues with the next CCW in storage. You
may use data chaining to read or write data into or out of storage areas that are not
necessarily adjacent.
In the following three CCWs, the first two use X'80' in the flag bits, operand 3, to specify
data chaining. An EXCP and CCB may then reference the first CCW, and as a result, the
chain of three CCWs causes the contents of an 80–byte input record to be read into three
separate areas in storage: 20 bytes in NAME, 30 bytes in ADDRESS, and 30 bytes in
CITY.
DATCHAIN CCW 2,NAME,X'80',20 Read 20 bytes into NAME,
and chain.
CCW ,ADDRESS,X'80',30 Read 30 bytes to ADDRESS,
and chain.
CCW ,CITY,X'00',30 Read 30 bytes into CITY,
and terminate.
• Bit 33 (chain command flag), set by X'40', specifies command chaining to enable the
channel to execute more than one CCW before terminating the I/O operation.
Each CCW applies to a separate I/O record.
The following set of Channel Command Words could provide for reading three input
blocks, each 100 bytes long:
COMCHAIN CCW 2,INAREA,X'40',100 Read record-l into
INAREA, chain.
CCW 2,INAREA+100,X'40',100 Read record-2 into
INAREA+l00, chain.
CCW 2,INAREA+200,X'00',100 Read record-3 into
INAREA+200, stop.

Page 533 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
• Bit 34 (suppress length indication flag), set by X'20', is used to suppress an error
indication that occurs when the number of bytes transmitted differs from the count in the
CCW.
• Bit 35 (skip flag), set by X'10', is used to suppress transmission of input data. The
device actually reads the data, but the channel does not transmit the record.
• Bit 36 (program controlled interrupt flag), set by X'08', causes an interrupt when this
CCW's operation is complete. (This is used when one supervisor SIO instruction executes
more than one CCW.)
• Bit 37 (indirect data address flag), as well as other features about physical IOCS, is
covered in the IBM Principles of Operation manual and the appropriate supervisor
manual for your system.
Sample Physical IOCS Program
The program in Fig. 29–8 illustrates many of the features of physical IOCS we have
discussed. It performs the following operations:
• At initialization, prints three heading lines by means of command chaining (X'40').
• Reads input records one at a time containing salesman name and company.
• Prints each record.
• Terminates on reaching end–of–file.
Note that the program defines a CCB/CCW pair for each type of record, and the
EXCP/WAIT operations reference the CCB name – INDEVIC for the reader, OUTDEV1
for heading lines, and OUTDEV2 for sales detail lines. Each CCB contains the name of
the I/O device, SYSIPT or SYSLST, and the name of an associated CCW: INRECD,
TITLES, and DETAIL, respectively.

Page 534 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Figure 29–8: Physical IOCS

Page 535 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
KEY POINTS

• Systems generation (sysgen) involves tailoring the supplied operating system to the
installation's requirements, such as the number and type of disk drives, the number and
type of terminals to be supported, the amount of process time available to users, and the
levels of security that are to prevail.
• The control program, which controls all other programs being processed, consists of
initial program load (IPL), the supervisor, and job control. Under OS, the functions are
task management, data management, and job management.
• Initial program load (IPL) is a program that the operator uses daily or whenever
required to load the supervisor into storage. The system loader is responsible for loading
programs into main storage for execution.
• The supervisor resides in lower storage, beginning at location X'200'. The supervisor is
concerned with handling interrupts for input/output devices, fetching required modules
from the program library, and handling errors in program execution.
• Channels provide a path between main storage and the input/output devices and permit
overlapping of program execution with I/O operations. The channel scheduler handles
all I/O interrupts.
• Storage protection prevents a problem program from erroneously moving data into the
supervisor area and destroying it.
• An interrupt is a signal that informs the system to interrupt the program that is currently
executing and to transfer control to the appropriate supervisor routine.
• The source statement library (SSL) catalogs as a book any program, macro, or
subroutine still in source code.
• The relocatable library (RL) catalogs frequently used modules that are assembled but
not yet ready for execution.
• The core image library (CIL) contains phases in executable machine code, ready for
execution.
• Multiprogramming is the concurrent execution of more than one program in storage. An
operating system that supports multiprogramming divides storage into various
partitions. One job in each partition may be subject to execution at the same time,
although only one program is actually executing.
• The PSW is stored in the control section of the CPU to control an executing program
and to indicate its status. The two PSW modes are basic control mode (BC) and
extended control (EC) mode.
• Certain instructions such as Start I/O and Load PSW are privileged to provide
protection against users' accessing the wrong partitions.
• An interrupt occurs when the supervisor has to suspend normal processing to perform a
special task. The supervisor region contains an interrupt handler for each type of
interrupt.

Page 536 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
• A channel is a component that functions as a separate computer operated by channel
commands to control I/O devices. It directs data between devices and main storage and
permits the attachment of a variety of I/O devices.
The two types are multiplexer and selector.
• The operating system uses certain names, known as system logical units, such as
SYSIPT, SYSLST, and SYSLOG. Programmer logical units are referenced as SYS000-
SYSnnn.
• Physical IOCS (PIOCS), the basic level of IOCS, provides for channel scheduling, error
recovery, and interrupt handling. When using PIOCS, you write a channel program (the
channel command word) and synchronize the program with completion of the I/O
operation. .
• The CCW macro causes the assembler to construct an 8–byte channel command word
that defines the I/O command to be executed.

Page 537 Chapter 29 Revised March 13, 2010


Copyright © 2010 by Edward L. Bosworth, Ph.D.
Appendix A – The EBCDIC Character Set
The EBCDIC (Extended Binary Coded Decimal Interchange Code) was developed in 1963 and
1964 by IBM for use on its System/360 line of computers. It was created as an extension of the
BCD (Binary Coded Decimal) encoding that existed at the time.
EBCDIC code uses eight binary bits to encode a character set; it can encode 256 characters. The
codes are binary numeric values, traditionally represented as two hexadecimal digits.
Character codes 0x00 through 0x3F and 0xFF represent control characters.
0x0D is the code for a carriage return; this moves the cursor back to the left margin.
0x20 is used by the ED (Edit) instruction to represent a packed digit to be printed.
0x21 is used by the ED (Edit) instruction to force significance.
All digits, including leading 0’s, from this position will be printed.
0x25 is the code for a line feed; this moves the cursor down but not horizontally.
0x2F is the BELL code; it causes the terminal to emit a “beep”.
Character codes 0x40 through 0x7F represent punctuation characters.
0x40 is the code for a space character: “ ”.
0x4B is the code for a decimal point: “.”.
0x4E is the code for a plus sign: “+”.
0x50 is the code for an ampersand: “&”.
0x5B is the code for a dollar sign: “$”.
0x5C is the code for an asterisk: “*”.
0x60 is the code for a minus sign: “–”.
0x6B is the code for a comma: “,”.
0x6F is the code for a question mark: “?”.
0x7C is the code for the commercial at sign: “@”.
Character codes 0x81 through 0xA9 represent the lower case Latin alphabet.
0x81 through 0x89 represent the letters “a” through “i”,
0x91 through 0x99 represent the letters “j” through “r”, and
0xA2 through 0xA9 represent the letters “s” through “z”.
Character codes 0xC1 through 0xE9 represent the upper case Latin alphabet.
0xC1 through 0xC9 represent the letters “A” through “I”,
0xD1 through 0xD9 represent the letters “J” through “R”, and
0xE2 through 0xE9 represent the letters “S” through “Z”.
Character codes 0xF0 through 0xF9 represent the digits “0” through “9”.
NOTES:
1. The control characters are mostly used for network data transmissions.
The ones listed above appear frequently in user code for terminal I/O.
2. There are gaps in the codes for the alphabetical characters.
This is due to the origins of the codes for the upper case alphabetic characters
in the card codes used on the IBM–029 card punch.
3. One standard way to convert an EBCDIC digit to its numeric value
is to subtract the hexadecimal number 0xF0 from the character code.

Copyright © 2009 by Edward L. Bosworth, Ph.D.


An Abbreviated Table: The Common EBCDIC
Code Char. Comment Code Char. Comment Code Char. Comment
80 C0 } Right brace
81 a C1 A
82 b C2 B
83 c C3 C
84 d C4 D
85 e C5 E
86 f C6 F
87 g C7 G
0C FF Form feed 88 h C8 H
0D CR Return 89 i C9 I
16 BS Back space 90 D0 { Left brace
25 LF Line Feed 91 j D1 J
27 ESC Escape 92 k D2 K
2F BEL Bell 93 l D3 L
40 SP Space 94 m D4 M
4B . Decimal 95 n D5 N
4C < 96 o D6 O
4D ( 97 p D7 P
4E + 98 q D8 Q
4F | Single Bar 99 r D9 R
50 & A0 E0 \ Back slash
5A ! A1 ~ Tilde E1
5B $ A2 s E2 S
5C * A3 t E3 T
5D ) A4 u E4 U
5E ; A5 v E5 V
5F Not A6 w E6 W
60 – Minus A7 x E7 X
61 / Slash A8 y E8 Y
6A ¦ Dbl. Bar A9 z E9 Z
6B , Comma B0 ^ Carat F0 0
6C % Percent B1 F1 1
6D _ Underscore B2 F2 2
6E > B3 F3 3
6F ? B4 F4 4
79 ‘ Apostrophe B5 F5 5
7A : Colon B6 F6 6
7B # Sharp B7 F7 7
7C @ At Sign B8 F8 8
7D ' Apostrophe B9 F9 9
7E = Equals BA [ Left Bracket
7F " Quote BB ] R. Bracket

Copyright © 2009 by Edward L. Bosworth, Ph.D.


Part 2: External Storage and File Processing
Chapters 25 through 29 of this textbook cover external storage, file processing, and parts of a
number of operating systems. As indicated below, these chapters are copied almost verbatim
from an earlier textbook by Mr. Peter Abel, who at the time of writing the book was a faculty
member at the British Columbia Institute of Technology. These sections are used with
explicit written permission of Mr. Abel.

This textbook started as a set of notes for a course based on the textbook “Programming
Assembler Language: IBM® 370 Series Architecture and Assembly Language”, the
textbook mentioned above. Mr. Abel first published the textbook in 1979, with revisions in
1984 and 1989; these sections are based on chapters from the third edition. The book was
published by Prentice–Hall with ISBN 0 – 13 – 728924 – 3.

The textbook is currently out–of–print. According to the publisher, all authorship rights have
been returned to Mr. Abel, who kindly granted permission to use this material.

Were Mr. Abel’s textbook not out–of–print, this textbook would not have been written. As it
is, copies of the book in remarkable good condition can be purchased from a number of web
sites. The author of this textbook owns a good copy of Mr. Abel’s textbook, which he
purchased for $7.00. The book is a classic for all those who want to understand the IBM
Enterprise Server architecture, as of 2010 embodied in the System Z.

Chapter 25 of this textbook (External Storage) is an almost verbatim copy of


Chapter 17 in the Third Edition of Mr. Abel’s textbook.
Chapter 26 of this textbook (Sequential File Organization) is an almost verbatim copy of
Chapter 18 in the Third Edition of Mr. Abel’s textbook.
Chapter 27 of this textbook (ISAM) is a revision of material in Chapter 20 in the Third
Edition of Mr. Abel’s textbook. At the time of writing this textbook, the ISAM has become
less important than in the time of Mr. Abel’s writing, having become a part of VSAM.
Chapter 28 of this textbook (VSAM) is an almost verbatim copy of a large part of
Chapter 19 in the Third Edition of Mr. Abel’s textbook.
Chapter 29 of this textbook (External Storage) is an almost verbatim copy of
Chapter 21 in the Third Edition of Mr. Abel’s textbook.

You might also like