Professional Documents
Culture Documents
David Woolbright's Assembly Tutorial
David Woolbright's Assembly Tutorial
Contents
CPSC 3121/3122 Resources
The following is a list of links to articles covering a variety of topics in IBM System/390 Assembly language.
The following table is a collection of links to individual articles covering all the major instructions (used by
application programmers) in the IBM System 390 architecture. Each article contains a description of the instruction,
example uses of the instruction, and "tips" on technique.
A AH AP AR BAS BASR BC BCT BCTR CLC
CLI CH CP CR C CVB CVD D DP
DR ED EDMK EX IC ICM L LA LCR
LM LNR LH LPR LR LTR M MP MH
MR MVC MVCL MVI MVN MVZ N NC NI
NR O OC OI OR PACK S SLA SLDA
SLDL SLL SRA SRDA SRDL SRL SRP ST STC
STH STM SH SP SR TM TR TRT UNPK
One of the basic skills a programmer needs is the ability to convert numbers between decimal, hexadecimal, and binary. This
article will demonstrate the conversions between each of these bases.
Decimal to Hexadecimal
Here is an algorithm to convert a decimal integer to hexadecimal:
1) Let X be the decimal integer you wish to convert and let k = 1.
2) Divide X by 16, saving the quotient as Q, and the remainder (in hexadecimal) as R k .
3) If Q is not zero, let X = Q, k = k + 1, and go back to step 2. Otherwise go to step 4.
4) Assume steps 1-3 were repeated n times. Arrange the remainders as a string of digits - R n R n-1 R n-2 …R 3 R 2 R 1 .
Here is an example where we number and describe each iteration of the algorithm:
1) Let X = 954 and let k = 1. Dividing by 16 we have Q = 59 and R 1 = A (10 = A in hexadecimal). Since Q is not zero, we let X
= 59 and go back to start the second iteration.
2) Dividing X = 59 by 16, we have Q = 3 and R 2 = B since 11 = B in hexadecimal. Since Q is not zero, we let X = 3 and start
the third iteration.
3) Dividing X = 3 by 16, we have Q = 0 and R3 = 3. Since Q = 0, the loop terminates and the algorithm is completed by
arranging the remainders as “3BA”.
Here is another example using long division. In this example we convert 2623 in decimal to A3F in hexadecimal. The
computations move from right to left.
Hexadecimal to Decimal
Consider the problem of converting the hexadecimal number A3B7 to decimal. Each hexadecimal digit in the representation
represents a number of occurrences of a power of 16. We can change each hexadecimal digit to its decimal equivalent and
multiply by the corresponding power of 16. Totaling the components produces the decimal representation of the original
hexadecimal number.
Binary to Decimal
In the representation of a binary integer, each 1 indicates the occurrence of the corresponding power of 2. To convert to
decimal, we simply compute the total of the powers of 2 which correspond to a 1. Consider the following example in which we
convert 1101110 to a decimal representation.
1 = 1 x 26 = 64
1 = 1 x 25 = 32
0 = 0 x 24 = 0
1 = 1 x 23 = 8
1 = 1 x 22 = 4
1 = 1 x 21 = 2
0 = 0 x 20 = 0
Total = 110
Here is another example in which 100111 is converted to 39 in decimal.
5
Binary to Hexadecimal
Converting from binary to hexadecimal involves replacing each consecutive block of four bits in the binary representation (moving
from right to left within the representation) with its hexadecimal equivalent. You may need to add 0’s on the left of the binary
representation in order that the number of 1’s and 0’s is a multiple of 4. Consider the following conversion.
Each block of four bits beginning with 1010 is replaced with one hexadecimal digit. The leftmost 2 digits 11 are treated as 0011
and converted to “3”.
The term “machine architecture” refers to the design of the electronic components that comprise a computer. Since we are
studying assembly language, we are most interested in the design of the components that directly affect the assembler programs
we write. These components include Memory, Registers, the Program Status Word, and the CPU. The orginal architecture was
designed in the early 1960’s and was know as the System 360. The “360” in the name referred to 360 degrees - the number of
degrees in a circle. (System 360 machines were supposed to be be “all-purpose” machines, capable of handling business as well
as scientific applications. ) In the early 1970’s the architecture was modified to allow access to larger amounts of memory and was
known as the System 370 architecture. The architecture has continued to evolve and today is known as the System 390.
Throughout this evolution, the architecture has remained “backwards compatible”. In fact, programs that were written to run on
1960’s era machines can run on current machines with little or no change in their code. The IBM mainframe has been an
incredibly stable platform and this fact has accounted for much of the success of this family of machines. We begin our discussion
of the architecture by looking first at the main storage memory of the machine.
MEMORY
The smallest unit of storage memory is a bit (binary digit). A bit can hold a binary digit, 0 or 1, and is represented internally in
the machine as a high or low voltage. Bits are organized into consecutive groups called bytes. In the System 390 architecture, a
byte consists of 8 bits together with a “hidden” ninth bit that is used for parity checking. Since the parity bit is unavailable to us as
programmers, we will assume that there are 8 bits in a byte. With 8 bits there are 2 8 = 256 possible bit patterns that can be made.
Binary Pattern Decimal Equivalent
00000000 = 0
00000001 = 1
00000010 = 2
00000011 = 3
00000100 = 4
...
11111101 = 253
11111110 = 254
11111111 = 255
Each of the 256 bit patterns is used to represent one character of data in the EBCDIC encoding sequence. “EBCDIC” is an
acronym for “Extended Binary Coded Decimal Interchange Code”. This is a fancy name for a code created by IBM to represent
characters in memory. For instance 11000001 represents a character “A” , and 11110001 represents a character ‘1’ in the
EBCDIC encoding sequence. “ASCII” is another binary code which is used on non-IBM machines. See the article on Character
Data for more details.
Each byte can be divided into two 4-bit areas called the zone and numeric portions as pictured below. Programmers will refer to
a half-byte as a “nibble” or sometimes “nybble”. This is a colloquial term that is not found in the IBM documentation.
Nevertheless, bits 0 - 3 are called the “High Order Nibble” and bits 4 - 7 are called the “Low Order Nibble”.
Bytes are arranged consecutively and numbered, starting with the first byte, which is numbered 0 as indicated in the diagram
below. The number assigned to each byte is called an address. The idea of an address is an important one when learning to
program in assembly language since every reference to memory is made using an address. This idea will be thoroughly developed
in the article on Base/Displacement Addressing.
A byte is the smallest unit of storage on the machine that has an address. Bits do not have addresses.
Consecutive bytes are arranged into groups called fields. The address of a field is denoted by the address of the first byte that
is in the field. A halfword is a 2-byte field that begins on an address that is evenly divisible by 2 ( Addresses 0, 2, 4, 6, ...). Such
an address is called a halfword boundary. A fullword is a 4-byte field that begins on a fullword boundary (an address evenly
divisible by 4). A doubleword is an 8-byte field that begins on a doubleword boundary (an address that is evenly divisible by
8). In the diagram above there are 3 halfwords pictured (bytes 0 and 1, bytes 2 and 3, and bytes 4 and 5), 1 fullword ( bytes
0,1,2, and 3 ), and the beginning of a doubleword ( bytes 0 - 8).
There are several terms that are commonly used to describe blocks of memory:
1) kilobyte = 2 10 = 1,024 bytes
2) megabyte =220 = 1,048,576 bytes
3) gigabyte =230 = 1024 megabytes
The original System 360 architecture, which was designed in the early 1960’s, called for a 24-bit address size when referring to
bytes in main storage. With 24 bits, the maximum address which could be constructed (24 consecutive binary 1’s) is 2 24 - 1 = 16
megabytes. The architecture was extended in the 1970’s in order to support 31-bit addresses. Today, the machine is capable of
creating addresses as large as 2 31 - 1 = 2 gigabytes.
REGISTERS
A register consists of special circuitry devoted to high speed arithmetic, addressing main storage locations, and providing control
information for the operating system. There are 3 types of registers:
1) General purpose - There are 16 general purpose registers numbered 0 through 15 that are available to an assembler
programmer. These registers are used for high-speed arithmetic and addressing storage locations. Each general purpose register
is 32 bits in length - just large enough to hold a fullword.
2) Floating point - There are 4 floating point registers available for an assembler programmer. These registers are used for
scientific data processing where the data is quite large or has a large number of decimal places. Each floating point register is 64
bits in length.
3) Control - There are 16 control registers used by the operating system to control the operation of the machine. These
Character data is created by specifying a “C” for the type in a DC or DS declarative. In this format, each character occupies 1
byte of storage. Characters are represented using the EBCDIC encoding sequence where each character is presented using 8
bits. As a result, there are 2 8 = 256 possible bit patterns or characters which can be formed.
A character field can be created using either of the following formats,
name DC dCLn’constant’
or
name DS dCLn
where ‘name’ is an optional field name
‘d’ is a duplication factor used to create consecutive copies of the field (default = 1 copy)
‘C’ represents the character data type
‘L’ represents an optional length (default = 1 byte)
‘n’ is the number of bytes in the field
‘constant’ is an initial value of the field in character format.
It is important to note that if a name for a field is specified, it will represent the address of the first byte of the field. Additionally,
the name of the field will be associated with a length attribute which equals the number of bytes in the field. If the “Ln”
construction is omitted in a DS, the length will default to 1 byte. If the “Ln” construction is omitted in a DC, the length of the
constant determines the field length. The length of a field defined using DC is limited to a maximum of 256 bytes and the length of
a field defined using DS is 65,535 bytes.
When specifying a constant, the length of the constant and the length of the field may differ in size. If the length of the constant
is shorter than the field length, the assembler will pad the constant on the right with blanks to fill up the field. If the constant is
longer than the field, the constant will be truncated on the right so that it will fit inside the field. The assembler does not generate
a warning message when this occurs.
During assembly, fields that were defined consecutively in the source code with DC’s or DS’s, are assigned consecutive storage
locations in the program according to the value of the location counter which is maintained by the assembler. For example, in the
fields below, if FIELDA is associated with address x’1000’, then FIELDB is located at x’1003’ and FIELDC is located at x’100C’.
LOCATION
1000 FIELDA DS CL3
1003 FIELDB DS CL9
100C FIELDC DS CL3
An exception to sequential allocation of fields occurs if the duplication factor is specified as 0. In this case the location counter is
not advanced and the next field redefines the previous field. Consider the following example and note the location counter values.
LOCATION
1000 FIELDA DS 0CL5
1000 FIELDB DC CL2’AB’
1006 FIELDC DC CL3’CDE’
In this case, FIELDB and FIELDC are allocated addresses “inside” FIELDA.
1. A common coding error that occurs when defining a field with a constant, is to choose DS instead of DC. Consider the
following example,
LNAME DS CL10’SMITH’
On first glance, the code appears correct, and in fact, it is syntactically correct. The assembler will not complain about the
construction. But the constant is treated as a comment and the field remains uninitialized.
2. Pay careful attention to the constants you provide. If the constant is too long, it will be truncated. If it is too short, it will be
padded with blanks.
3. Learn to recognize a working subset of characters and their hexadecimal equivalents. The list below ,consisting of the alphabet,
a blank, the digits, and some punctuation symbols, is a good start.
Character Hex Equivalent Character Hex Equivalent
A C1 0 F0
B C2 1 F1
C C3 2 F2
D C4 3 F3
E C5 4 F4
F C6 5 F5
G C7 6 F6
H C8 7 F7
I C9 8 F8
J D1 9 F9
K D2 BLANK 40
L D3 ,(COMMA) 6B
Packed decimal data fields are created by specifying a “P” for the type in a DC or DS declarative. In this format, when
assembled, each byte in the field contains 2 decimal digits except the right-most byte in the field which contains a decimal digit
followed by a sign. The valid positive signs are the hexadecimal characters A, C, E, and F. The valid negative signs are the
hexadecimal characters B and D. The “preferred” signs, those which are generated by the machine or chosen by the assembler,
are positive “C” and negative “D”. It is standard practice to use “C” and “D”, but be aware that the other signs are recognized as
well. Consider the two fields defined below,
AMOUNT1 DC PL3’+20’
AMOUNT2 DC PL2’-34’
In the first example the assembler generates x’00020C’ for AMOUNT1 and x’034D’ for AMOUNT2.
A packed decimal field can be created using either of the following formats,
name DC dPLn’constant’
or
name DS dPLn
where ‘name’ is an optional field name
‘d’ is a duplication factor used to create consecutive copies of the field (default = 1copy)
‘P’ represents the packed decimal data type
‘L’ represents an optional length (default = 1 byte)
‘n’ is the number of bytes in the field
‘constant’ is the initial value of the field in decimal format. Optionally, a decimal
point and a + or - sign can be coded but the decimal point is not assembled.
It is important to note that if a name for a field is specified, it will represent the address of the first byte of the field. Additionally,
the name of the field will be associated with a length attribute which equals the number of bytes in the field. If the “Ln”
construction is omitted in a DC, the length will be just large enough to accommodate the digits specified in the constant (along with
a padded 0 on the left if the number of digits in the constant is even). In a DS declarative, “Ln” must be coded. The length of a
packed field defined using a DC or DS is limited to a maximum of 16 bytes. This limits the size of decimal fields to 31 digits.
During assembly, fields that were defined consecutively in the source with DC’s or DS’s are assigned consecutive storage
locations in the program according to the value of the location counter which is maintained by the assembler. For example, in the
fields below, if PKD1 is associated with address x’1000’, then PKD2 is located at x’1008’ and PKD3 is located at x’1011’.
LOCATION
1000 PKD1 DS PL8
1008 PKD2 DC PL9’20’
1011 PKD3 DS PL3
1. Be sure and use DC instead of DS when providing a constant. Consider the example below,
AMOUNT DS PL4’1234’
The assembler will not complain about you providing a constant on a DS statement. It will, however, ignore the constant and
treat it as a comment. The field remains uninitialized.
2. Be sure to make any packed fields you define large enough to hold any possible values that might be developed in them. You
cannot err by overestimating the size of a packed field. On the other hand, it is disastrous to underestimate the size of a
packed field - this will result in truncation of digits in arithmetic operations (decimal overflow exception).
3. The specification of “P” as the type of data does not insure that the data is packed. In fact,
many kinds of data might be stored in a packed field.
Fixed point data fields, more commonly called “Binary” data fields, are defined using an “F” or an “H” in a DS or DC declarative.
The “F” creates a fullword (4-byte) field containing a binary integer in 2’s complement format. In this format, the integer can be
positive or negative. The “H” designator is used to create halfword (2-byte) fields containing 2’s complement signed integers. In
both formats, the length indicator “Ln” is usually omitted since the length is understood to be 2 or 4. When the length indicators
are absent, the fields will be aligned on either halfword or fullword boundaries. (A halfword boundary is an address that is evenly
divisible by 2, while fullword boundaries are evenly divisible by 4.) In order to align a field properly, the assembler may generate
from 1 to 3 unused bytes called “slack” bytes. Consider the example below. We assume that field “X” is located at address
x’1000’ and that the addresses of the bytes are shown inside each byte.
LOCATION
1000 X DS CL1
1004 Y DS F
It is possible to code a length for fullword and halfword binary fields. Specifically, we may code “FL4” and “HL2”. When a length
is indicated, slack bytes will not be generated. Consider the following example which is similar to the example above, but
generates no slack bytes.
LOCATION
1000 X DS CL1
1004 Y DS FL4
Fullword and halfword alignment can also be obtained with another technique: Coding a 0 duplication factor forces proper
alignment for the succeeding field. For instance, the following example forces FIELDA to be fullword aligned.
DS 0F
FIELDA DS ...
1. Remember that halfword fields are fairly small - between 32767 and -32768. Don’t select a halfword if you think your results
may exceed these values.
2. When defining fields in an input or output buffer, fullword and halfword fields are not usually aligned in order to conserve space
on a file. Remember to code the length indicator in these cases.
Define Constant (DC) is used to create and initialize fields at assembly time. The word “constant” in the title is something of a
misnomer since fields created with DC are initialized with their assembled values when the program is loaded, but are subject to
modification when the program begins execution. This declarative has the following format,
name DC dTLn’constant’
where ‘name’ is the optional field name,
‘d’ is a duplication factor which allows you to create consecutive copies of the field -
a 0 duplication factor leaves the location counter unchanged,
‘T’ is a data type - C - Character
Z - Zoned Decimal
P - Packed Decimal
H - Binary Halfword
F - Binary Fullword
A - Address
V - Virtual Address
X - Hexadecimal
B - Binary,
‘L’ stands for length,
‘n’ is the number of bytes in the field length,
‘constant’ is an appropriate constant of the specified type contained in apostrophes.
The following are some sample DC’s. For more information about a particular data type, consult the data type
documentation.
FIELD DEFINITION HEXADECIMAL CONTENTS
A DC C’ABC’ C1C2C3
B DC CL4’ ’ 40404040
C DC CL4’A’ C1404040
D DC 2C’AB’ C1C2C1C2
E DC X’12AB’ 12AB
F DC P’12345 12345C
G DC H’25’ 0019
H DC F’-3’ FFFFFFFD
I DC CL3 Assembly Error - No constant
DC CL30’ ’ Field name is not required
J DC 0CL5 0 Duplication factor
K DC CL3 J And K have the same address
L DC CL2 J Contains K and L
Programmers often find it necessary to change data from one data type to another. We will call this process “data conversion”.
There are a number of instructions devoted to data conversion that we will examine; specifically, we will discuss conversion
instructions involving four important data types: Zoned Decimal, Character, Packed Decimal, and Binary data types. The following
diagram illustrates all possible conversions among the 4 data types, and the instructions necessary to perform the conversions.
Converting from Zoned and Character to Packed
Zoned decimal data and character data that contains digits have closely related data formats. ( See Zoned Decimal Data
and Character Data.) For example, consider the definitions below.
CFIELD DC C’12345’ CFIELD = X’F1F2F3F4F5’
ZFIELD DC Z’12345’ ZFIELD = X’F1F2F3F4C5’
In fact, the only difference above occurs in the zone portion of the rightmost byte. The zoned field contains a “C” while the
character field contains an “F”. In a zoned format both “C” and “F” represent a positive sign (+) and so CFIELD AND ZFIELD are
equivalent as zoned decimal fields. As a result, the PACK instruction can be used to convert both of these fields to a packed
format:
CPACKED DS PL3
ZPACKED DS PL4
DBLWD DS D
...
PACK CPACKED,CFIELD CPACKED = X’12345F’
PACK ZPACKED,ZFIELD ZPACKED = X’0012345C’
PACK DBLWD,CFIELD DBLWD = X’000000000012345F’
In converting the character field to packed decimal in the first example above, we decided to use a 3 byte field to hold the result.
This decision is somewhat arbitrary. Since the character field contained 5 digits, it takes at least 3 bytes to hold the result in a
packed format ( 2 packed digits per byte plus the sign). A smaller choice would have caused truncation of digits on the left. A
We use the term “simple” to refer to an assembler program that is organized using a single control section. Programs that involve
multiple control sections are the topic of another article. Every program can be divided into two parts:
An executable section that consists of all the instructions in the program which direct the action of the central processing unit.
This includes all the instructions in the instruction set. Some examples are MVC, AP, and CR. These instructions move data,
perform arithmetic, and compare fields. Also included in the executable section are executable macros like GET, PUT, OPEN and
CLOSE. These macros generate executable instructions from the instruction set.
A non-executable section that consists of all the “directive” statements in the program that control how the assembler processes
the source code. These include the DS and DC directives (used to create variables and storage areas), EQU directives (used for
register names and target labels), the LTORG directive (used to create a literal pool), USING and DROP directives (used to control
register selection by the assembler), and a several “cosmetic” directives like PRINT, EJECT and SPACE.
Physically, the executable section and the non-executable section are intermixed. If you think of the executable section being
colored “red”, and the non-executable section being colored “blue”, then from afar, our “simple program” will appear as a red block
on top of a blue block. A closer look will reveal that the red block contains a few scattered lines of blue code. This organization is
indicated in the diagram below.
The Executable Section
Next we consider the organization of the executable section. There are several things that must occur upon entry into every
program. We will collectively refer to these tasks as the “standard entry section”. These tasks are several:
1) Copy the current contents of the registers into a save area which is located in the non-executable part of the program,
2) Establish addressability (the ability to use symbols),
3) Prepare the program for calling other programs.
After the standard entry section the programmer is free to write the code that comprises the body of the program. This section
instructs the central processing unit to perform the tasks for which the program is being written.
Finally, coding the “standard exit section” completes the executable section. There are three tasks in this section:
1) Restore the registers to their original state upon entering the program,
2) Set a return code which will be used by the calling program or operating system,
3) Branch back to the calling program or operating system.
The term “sequential file” refers to the manner in which the records of a file will be processed, and to a lesser extent, the way in
which the file records are physically organized on some media. For input, a sequential file is usually read starting from the first
record, proceeding to the second record, then the third, and continuing in this fashion to the end. For sequential output files, we
will write out the first record, then the second, then the third, proceeding in this manner to the last record. The most commonly
used sequential file for IBM mainframes is a QSAM file. QSAM is an acronym for “queued sequential access method”. In this
topic we investigate how QSAM files are created and processed. We will also learn about record blocking as well as “locate” and
“move mode” input and output.
Defining a QSAM File (Queued Sequential Access Method)
QSAM files are defined inside a program using IBM’s DCB macro. This macro generates a block of storage called a “data
control block” which contains information that is used by the operating system when processing the file that the macro defines. The
macro is non-executable, and serves only to generate a control block at assembly time. Being non-executable, the macro is coded
in the program at a point which would not become part of the execution sequence. Many programmers choose to code the DCB
just after the executable portion of the program, and before the declarations for variables. This is a fairly safe location and serves
to keep the DCB’s from becoming corrupted by the program accidentally. At run time, the information in the DCB is combined with
information in the job control language data definition statement (DD), as well as information in the data set label in order to
complete the information that is stored in the DCB. The data set label is a control block that is created and stored with the file
when it is created. Later we will investigate how the information from the DCB, the DD statement, and the data set label are
combined at run time.
Lets first look at a sample DCB macro as it might appear in a program.
CUSTFILE DCB DDNAME=CUSTOMER, +
DSORG=PS, +
LRECL=80, +
MACRF=(GM), +
RECFM=FB, +
EODAD=ENDFILE
By coding a DCB, we are defining a file and its characteristics. In the DCB above, the file’s internal name, the name that will be
used inside the program, is “CUSTFILE”. Whenever the program references the file, this is the name that will be used. For
instance, to read a record in the file we might code “GET CUSTFILE,MYREC”. The internal name appears in the first 8 columns
of the macro. This is followed by the macro name, “DCB”. The rest of the macro is a sequence of keyword parameters which may
be coded in any order:
1) DDNAME - This parameter assigns the file a “second” name which appears in the DD statement in the JCL that is used to
execute the program. The following is typical of the DD statement that would be part of the JCL.
//CUSTOMER DD DSN=TSYSAD2.PRIVATE.DATA,DISP=SHR
Notice that the word “CUSTOMER”, which we will call the “JCL name”, appears in the name field of the DD statement and is used
to associate the JCL name with a “physical file name”. The physical file name is the actual file name as it might appear in the
system catalog. As a result, we have three names for the file we are processing: an internal name, a JCL name, and a physical
file name. The purpose for having three names is to provide some “indirection” in the file names so that our program is not tied to
a single physical file. By changing the DD statement we can change the physical file that the program references. This is
illustrated below.
//CUSTOMER DD DSN=TSYSAD2.PRIVATE.DATA1
//CUSTOMER DD DSN=TSYSAD2.PRIVATE.DATA2
Only one of the DD statements above would appear in the JCL. If the first was coded, the connections in the upper path would be
indicated. If the second DD was coded, the connections in the lower path would be indicated. As you can see from the diagram,
changing the JCL DD statement allows the program to easily process different physical files.
2) DSORG - This keyword parameter stands for “data set organization” and is used to control the basic structure of the file. In
this case, PS means “physical sequential” and serves to identify the file as a QSAM file. The records in the file are stored and
processed sequentially. Records which are “logically” in sequence are also physically stored in sequence on the disk.
3) LRECL - The “logical record length” is the number of bytes in the record structure defined by the programmer and processed
by the program.
4) MACRF - This parameter determines the format for the I/O macros that will be used to process the file and the mode in which
the I/O will occur. For QSAM files there are four possible values that can be coded: GM, PM, GL, PL. The “G” in the parameter
value means that the GET macro will be used for accessing the file. This implies the file is an input file and already exists. The
“P” means the PUT macro will be used to process the file. In this case the file is an output file. The second letter indicates the
mode in which the I/O will occur. “L” means locate mode I/O and “M” means move mode I/O. These two modes will be discussed
later in this topic.
5) RECFM - The RECFM parameter determines whether the logical records the program processes are fixed in length (F), or of
variable lengths (V). This parameter also controls whether the records are blocked (B) or unblocked. Here are the typical values
for this parameter and their meanings.
RECFM = F Fixed size records, unblocked
RECFM = FB Fixed size records, blocked
RECFM = V Variable size records, unblocked
RECFM = VB Variable size records, blocked
The concept of record blocking will be discussed later in this topic.
6) EODAD - The “End of Data” parameter is only coded for input files (MACRF=GM or GL). This parameter provides a label to
which the program will automatically branch when the “end of file” condition occurs. The operating system detects the “end of file”
condition while executing a GET macro when there are no records in the file left to be read. Upon detecting “end of file”, the
operating system transfers control to address coded on the EODAD parameter.
Opening a QSAM File
Before you can process any records in a file, the file must be “opened”. The open process causes the “empty” fields in the DCB
to be filIed in so the file can be processed correctly. It is
helpful to understand how information in the DCB is constructed. This process is illustrated in the diagram below. Some of the
parameters are impractical but serve to illustrate how the information is combined.
At assembly time, the DCB is created and initialized with information contained in the program’s DCB macro. When the job is
submitted for execution, the JCL is initially scanned by the Job Scheduler, and a Job File Control Block (JFCB) is created first
using the information found in the DSCB if the file already exists, and then overwritten with any parameters found in the DD
statement. The file is opened at run time, and any information that is missing in the DCB is supplied by the information in the
JFCB. Because of the order in which the information is combined from the DCB macro, the DD statement, and the DSCB, the
most important information is that which is placed in the DCB as a result of the parameters coded in the program’s DCB macro.
This information is supplemented by information gleaned from the DD statement in the JCL. The only information that is taken from
the DD statement and stored in the DCB, are those fields which were not supplied in the program DCB. In other words, if a
parameter is supplied in the DCB and on the DD statement in the JCL, only the DCB parameter is used. Finally, the only
information that is gathered from the data set label is that which was not found in the DCB macro nor in the DD statement.
The OPEN macro has the following format,
OPEN (dcb-address,(processing option))
dcb-address - The label in the name field of the DCB macro.
processing option -
INPUT - An existing data set is to be used for retrieving records.
OUTPUT - A new data set is being created or the records in an existing file will be
replaced by the records that will be written by the program.
EXTEND - Records will be added to the end of an existing file.
UPDAT - An existing data set is to be used for retrieving records. Additionally,
existing records can be modified.
For example, the following statement opens the file called “CUSTFILE” for input processing.
As depicted above, the diagram illustrates “move mode” input and output. The term “move mode” refers to the process of
moving a record from a system input buffer to a program input area or from a program output area to a system output buffer.
These moves occur as a result of coding GET and PUT.
Reading and Writing QSAM Records in Move Mode
A loop is a control structure which allows a block of instructions, the loop body, to be executed repeatedly in succession. In
this article we investigate loop control structures and how they are constructed in assembly language. There are two categories of
loops:
1) Counted Loops - Loops in which the iteration number, the number of times the loop should be executed, is known before the
loop is entered.
2) Conditional Loops - Loops which will be continually iterated until a prescribed condition occurs.
Creating Counted Loops
The most commonly used instruction for creating a counted loop is the Branch On Count instruction, which has mnemonic BCT.
The iteration number is first loaded into a register which is subsequently manipulated by BCT. Each time the BCT is executed, the
iteration number in the register is decremented by one. After the register is decremented, the register is tested. If the result in the
register is not zero, a branch is taken to the address specified in Operand 2. If the test reveals that the result in the register is
zero, the loop is terminated and execution continues with the instruction following the BCT. Here is a sample loop that would be
iterated 10 times.
LA R5,10 PUT THE ITERATION NO. IN R5
LOOPTOP EQU *
...LOOP BODY GOES HERE
BCT R5,LOOPTOP DECREMENT R5,IF NOT 0, BRANCH BACK
In the code above, the register that will control the loop is initialized at 10 and then the statements in the loop body are
executed. At the end of the first iteration, BCT subtracts 1 from register 5, leaving it set to 9. The register is tested and since it
does not contain zero, a branch is taken back to LOOPTOP. The loop body is executed a second time, and again BCT subtracts
1 from register 5, leaving it set at 8. BCT tests the content of R5, which is now 8 , and not finding it zero, branches back to
LOOPTOP. This process continues through 10 iterations of the loop body. On the tenth iteration, BCT decrements the register
and the result becomes zero. Testing R5 reveals it to be zero. This time the branch is not taken and control returns to the
statement following the branch on count instruction.
There are two other instructions which are occasionally used to implement a counted loop. The first instruction that we consider
is called “Branch on Index Less Than or Equal”. The mnemonic for this instruction is BXLE. When coded it has three operands:
1) Operand 1 is a register containing a count or an address.
2) Operand 2 is typically an even register of an even-odd consecutive pair of registers. The even register contains a value which
is used to increment or decrement the value in Operand 1.
The odd register, which is not coded in the instruction, contains a limit or address against which Operand 1 is compared.
3) Operand 3 represents an address to which the instruction will branch if the Operand 1 value is less than or equal to the limit in
the odd register.
For example, consider the following instruction.
BXLE R3,R4,LOOPTOP
The diagram below illustrates the relationships among the registers used by the instruction.
Each time the instruction is executed, the value in the even register, R4, is added to the value in the Operand 1 register, R3. If
the result is less than or equal to the value in the odd register, R5, a branch occurs to the address in Operand 3, LOOPTOP. The
code listed below uses BXLE to implement a loop.
SR R3,R3 PUT 0 IN R3
LA R4,10 PUT INCREMENT INTO EVEN REG
LA R5,100 PUT LIMIT VALUE IN ODD REG
LOOPTOP EQU *
...LOOP BODY
BXLE R3,R4,LOOPTOP EXECUTE THE LOOP
First, the count in R3 is initialized to 0, the increment is set to 10, and the limit is set at 100. Each time the BXLE is executed, the
increment in R4 is added to the count in R3 and the result is compared to the limit in R5. If the new count is less than or equal to
the limit, a branch occurs back to LOOPTOP. The effect of the statement is to execute the loop 11 times. ( The loop is executed
once on the equal condition.)
BXLE has a companion instruction called “Branch on Index High”. The mnemonic is BXH and the instruction is similar in
execution to BXLE except the branch occurs on a “high” condition instead of “less than or equal”. The following code gives an
example of this instruction.
LA R3,5 SET THE COUNT TO 5
L R4,=F’-1’ SET THE DECREMENT TO -1
SR R5,R5 SET THE LIMIT VALUE AT 0
LOOPTOP EQU *
...LOOP BODY
BXH R3,R4,LOOPTOP EXECUTE THE LOOP
In the example above, the count is set at 5, the decrement is -1, and the limit is 0. Each time the BXH is executed, the decrement
is added to the count, reducing it by 1. As long as the result is higher than the limit 0, a branch occurs to LOOPTOP. The effect
is to execute the loop body 5 times.
The main drawback to using BXLE and BXH is that both instructions require 3 registers. Since registers are usually at a
premium in most programs, loops are often implemented using BCT.
While the instructions discussed above were specifically designed for the construction of loops, comparisons of any type, as well
as other instructions that set the condition code, can be used to create “home-made” loop structures. In the code below we use a
packed decimal instruction in combination with a branch to implement a counted loop.
ZAP COUNT,=P’100’ LOOP 100 TIMES
LOOPTOP EQU *
...LOOP BODY
SP COUNT,=P’1’ DECREMENT ON EACH ITERATION
BNZ LOOPTOP BRANCH IF NOT ZERO
In this case, we have decided to loop 100 times. Each time through the loop the count is decremented by 1. We take advantage
of the fact that SP sets the condition code based on the result of the subtraction. If the result is not zero, we loop back to
LOOPTOP.
Creating Conditional Loops
Packed decimal is a convenient format for doing many arithmetic calculations in assembly language for several reasons:
1) All computations occur in integer arithmetic (no decimals, 5/2 = 2, etc.),
2) Packed decimal fields are easy to read in a storage dump,
3) Computations occur in base 10.
The main disadvantage to packed decimal arithmetic is that decimal points are not stored internally. This means a programmer
must keep up with decimals and make sure they are printed in the correct positions on any report.
In this topic we discuss commonly used packed decimal computations with examples. Later we will consider arithmetic
operations with decimal points.
Copying Packed Decimal Fields
When copying a packed decimal field, be sure to use the Zero and Add Packed instruction, ZAP. By using ZAP, you are assured
that the target field will be properly initialized. Many beginners make the mistake of using MVC when copying packed decimal
values. This can lead to an error which is illustrated in the following example.
MVC AFIELD,PKFIELD AFIELD = X’038CFF’
ZAP AFIELD,PKFIELD AFIELD = X’00038C’
...
AFIELD DS PL3
PKFIELD DC PL2’38’ PKFIELD = X’038C’
DC X’FF’
We are copying a 2-byte packed field, PKFIELD, to a 3-byte field, AFIELD. Since MVC has an SS 1 format, the length of AFIELD
is used to determine that 3 bytes will be “moved” by this instruction. The effect of this instruction is to copy the 2 bytes in
PKFIELD and the byte which follows PKFIELD as well. As a result, AFIELD does not contain a packed value. On the other hand,
the ZAP above first initializes AFIELD with a packed decimal zero just before adding the packed value of PKFIELD. This produces
the correct packed decimal value X’00038C’. This type of error with the MVC instruction occurs each time the fields involved have
different sizes.
Care must be taken even when using a ZAP to copy a packed field. If the target field is too small to hold the result, high order
truncation of digits can occur, causing an overflow. Consider the following example involving AFIELD defined above.
ZAP AFIELD,=P’123456789’ AFIELD = X’56789C’
After executing the instruction above, the high-order digits of the packed decimal literal have been truncated. This may or may not
cause the program to abend, depending on the decimal-overflow mask. (See SPM.) In the case where the program continues
execution, the programmer is not immediately aware that an error has occurred.
One side effect of executing a ZAP is that the condition code is set to indicate how the target field compares to zero. The
condition code can be tested with the branch on condition instruction using the extended mnemonics. Here is an example,
ZAP FIELD1,FIELD1 SET THE CONDITION CODE
BZ WASZERO BRANCH IF ZERO
Adding Packed Decimal Fields
Next we consider the problem of adding several packed decimal fields. In doing this we must estimate the size of the sum and
define a packed decimal work field that will contain it. The first field that will participate in the sum can be ZAPed into the work
field. All other fields that contribute to the sum will be added using the AP instruction. The following example computes the sum
of 3 packed decimal fields.
Internal memory on an IBM mainframe is organized as a sequential collection of bytes. The bytes are numbered starting with 0
as pictured below,
The IBM System 370 architecture allows an address to be expressed as a collection of 31 consecutive bits. The smallest address
would be represented by 31 consecutive 0’s which denotes address 0. The largest address would be represented by 31
consecutive 1’s whose value is 2 31 - 1 = 2,147,483,647. If we work with addresses in this form (lets call these direct addresses),
each address occupies a fullword - 4 bytes.
Why do we need an address in the first place? Consider the following instruction,
MVC COSTOUT,COSTIN
In order for the machine to move the contents of COSTIN to COSTOUT, it must know the locations of these two fields. The
computer identifies a field by the address of the first byte in the field. When an instruction is assembled, the assembler converts
any symbols like “COSTOUT” to their corresponding addresses. The assembler does not, however, generate direct addresses, but
produces an address in base / displacement format. Addresses in this form consist of 4 hexadecimal digits or two bytes, BDDD,
where B represents a base register and DDD represents a displacement. The smallest displacement is x’000’ = 0 and the largest
displacement is x’FFF’ = 4095. Ultimately, the base / displacement address must be converted to a direct address. How does this
occur? The diagram below indicates how this process takes place starting with the base/displacement address x’8003’.
Notice that the effective address, which is the direct address equivalent to the base/displacement address, is computed by adding
the contents of the base register with the specified displacement.
Effective address = Contents( Base Register) + Displacement
There are two advantages of using base/displacement addresses instead of direct addresses in the object code that the
assembler produces:
1) Every address is shorter. Instead of being 4 bytes long, the addresses are only 2 bytes.
A DSECT or Dummy Section provides the programmer with the ability to describe the layout of an area of storage without
reserving virtual storage for the area that is described. The DSECT layout can then be used to reference any area of storage
which is addressable by the program. Think of the DSECT as a template, or pattern, which can be “dropped” on any area of
storage. Once the DSECT is “positioned”, the symbolic names in the DSECT can be used to extract data from the underlying
storage area.
How is the DSECT positioned? This is a two-step process. First, a register is associated with the DSECT name by coding a
USING directive. Loading the register with the storage address completes the process. Consider the sample code below.
CUSTOMER DSECT
FNAME DS CL4
LNAME DS CL5
BALANCE DS PL5
MAIN CSECT
...
USING CUSTOMER,R7
LA R7,TABLE
MVC NAME1,FNAME
MVC NAME2,LNAME
...
TABLE EQU *
DC CL4’FRED’
DC CL5’SMITH’
DC PL5’432.98’
...
NAME1 DS CL10
NAME2 DS CL20
The “CUSTOMER” DSECT is created by coding the DSECT directive which indicates the beginning of the dummy section. The
general format for this directive is listed below.
NAME OPERATION OPERAND
Any Symbol DSECT Not required
The pattern for the DSECT is created using a series of DS directives to describe a collection of fields in storage. The end of the
DSECT is indicated by the beginning of the CSECT. While the DSECT can be coded almost anywhere in the program, it is a
common practice to place any DSECTs you will need above the main control section, as in the example above. In order to code a
DSECT in the “middle” of a control section, the CSECT directive would appear twice as indicated below.
MAIN CSECT
...
CUSTOMER DSECT
FNAME DS CL4
LNAME DS CL5
BALANCE DS PL5
MAIN CSECT
The second CSECT directive indicates that the “MAIN” control section is being continued.
After defining the dummy section, it must be associated with an available register in a USING directive. In the example code
above, the statement “USING CUSTOMER,R7” associates register seven with the “CUSTOMER” dummy section. Addressability
is established when the register is loaded with the address of the table. At that point, FNAME contains the value “FRED”, and
LNAME contains the value “SMITH”. Loading the register “drops” the DSECT on the storage area whose address is contained in
the register.
You should consider the power of the above technique. There were no symbolic names associated with the table when it was
defined. By creating a DSECT, we are able to dynamically assign symbols to an area of storage and retrieve the data the area
contains. DSECTs have many uses in assembly language including array processing, locate mode I/O ( See SEQUENTIAL FILE
PROCESSING ), and data structure creation and manipulation. Most sophisticated assembler programs involve DSECTS to some
degree. Because of their importance, we will consider the use of DSECTs in array processing.
The term explicit addressing refers to the practice of representing the address of a byte in memory by specifying a base
register and a displacement, or a base and index register and a displacement. If at all possible, we would prefer to represent a
byte in memory by a symbolic name. Usually this is possible. For instance, consider the following declaration,
XFIELD DS CL5
While it does have a length attribute of five, the symbol “XFIELD” represents the address of the first byte of that field. This is
important to understand because the assembler will convert this symbolic address to a base/displacement format representing the
address of the first byte of the field. This base/displacement address (BDDD in hexadecimal) occupies two bytes in the
assembled code as evidenced in the instruction formats. (See the instruction format for an SS instruction.)
Unfortunately, sometimes the use of a symbolic name like XFIELD is inconvenient or impossible to create. At these times we
must resort to an explicit address. The explicit format for each instruction in this text is provided at the top left of the title page for
each instruction. For example, the MVC instruction lists the following explicit format.
Consider the following example instruction.
MVC 4(8,12),32(8)
Using the explicit format above we can decipher what the instruction will do. First, we can see that it is a move instruction that will
transfer 8 bytes. Where will the data that is to be moved come from? The answer is given explicitly as 32(8). This is a 32 byte
displacement off register 8. At execution, the effective address is computed by adding the contents of base register 8 plus the 32
byte displacement:
Effective address = Contents(Base register 8) + 32
At “execution time” it is imperative that register 8 contains a “known” address and that the second operand field that we are
currently addressing be 32 bytes away from this known address.
Where will the data be moved? Again, the answer is given explicitly as 4(12). This represents a 12 byte displacement off
register 12. The effective address is computed to be the contents of base register 12 plus 4. The field which is to receive the data
must be at an address which is 4 bytes larger than the “execution time” address in register 12.
Each instruction format has its own explicit format. For instance, the load instruction appears below.
Consider the following explicitly coded instruction,
L 10,4(3,5)
Obviously, register 10 is being loaded with a fullword in memory. Where is the fullword stored? The explicit format gives the
answer. The base register is 5, register 3 is an index register, and 4 is a displacement. The effective address can be computed
by adding the contents of the base register, plus the contents of the index register, plus the displacement:
Effective Address = Contents(register 5) + Contents(register 3) + 4
A knowledge of the explicit notation is helpful in understanding many instructions. For instance, it is common practice for an
assembler programmer to code an instruction similar to the one below.
LA R5,10
Without prior knowledge, what are we to make of this code? First we could look up a load address instruction and discover that it
is an RX instruction and has an explicit format similar to the load instruction described above. The second operand for an RX
instruction appears as D2(X2,B2). The instruction above has no parentheses - they were omitted. This means that 10 is a
displacement. What is the effective address? Since the base and index registers were omitted, zero was chosen for the base and
index registers. But the machine never uses register zero as a base or index register. This means that the effective address is
simply 10. The effect of the instruction above is to load a “small” number into register 5. Experienced programmers understand
this and choose the method as an effective way to load “small” numbers. What is meant by “small”? Since the number we are
loading must appear as a displacement, the largest number we could code in this way is 4095 = X’FFF’ which is the maximum
displacement allowed.
Mixing Symbolic and Explicit Notation
It is also possible to mix symbols and explicit notation within the same instruction. For example,
L 8,XWORD(5)
In the load instruction above, 8 is the Operand 1 register where a fullword will be loaded. What does the notation XWORD(5)
mean? In all cases, the assembler can process a symbol like XWORD and produce a base register and a displacement. This
means that the 5 is an index register. A related example appears below.
MVC AFIELD(8),BFIELD
Operand 1 appears as AFIELD(8). Again, the assembler can process the symbol AFIELD and produce a base register and a
displacement. Checking the explicit notation for a move character instruction we see that the 8 must be the length of Operand 1.
Normally, the length would be taken from the length attribute of AFIELD. Mixing notations allows us to overide the “implicit” length
with an “explicit” length.
L 14,12,12(R13) 14 AND 12 REPRESENT A RANGE OF REGISTERS.
WORDS ARE LOADED BEGINNING WITH THE WORD
12 BYTES OFF REGISTER 13.
MVC X(9),Y A 9 BYTE EXPLICIT LENGTH
1) Avoid the use of explicit notation whenever possible to simplify your code.
2) If you must use explicit notation, always code base and index registers using equate names (R0, R1, ...). This practice was not
followed in the notes above (examples excluded) in order to emphasize the explicit nature of the code. Using equate names forces
the assembler to record the use of each register in the cross reference listing at the end of your program. For large programs this
is a necessity.
3) One of the primary uses for explicit addresses involves parameter passing. In this area, the use of explicit addresses is a
commonly accepted practice. Read Program Linkage and become familiar with this important use of explicit addresses.
4) Consider the use of a DSECT as a means of using symbolic names instead of coding explicit addresses.
5) Remember that explicit addresses must be used if you have not issued a USING directive or if no base register is available.
(See Base Displacement Addressing.)
When the assembler processes an instruction, it converts the instruction from its mnemonic form to a standard machine-language
(binary) format called an “instruction format”. In the process of conversion, the assembler must determine the type of instruction,
convert symbolic labels and explicit notation to a base/displacement format, determine lengths of certain operands, and parse any
literals and constants. Consider the following “Move Characters” instruction,
MVC COSTOUT,COSTIN
The assembler must determine the operation code (x’D2’) for MVC, determine the length of COSTOUT, and compute
base/displacement addresses for both operands. After assembly, the result which is called “object code”, might look something like
the following in hexadecimal,
D207C008C020
The assembler generated 6 bytes (12 hex digits) of object code in a storage to storage (type one) format. In order to understand
the object code which an assembler will generate, we need some familiarity with 5 basic instruction formats (there are other
instruction types covering privileged and semiprivileged instructions which are beyond the scope of this discussion).
First we consider the Storage to Storage type one (SS 1 ) format listed below. This is the instruction format for the MVC
instruction above.
Byte 1 - machine operation code
Byte 2 - length -1 in bytes associated with operand 1
Byte 3 and 4 - the base/displacement address associated with operand 1
Byte 5 and 6 - the base/displacement address associated with operand 2
Each box represents one byte or 8 bits and each letter represents a single hexadecimal digit or 4 bits. The subscripts indicate
the number of the operand used in determining the contents of the byte. For example, the instruction format indicates that operand
1 is used to compute L 1 L 1 , the length associated with the instruction. If we reconsider the assembled form of the MVC instruction
above we see that the op-code is x‘D2’, and the length, derived from COSTOUT, is listed as x’07’. Since the assembler always
decrements the length by 1 when converting to machine code, we determine that COSTOUT is 8 bytes long - 8 bytes will be
moved by this instruction. Additionally we see that the base register for COSTOUT is x’C’ (register 12) and the displacement is
x’008’. The base/displacement address for COSTIN is x’C020’.
Why was register 12 chosen as the base register? How were the displacements computed? These parts of the object code
could not be determined by the information given in the example above. In order to determine base/displacement addresses we
must examine the “USING” and “DROP” directives that are coded in the program. These directives are discussed in the topic
called BASE DISPLACEMENT ADDRESSING.
Being able to read object code is a necessary skill for an assembler programmer. Knowledge of an instruction’s format gives
several important clues about the instruction. For example, knowing that MVC is a storage to storage type one instruction, informs
us that both operands are fields in memory and that the first operand will determine the number of bytes that will be moved. Since
the length (L 1 L 1 ) occupies one byte or 8 bits, the maximum length we can create is 2 8 - 1 = 255 . Recall that the assembler
decrements the length when assembling, so the instruction is capable of moving a maximum of 256 bytes. The 256 byte limitation
is shared by all storage to storage type one instructions.
Storage to Storage type two (SS 2 ) is a variation on SS 1 .
Byte 1 - machine operation code
Byte 2 - L 1 - the length associated with operand 1 (4 bits)
L 2 - the length associated with operand 2 (4 bits)
Byte 3 and 4 - the base/displacement address associated with operand 1
Byte 5 and 6 - the base/displacement address associated with operand 2
The only difference between SS 1 and SS 2 is the length byte. Notice that both operands contribute a length in the second
byte. Since each length is 4 bits, the maximum value that could be represented is 2 4 - 1 = 15. Again, since the assembler
decrements the length by 1, the instruction can process operands that are large as 16 bytes. There are many arithmetic
instructions that require the machine to use the length of both operands. Consider the example below,
Object Code Source Code
AFIELD DS PL4
BFIELD DS PL2
...
FA31C300C304 AP AFIELD,BFIELD
AP (Add Packed) is an instruction whose format is SS 2 . Looking at the object code that was generated, we see that x’FA’ is
the op-code and that the length of the first operand is x’3’ which was computed by subtracting 1 from the length of AFIELD.
Similarly, the length of BFIELD was used to generate the second length of x’1’. In executing this instruction, the machine makes
use of the size of both fields. In this case, a 2 byte field is added to a 4 byte field.
A second type of instruction format is Register to Register (RR).
Byte 1 - machine operation code
Byte 2 - R1 - the register which is operand 1
R2 - the register which is operand 2
Instructions of this type have two operands, both of which are registers. An example of an instruction of this type is LR (Load
Register). The effect of the instruction is to copy the contents of the register specified by operand 2 into the register specified by
operand 1. The following LR (Load Register) instruction,
LR R3,R12
would cause register 12 to be copied into register 3. The assembler would produce the object code listed below as a result of the
LR instruction.
183C
Examining the object code we see that the op-code is x’18’ , operand 1 is register 3, and operand 2 is register 12. You should
note that 4 bits are enough to represent any of the registers which are numbered 0 through 15.
A third type of instruction format is Register to Indexed Storage (RX).
Byte 1 - machine operation code
Byte 2 - R 1 - the register which is operand 1
X2 - the index register associated with operand 2
One instruction which has a Register to Storage format is STM (Store Multiple). An example of how STM can be coded is as
follows,
STM R14,R12,12(R13)
The previous instruction would generate the following object code,
90ECD00C
where x’90’ is the op-code, x’E’ = 14 is operand 1, x’C’ = 12, is treated as R 3 , and x’D00C’ is generated from an explicit
base/displacement address (12(R13)).
The fifth and final instruction format that we will consider is called Storage Immediate (SI). In this format, the second operand,
called the immediate constant, resides in the second byte of the instruction. This constant is usually specified as a self-defining
term.
The format for SI instructions is listed below.
Byte 1 - machine operation code
Byte 2 - I2 I2 - the immediate constant denoted in operand 2
Byte 3 and 4 - the base/displacement address associated with operand 1
An example of a storage immediate instruction is Compare Logical Immediate (CLI). This instruction will compare one byte in
storage to the immediate byte which resides in the instruction itself. We see from the instruction format that operand 2 is the
immediate constant. For example, consider the instruction below.
CLI CUSTTYPE,C’A’
When assembled, the object code might look like the following,
95C1C100
The op-code is x’95’, the self-defining term C’A’ is converted to the EBCDIC representation x’C1’, and the variable CUSTTYPE
The term “program linkage” or simply “linkage” encompasses all the techniques required to make separately assembled control
sections work cooperatively. This includes transfers of execution between control sections as well as the communication of data
between control sections or programs. To facilitate program linkage, IBM developed a series of rules called “Linkage Conventions”
which specify the responsibilities of the cooperating programs. We will call the main program the “calling program” and the
subroutine it calls the “called program”. Each type of program has it own conventions.
The Calling Program’s Conventions
1) Register 13 should contain the address of a “Save Area”. The save area is a contiguous collection of 18 fullwords that is used
as a storage area for the registers. Since there are only 16 registers which must be shared by all programs, the calling program
must provide the address of its save area in register 13. Subsequently, the called program stores the contents of the registers in
this area before continuing execution.
2) Register 15 should contain the entry point address of the called program. Since the entry point is not in the calling program,
we must use a “virtual” address constant in order to reference the entry point. For example, suppose the entry point in the called
program is the CSECT name “SUBPROG”. Then the following instruction would load register 15 properly.
L R15,=V(SUBPROG)
When the assembler processes the virtual address constant, it recognizes that the symbol SUBPROG is not part of the current
control section. As a result it assembles a fullword containing zeros for the virtual address. When the linkage editor combines the
calling and called subprograms, the fullword is filled in with the correct runtime address of SUBPROG. Only “external” symbols can
be used for entry points into a control section. Control section names are automatically external. Other symbols can be declared
external using the EXTRN directive.
3) When passing variables from the main program to the subprogram, the address of each variable we wish to pass becomes an
entry in a list of consecutive fullword addresses. The address of the list is placed in register 1. Assume we want to pass variables
X, Y, and Z. The following code will create the address list and initialize register 1.
LA R1,=A(X,Y,Z)
The following diagram illustrates the structure which is created by the above command. We assume the following declarations.
X DC CL3’ABC’
Y DC CL2’PQ’
Z DC CL4’DEFG’
Notice that only one item of data is passed - the address of the list of addresses. You must use register 1 to find all the variables
which are passed.
4) Register 14 should be initialized with the “return” address. This is the address to which the called program will transfer control
when it has completed execution. The following instruction will accomplish this.
BASR R14,R15
BASR stores the address of the instruction following the BASR in register 14, and branches to the address in register 15. In this
way, control is transferred to the subprogram.
The Called Program’s Conventions
1) The called program must save the current values of the registers in the caller’s save area. Since the caller has placed the
address of the save area in register 13, the following code will save the registers.
STM R14,R12,12(R13)
Notice that the explicit address 12(R13) means that R14 is stored in the fourth fullword in the save area ( 12 bytes off R13 ). You
should also note that all the registers are stored except R13. Register 13 contains the address of the save area and must be
stored in an area that belongs in the called program.
The format of the save area is listed below. We assume a sequence of program calls: Program “A” calls Program “B”, and
Program “B” calls Program “C”. The save area in the diagram is for Program “B”.
2) The contents of register 13 ( the address of the caller’s save area ) must be stored in the second fullword of the called
program’s save area. This can be done using the following instruction.
ST R13,SAVE+4
Notice that “SAVE” refers to the save area in the called program. “SAVE+4” becomes a “backwards pointer” to the previous save
area. This is illustrated below.
Additionally, the called program can store the address of its own save area in the calling program’s save area in the third word
(SAVE+8). This last technique is usually omitted and will not be used in this topic.
3) Like the calling program, R13 should contain the address of the program’s save area. This is accomplished with the same
instruction used in the main program.
LA R13,SAVE
4) Register 1 can be used to access any variables that are passed from the main program. For example, suppose X, Y, and Z are
passed as parameters as described in step 3 of the “The Calling Program’s Conventions”. Assume that Y is defined as CL2 in the
main program, and YSUB is defined as CL2 in the subprogram. The data in Y can be copied to YSUB as follows.
L R8,4(R0,R1) LOAD THE 2ND ADDRESS CONSTANT
MVC YSUB,0(R8) R8 POINTS AT Y IN THE MAIN
The technique of copying a variable to the subprogram and working with the copy is called “Pass by Value”. An alternative would
be to work directly with Y in the main program. This technique is called “Pass by Reference”. Either technique is acceptable
1. Each program you write should follow the calling program’s conventions as well as the called program’s conventions. The
operating system treats each main program you write as a subprogram and so even a main program behaves as a subprogram.
On the other hand, each subprogram you write may call other programs either explicitly or by requesting services from the
operating system.
Write each program as if it is one link in a chain of program calls.
Each byte of internal memory is numbered sequentially beginning with 0 for the first byte, 1 for the second byte, and continuing
in this way until the end of memory is reached. We will call the number associated with each byte the address of the byte. There
is a limit to the amount of memory that is supported, since addresses are expressed as binary integers using 31 bits. The smallest
address which can be created is 0 and the maximum address is 2 31 - 1 which is 2,147,483,647 or 2 gigabytes.
Address fields are created by using the A,Y, or V indicators in a DS or a DC. (Q-constants and S-constants are discussed
elsewhere.) If a length indicator is not coded, A and V indicate fullword fields, while Y indicates a halfword address. A length
indicator can be used to create A-constants with 1 to 4 bytes, V-constants with 3 or 4 bytes, and Y-constants with 1 or 2 bytes.
The following are formats for creating address constants,
name DC T( address, ... )
name DC TLn( address, ...)
where “name” is a field name,
“T” is the address type A,Y, or V,
“address, ...” represents 1 or more addresses separated by commas. Each address is
either a relocatable, a complex relocatable, or an absolute expression.
It is difficult to give the technical definition of the terms relocatable and complex relocatable, but generally, an expression is
relocatable if it refers to labels in a program and the value of the expression changes if the program is moved from its original
location. An expression is absolute if it refers to labels in a program, and the value of the expression is constant regardless of
the location of the program. An example will help with these ideas,
DOG DS CL5
CAT DS CL7
PIG DS CL9
ADR1 DC A(PIG) RELOCATABLE
ADR2 DC A(PIG - DOG) ABSOLUTE
ADR3 DC A(PIG + DOG) COMPLEX RELOCATABLE
Notice that “ADR1” is relocatable since its value (address) would change if the program were moved. “ADR2” is absolute since
PIG and DOG are 12 bytes apart regardless of where the program is loaded. “ADR3” is complex relocatable since it involves
multiple “unpaired” relocatable expressions and its value would change depending on the program’s location.
Relocatable expressions are initially created at assembly time and then modified by the linkage editior at link time to contain the
correct address for the expression you have created. Absolute expressions are not modified by the linkage editor.
The main difference between A-constants and V-constants is that a V-constant can refer to a label in a different control section.
A-constants can only reference labels within the same control section. For V-constants, at assembly time, the assembler creates a
fullword containing 0’s and leaves an indicator for the linkage editior to supply the correct address in the constant at link time. The
primary reason for using a V-constant is for program linkage - we want to branch to a separately assembled control section. This
can be accomplished with the code below,
LA R1,=A(X,Y,Z) POINT TO THE PARAMETERS
L R15,=V(SUBPROG1) VIRTUAL ADDRESS SUBPROG1
BASR R14,R15 BRANCH TO THE SUBPROGRAM
Notice that the above example also uses A-constants to create 3 consecutive fullword addresses for parameter passing.
1. Read the technical definitions of Relocatable, Complex Relocatable, and Absolute expressions found in IBM’s High Level
Assembler Language Reference .
The Add instruction performs 2’s complement binary addition. Operand 1 is a register containing a fullword integer. Operand 2
specifies a fullword in memory. The fullword in memory is added to the fullword in the register and the result is stored in the
register. The fullword in memory is not changed. Consider the following example,
A R9,AFIELD
The contents of the fullword “AFIELD”, x’0000000A’ = 10, are added to register 9 which contains x’00000025’ = 37. The sum is
47 = x’0000002F’ and destroys the previous value in R9. The fullword in memory is unchanged by this operation.
Since A is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
The Add Halfword instruction performs 2’s complement binary addition. Operand 1 is a register containing a fullword integer.
Operand 2 specifies a halfword in memory. The halfword in memory is sign extended (internally) and added to the fullword in the
register. In other words, it is converted to an arithmetically equivalent fullword before the addition. The result is stored in the
register, while the halfword in memory is not changed. Consider the following example,
AH R9,AFIELD
The contents of the halfword “AFIELD”, x’007F’ = 127, are added to register 9 which contains x’000003FA’ = 1018. The sum is
1145 = x’00000479’ and destroys the previous value in R9. The halfword in memory is unchanged by this operation.
Since AH is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
A common error is to code a AH when the second operand is not a halfword. For example:
AMOUNT DC F’20’ AMOUNT = X’00000014’
...
AH R5,AMOUNT
The assembler will not complain about your code, but the halfword instruction will only access the first two bytes of the AMOUNT
field (x’0000’).
AP is an SS 2 instruction which is used to add packed decimal fields. Operand 1 is a field in storage which should contain a
packed decimal number. The resulting sum develops in this field. The contents of Operand 2, another packed decimal field in
storage, is added to the contents of Operand 1 to produce the sum which is stored in Operand 1. The operands are limited to a
maximum length of 16 bytes and may have different sizes since this is a SS 2 instruction.
A decimal overflow (condition code = 3) can occur if the generated sum loses a significant digit when it is placed in the target
field. A decimal overflow may or may not cause a program interruption (abend). This depends on the setting of a bit in the PSW
(See SPM). Otherwise, the condition code is set to indicate whether the result was zero (condition code = 0), negative (condition
code = 1), or positive (condition code = 2). You can test these conditions with BZ or BNZ, BM or BNM, and BP or BNP.
Consider the following AP example.
AP APK,BPK
BP APOSITIV
Assume the variables are initially in the following states,
APK DC PL4’34’ = X’0000034C’
BPK DC PL3’22’ = X’00022C’
After the AP instruction has executed, the variables have the following values.
APK = X’0000056C’
BPK = X’00022C’
The contents of BPK and APK were added and the result stored in APK. BPK was unaffected by the add operation. The branch
would occur and execution would resume at “APOSITIV” since the condition code was set to positive.
On the other hand, consider the following example,
AP APK,BPK
...
APK DC PL2’999’ = X’999C’
BPK DC PL2’3’ = X’003C’
After the AP instruction has executed, the variables have the following values.
APK = X’002C’
BPK = X’003C’
Notice that an overflow occurred in APK with the loss of a significant digit since the APK field was too short to hold the resulting
sum.
1. You must be familiar with your data. The best way to prevent overflows is to plan the size of your fields based on the data at
hand. There is a rule of thumb that you can follow for additions: If you are adding two packed fields with m and n bytes, then the
sum might be as large as
max(m, n) + 1 bytes. You may need to construct a work area to handle the maximum values. For instance,
FIELDA DS PL4
FIELDB DS PL3
WORK DS PL5
In planning to add FIELDA and FIELDB, we construct a work field called “WORK”. The following code completes the task.
ZAP WORK,FIELDA
AP WORK,FIELDB
The Add Register instruction performs 2’s complement binary addition. Operand 1 is a register containing a fullword integer.
Operand 2 specifies a register as well. The fullword in Operand 2 is added to the fullword in Operand 1, and the sum replaces
the contents of Operand 1. Operand 2 in unchanged by this operation except when Operand 1 and 2 refer to the same register.
Consider the following example,
AR R9,R8
The contents of the fullword in register 8, x’00000479’, are added to the contents of register 9 which contains x’000003FA’ . The
sum is x’00000873’ and replaces the previous value in R9. The contents of register 8 are unchanged by this operation.
The condition code is set by this instruction to zero (0) if the result is zero, it is set to minus (1) if the result is negative, and to
plus (2) if the result is positive.
BAS is a RX instruction which is used to support internal subroutines. When executed, the address of the instruction which
follows the BAS, a return address, is stored in the operand 1 register, and a branch is taken to the address specified by operand
2. BAS is used in combination with BR to construct internal subroutines (routines that are contained in the same control section).
Consider the instruction sequence below
BAS R8,SUB1
BAS R8,SUB2
MVC X,Y
...
SUB1 EQU *
... (SUBROUTINE CODE GOES HERE)
BR R8 BRANCH TO THE RETURN ADDRESS
SUB2 EQU *
... (SUBROUTINE CODE GOES HERE)
BR R8 BRANCH TO THE RETURN ADDRESS
When the first BAS instruction is executed, the address of the next instruction (BAS R8,SUB2) is loaded into R8. After this return
address is loaded, a branch occurs to the address denoted by SUB1. This begins execution of the code in the subroutine. At
completion of the subroutine, an unconditional branch (BR R8) occurs to the address in R8. Execution resumes at the second
BAS instruction. The second BAS causes the address of the next instruction (MVC X,Y) to be loaded into R8. A branch is taken
to the subroutine denoted by SUB2. After execution of the subroutine, the unconditional branch (BR R8) at the end of the
subroutine returns control at the MVC instruction.
BAS replaces an older instruction called “BAL” which stands for “Branch and Link”. Both of these instructions load the address of
the next instruction into operand 1. The difference in their operation depends on the addressing mode that the machine is using:
In 24 bit mode: BAL loads bits 0 - 7 of operand 1 with linkage information ( instruction
length code, condition code, program mask )
BAL loads bits 8 - 31 of operand 1 with the 24 bit return address
BAS loads bits 0 - 7 with eight 0’s
BAS loads bits 8 - 31 of operand 1 with a 24 bit return address
In 31 bit mode BAS and BAL load bit 0 with a 1 indicating 31 bit mode addressing
BAS and BAL load bits 1 - 31 with a 31 bit return address
The information that was provided by BAL in bits 0 - 7, can now be obtained using the IPM ( insert Program Mask ) instruction.
1) Use BAS instead of BAL to avoid non-zero bits being placed in the high-order byte of the stored address.
2) When creating internal subroutines, consider saving the linkage register on entry to the subroutine and restoring it just before
exiting:
BASR is a RR instruction which is used to support linkage and internal subroutines. When executed, the address of the
instruction which follows the BASR, a return address, is stored in the operand 1 register, and a branch is taken to the address in
the operand 2 register. No branch is taken if R0 is specified as operand 2. In this case, execution continues with the instruction
following the BASR. Consider the instruction sequence below
LA R15,SUB1 PUT TARGET ADDRESS IN R15
BASR R14,R15 SAVE “HERE” AS THE RETURN ADDRESS
HERE EQU * THE RETURN ADDRESS
MVC X,Y
...
SUB1 EQU *
... (SUBROUTINE CODE GOES HERE)
BR R14 BRANCH TO THE RETURN ADDRESS
First the address of the subroutine ( the target address) is loaded into register 15. When the BASR is executed, the address of
the next instruction (MVC) is loaded into R14. Recall that the EQU directive does not generate object code, and so the address
denoted by HERE is equivalent to the address of the MVC instruction. After the return address is loaded, a branch occurs to the
address in R15 (SUB1). This begins execution of the code in the subroutine. At completion of the subroutine, an unconditional
branch occurs to the address in R14. This causes execution to resume at the MVC instruction.
BASR can also be used in the format listed below.
BASR R12,R0
In this case, the address of the next instruction is loaded into R12, and no branch is taken since operand 2 was specified as R0.
This form of a BASR is used in the topic called Base / Displacement Addressing. Briefly, R12 is declared to be a base register
in a USING statement and the BASR loads R12 with the base address ( the address of the next instruction ).
BASR replaces an older instruction called “BALR”. Both of these instructions load the address of the next instruction into
operand 1. The difference in their operation depends on the addressing mode that the machine is using:
In 24 bit mode: BALR loads bits 0 - 7 of operand 1 with linkage information ( instruction
length code, condition code, program mask )
BALR loads bits 8 - 31 of operand 1 with the 24 bit return address
BASR loads bits 0 - 7 with eight 0’s
BASR loads bits 8 - 31 of operand 1 with a 24 bit return address
In 31 bit mode BASR and BALR load bit 0 with a 1 indicating 31 bit mode addressing
BASR and BALR load bits 1 - 31 with a 31 bit return address
The information that was provided by BALR in bits 0 - 7, can now be obtained using the IPM ( Insert Program Mask ) instruction.
1) Use BASR instead of BALR to avoid non-zero bits being placed in the high-order byte of the stored address.
2) Read about the use of BASR in the topic Base Displacement Addressing.
The Branch on Condition instruction examines the 2-bit condition code in the PSW and branches (or not) based on the value it
finds. Operand 1 is a self-defining term which represents a 4-bit mask (binary pattern) indicating the conditions under which the
branch should occur. Operand 2 is the target address to which the branch will be made if the condition indicated in Operand 1
occurs. If the condition code has one of the values specified in the mask, the instruction address in the PSW is replaced with the
target address in the instruction. This causes the processor to fetch the instruction located at the target address as the next
instruction in the fetch/execute cycle. See System 390 Architecture for more details.
There are four possible values for the condition code:
Condition Code Meaning
00 Zero or Equal
01 Low or Minus
10 High or Plus
11 Overflow
When constructing a mask for Operand 1, each bit ( moving from the high-order bit to the low-order bit ) represents one of the
four conditions in the following order: Zero/Equal, Low/Minus, High/Plus, Overflow. Consider the following instruction,
BC 8,THERE
The first operand,”8”, is a decimal self-defining term and represents the binary mask B’1000’. Since the first bit is a 1, the mask
indicates that a branch should occur on a zero or equal condition. Since the other bits are all 0, no branch will be taken on the
other conditions. The first operand could be designated as any equivalent self-defining term. For example, the following instruction
is equivalent to the one above.
BC B’1000’,THERE
Extended mnemonics were developed to replace the awkward construction of having to code a mask. The extended mnemonics
are easier to code and read. A listing of the extended mnemonics follows below.
BE Branch Equal BNE Branch Not Equal
BZ Branch Zero BNZ Branch Not Zero
BL Branch Low BNL Branch Not Low
BM Branch Minus BNM Branch Not Minus
BH Branch High BNH Branch Not High
BP Branch Positive BNP Branch Not Positive
NOP No Operation B Unconditional Branch
Using extended mnemonics we could replace the previous Branch On Condition instruction with the following,
BZ THERE
The “BZ” means “Branch on Condition Zero”. When the assembler processes BZ, it generates the mask as B’1000’. The table
below indicates the possible mask values and the equivalent extended mnemonics.
Eq/Low Low/Min High/Plus Overflow Decimal Extended
Condition Mnemonic
0 0 0 0 0 NOP
0 0 0 1 1 BO
0 0 1 0 2 BH, BP
0 0 1 1 3 No mnemonic
BCT is used to implement counted loops - loops in which the number of iterations is known before entrance to the loop body
occurs. First the number of iterations is loaded into operand 1, a register which will control the loop. Operand 2 specifies a target
address to branch to when the end of the loop body is encountered. Each time the BCT is executed the register denoted by
operand 1 is decremented by 1. (The subtraction occurs in 2’s complement arithmetic.) If the result in operand 1 is not zero, the
branch is taken to the target address specified in operand 2. If the result is zero, execution continues with the instruction following
the BCT. Here is an example.
LA R8,3 SET THE NO. OF ITERATIONS TO 3
LOOP EQU *
... (LOOP BODY GOES HERE)
BCT R8,LOOP DECREMENT LOOP, BRANCH BACK IF NOT ZERO
In the example above, 3 is loaded into R8. The loop body is executed and the BCT is executed. This causes R8 to be
decremented by 1. Since the result, 2, is not zero, a branch occurs back to “LOOP”. The loop body is executed again, and BCT
reduces R8 to 1. Again, a branch is taken to “LOOP”. The loop body is executed a third time and R8 is reduced to 0 by the
execution of BCT. Since the result in R8 is equal to zero, the branch is not taken and execution continues with the instruction
which follows the BCT.
1. Be sure to initialize the register that controls the loop. In the last example above, the loop would execute the loop body 2 31
times, running through all possible values, before R6 contained a 0.
BCTR is the RR version of BCT. It is used to support counted loops - loops in which the number of iterations is known before
entry to the loop body. Operand 1 is a register which contains a count - the number of iterations the loop should perform. Each
time the BCTR is executed, the operand 1 register is decremented by 1. If the result is not zero, a branch is taken to the address
stored in the register denoted by operand 2. If the result is zero, no branch is taken and execution continues with the instruction
following the BCTR. Here is an example of how BCTR can be used to create a counted loop.
LA R10,LOOP PUT TARGET ADDRESS IN R10
LA R8,3 LOOP 3 TIMES
LOOP EQU *
... (LOOP BODY GOES HERE)
BCTR R8,R10 BRANCH TO “LOOP” IF NOT ZERO
MVC X,Y
First the address of the loop body ( the target address) is loaded into register 10. Then the number of iterations, 3, is put in R8.
The loop body is executed. The BCTR decrements R8 to 2, and since the result is not zero, a branch is taken to the address in
R10 which is LOOP. The loop body is executed again and the BCTR decrements R8 to 1. Since the result was not zero, a
branch is taken to LOOP. The third execution of the loop body occurs and BCTR decrements R8 to 0. No branch is taken in this
case, and execution falls through the loop and continues with the MVC instruction.
BCTR is sometimes coded with R0 specified in operand 2 to indicate that no branch should be taken. Execution continues with
the next instruction.
BCTR R5,R0
In this case, R5 is decremented by 1. Since R0 was coded as the second operand, execution continues with the instruction
following the branch. Coding BCTR in this way provides an easy and efficient way to subtract 1 from a register.
CLC is used to compare two fields that are both in storage. The fields are compared, one byte at a time beginning with the
bytes specified in addresses B1 D 1 D 1 D 1 and B2 D 2 D 2 D 2 , and moving to higher addresses in the source and target fields. Each
byte in the source is compared to a byte in the target according to the ordering specified in the EBCDIC encoding sequence.
Executing a compare instruction sets the condition code (a two bit field in the PSW) to indicate how operand 1 (target field)
compares with operand 2 (source field). The condition code is set as follows,
Comparison Condition Code Value Test With
Operand 1 equals Operand 2 0 (equal) BE (Branch Equal)
BNE (Branch Not equal)
Operand 1 is less than Operand 2 1 (low) BL (Branch Low)
BNL (Branch Not Low)
Operand 1 is greater than Operand 2 2 (high) BH (Branch High)
BNH (Branch Not High)
The table above also indicates the appropriate branch instructions for testing the condition code. When comparing two fields, a
CLC instruction should be followed immediately by one or more branch instructions for testing the contents of the condition code:
CLC FIELDA,FIELDB
BH AHIGH BRANCH IF FIELDA IS HIGH
BL BHIGH BRANCH IF FIELDA IS LOW
Bytes are compared until the number of bytes specified (implicitly or explicitly) in operand 1 have been exhausted or until two
unequal bytes are found - whichever occurs first.
As you can see from the instruction format above, the instruction carries with it the maximum number of bytes to be compared, as
well as the beginning addresses of the source and target fields. Notice that the instruction does not specify the ending addresses
of either field - the instruction is no respecter of fields. If a longer field is compared to a shorter field, the bytes following the
shorter field may be used in the comparison operation.
The length (LL1 ) determines the maximum number of bytes which will be compared. The length is usually determined implicitly
from the length of operand 1 but the programmer can provide an explicit length. Consider the two example CLC’s below,
Object code Assembler code
FIELDA DC CL4’ABCD’
FIELDB DC C’ABE’
...
D502C00CC008 CLC FIELDB,FIELDA Implicit length = 3,
COND CODE = HIGH
D501C00CC008 CLC FIELDB(2),FIELDA Explicit length = 2,
COND CODE = EQUAL
In the first CLC, ‘A’ in FIELDB is compared with ‘A’ in FIELDA, then ‘B’ in FIELDB is compared with ‘B’ in FIELDA, finally, ‘E’ in
1. As with any storage to storage instruction, you must pay careful attention to lengths of the two operands. Generally, you should
be comparing fields that are the same size.
2. The instruction was designed to compare fields that are in character format. It can be used to compare fields with non-
character data, but this takes special consideration to make sure the comparison will produce the desired results. Packed decimal
data and binary data are supported with their own special comparison instructions.
3. The condition code can be changed by any other type of comparison instruction as well as by a variety of arithmetic
instructions. Don’t rely on the condition code to remain set - after you have issued a CLC , you should follow it up immediately
with a branch instruction.
CLI is used to compare two fields that are both in storage. Operand 1 is a field in main storage, while the second operand is a
self-defining term that gets assembled as a one byte immediate constant (II 2 ) in the second byte of the object code of the CLI
instruction. Only the first byte of Operand 1 is compared to the immediate constant. The comparison is made based on the
ordering of characters in the EBCDIC encoding.
Executing a compare instruction sets the condition code (a two bit field in the PSW) to indicate how operand 1 (target field)
compares with operand 2 (immediate constant). The condition code is set as follows,
Comparison Condition Code Value Test With
Operand 1 equals Operand 2 0 (equal) BE (Branch Equal)
BNE (Branch Not equal)
Operand 1 is less than Operand 2 1 (low) BL (Branch Low)
BNL (Branch Not Low)
Operand 1 is greater than Operand 2 2 (high) BH (Branch High)
BNH (Branch Not High)
The table above also illustrates the appropriate branch instructions for testing the condition code. When comparing two fields, a
CLI instruction should be followed immediately by one or more branch instructions for testing the contents of the condition code:
FIELDA DC C’1234’
...
CLI FIELDA,C’A’
BH AHIGH BRANCH IF FIELDA IS HIGH
BL BHIGH BRANCH IF FIELDA IS LOW
In the example above, the first byte of FIELDA, which contains the character “1” and is represented as x’F1’, is compared to the
self-defining term C’A’, which assembles as a x’C1’. In EBCDIC, since x’F1’ is greater than x’C1’, the condition code is set to
“high” to indicate that operand 1 is “higher” than operand 2.
The following example illustrates how a CLI might be processed by the assembler.
LOC OBJECT CODE
000F12 95F4C044 CLI CUSTCODE,C’4’
...
001028 CUSTCODE DS CL1
In the example above, the op-code for CLI is x’95’, the self-defining term C’4’ is assembled as the one byte hexadecimal constant
x’F4’, and CUSTCODE is translated into the base/displacement address C044.
1. Use CLI instead of CLC when comparing 1-byte fields. The resulting code is smaller and slightly more efficient. More
importantly, it makes explicit the fact that you are comparing two 1-byte fields.
The Compare Halfword instruction is used to compare a binary fullword in a register, Operand 1, with a binary halfword in
memory, Operand 2. The operands are compared as 2’s complement signed binary integers. For purposes of comparison, the
halfword is “sign-extended” to a fullword before the comparison occurs. This extension occurs internally and is temporary. The
instruction sets the condition code to indicate how Operand 1 compares to Operand 2:
Condition Code Meaning Test With
0 Operand 1 = Operand 2 BE, BZ
1 Operand 1 < Operand 2 BL, BM
2 Operand 1 > Operand 2 BH, BP
CH R9,AFIELD
The contents of the halfword “AFIELD”, x012C’, is signed extended to a fullword, x’0000012C’, and is compared to the contents
of register 9 which contains x’000045FF’. Since the contents of the register (Operand 1) is greater than the value than the
extended halfword (Operand 2), the condition code is set to “High”. The condition code in the diagram above is specified using 2
binary digits. After comparison, the condition code is set to a binary 10 which is 2 in decimal - a “High” condition.
Since CH is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
CP is a SS 2 instruction which is used to compare packed decimal fields. This instruction sets the condition code to “equal”
(condition code = 0), “low” (condition code = 1) or “high” (condition code = 2) based on a comparison of the two fields as decimal
numbers, and indicates how the first operand compares to the second operand. The fields may be of equal or different sizes. The
only restrictions on the field lengths is that they must be a maximum of 16 bytes in length (the typical restriction for SS 2 fields).
Consider the fields and instructions below.
APK DC P’123’ = X’123C’
BPK DC PL3’100’ = X’00100C
CHX DC X’123F’
...
CP APK,BPK C.C.= HIGH
CP APK,CHX C.C.= EQUAL
CLC APK,CHX C.C.= LOW
In the first CP, the fields are compared arithmetically and it is found that +123 is greater than +100. In the second compare, the
condition code is set to “equal” since +123 is equal to +123 (x’F’ is a valid plus sign). The third compare is a logical compare
rather than an arithmetic compare. Since x’3C’ is lower than x’3F’ in the EBCDIC collating sequence, the condition code is set to
“low”.
After setting the condition code with a CP, the condition code can be tested with a branch instruction. The typical branch
instructions you might use are BE or BNE, BL or BNL, and BH or BNH.
The Compare Register instruction is used to compare a binary fullword in a register, designated by Operand 1, with another
fullword in a register, designated by Operand 2. The operands are compared as 32-bit signed binary integers. The instruction sets
the condition code to indicate how Operand 1 compares to Operand 2:
Condition Code Meaning Test With
0 Operand 1 = Operand 2 BE, BZ
1 Operand 1 < Operand 2 BL, BM
2 Operand 1 > Operand 2 BH, BP
The following example sets the condition code by comparing registers 9 and 6.
CR R9,R6
The contents of the fullword in register 9, x’FFFFFFFF’ = -1, is compared to the contents of register 6 which contains
x’000001AF’ = 431. Since the contents of the Operand 1 register is less than the contents of the Operand 2 register, the condition
code is set to “Low”. The condition code in the diagram above is specified using 2 binary digits. After comparison, the condition
code is set to a binary 01 which is 1 in decimal - a “Low” condition.
The Compare instruction is used to compare a binary fullword in a register, Operand 1, with a fullword in memory, Operand 2.
The operands are compared as 32-bit signed binary integers. The instruction sets the condition code to indicate how Operand 1
compares to Operand 2:
Condition Code Meaning Test With
0 Operand 1 = Operand 2 BE, BZ
1 Operand 1 < Operand 2 BL, BM
2 Operand 1 > Operand 2 BH, BP
C R9,AFIELD
The contents of the fullword “AFIELD”, x’00000020’, is compared to the contents of register 9 which contains x’000000FF’. Since
the contents of the register (Operand 1) is greater than the value than the fullword in memory (Operand 2), the condition code is
set to “High”. The condition code in the diagram above is specified using 2 binary digits. After comparison, the condition code is
set to a binary 10 which is 2 in decimal - a “High” condition.
Since C is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
The Convert to Binary instruction takes packed decimal data and converts it to 2’s complement integer data. Operand 1
designates a register where the result will be stored. Operand 2 represents a doubleword storage area which contains a valid 8-
byte packed decimal integer.
CVB can convert any signed packed decimal integer in the range -2,147,483,648 and +2,147,483,647. If the doubleword
specified in Operand 2 contains an integer outside this range, the 32 rightmost bits of the result are placed in the Operand 1
register and a fixed-point-divide exception is recognized.
In the following example, a packed field of length 4 is converted to binary.
ZAP DOUBWORD,XPACK MOVE PACKED NO TO DOUBLEWORD
CVB R5,DOUBWORD CHANGE IT TO BINARY
...
XPACK DC PL4’123’ X’0000123C’
DOUBWORD DS D
To convert XPACK to binary, we must first move it to a doubleword as required by the CVB instruction. At the end of the
conversion, R5 contains x’0000007B’ = 123.
The diagram below illustrates the relationship between CVB and other data conversion instructions for some common data types.
The Convert to Decimal instruction takes a 2’s complement integer from a register and converts it to packed decimal data in
memory. Operand 1 designates a register containing the 2’s complement integer. Operand 2 represents a doubleword storage
area in memory where the packed decimal data will be placed.
CVD can convert any 2’s complement integer which is contained in a register. This includes all integers in the range -
2,147,483,648 and +2,147,483,647. Since the result is placed in an 8 byte field (doubleword), no overflow can occur since there is
ample room in Operand 2.
In the following example, register 5 is converted to packed decimal and placed in a doubleword. The result can be moved to a
smaller field if the programmer is sure it will fit.
CVD R5,DOUBWORD CHANGE IT TO PACKED DECIMAL
ZAP XPACK,DOUBWORD DATA WILL FIT IN 10 BYTES
...
XPACK DS PL10
DOUBWORD DS D
First the integer in register 5 is converted to packed decimal and placed in a doubleword in memory. Since the doubleword
contains at most 10 decimal digits ( it was converted from a single register ), it can be transferred to XPACK with ZAP.
The diagram below illustrates the relationship between CVD and other data conversion instructions for some common data types.
The Divide instruction performs 2’s complement binary integer division and returns a quotient and a remainder. Operand 1
names an even register of an “even-odd” consecutive register pair. For instance, R2 would be used to name the R2 / R3 even-
odd register pair, and R8 would be used to name the R8 / R9 even-odd register pair. Operand 2 is the name of a fullword in
memory containing the divisor. Before the division, the even-odd register pair must be initialized with the dividend, which is
effectively a 64-bit 2’s complement integer. After the division, the remainder is contained in the even register and the quotient is
contained in the odd register. The sign of the quotient is determined by the rules of algebra. The sign of the remainder will be the
same as the dividend.
In preparing to divide a fullword, a common practice is to load the fullword in the even register and algebraically shift it to the odd
register. This practice propagates the appropriate sign bit throughout the even register and successfully initialized the even/odd
register pair. Here is an example where we compute A/B where A and B are fullwords.
L R8,A PUT THE DIVIDEND IN THE EVEN REGISTER
SRDA R8,32 ALGEBRAICALLY SHIFT R8 INTO R9
D R8,B DIVIDE A BY B
...
A DC F’19’ DIVIDEND
B DC F’5’ DIVISOR
The diagram below illustrates the above division just after R8 has been shifted.
The diagram illustrates that the result of the integer division of 19 by 5 is a remainder of 4 in R8, and a quotient of 3 in R9.
1) Know your data! If the divisor might be zero, you must protect your divisions by testing the divisor beforehand.
CLC DIVISOR,=F’0 IS THE DIVISOR 0?
BE ZERODIV BRANCH IF DIVISOR IS 0
D R8,DIVISOR O.K. TO DIVIDE NOW
...
ZERODIV EQU *
(CODE TO HANDLE A ZERO DIVISOR)
DP is a SS 2 instruction which is used to divide two packed decimal fields and produce a quotient and a remainder. Since
packed decimal fields are integers, the division that occurrs is an integer division. If you are interested in producing a quotient with
decimals, you may need to use SRP to shift the quotient before the division, and ED to provide a decimal point in the output. (See
the topic on “Decimal Precision”.)
Operand 1 is a field containing a packed decimal number which is the dividend. Both the quotient and the remainder develop in
this field. Operand 2 is a packed decimal field containing the divisor. The maximum length of the dividend is 16 bytes, and the
maximum length of the divisor is 8 bytes. Keep in mind the following rules when thinking about the sizes of the generated quotient
and remainder,
1) The remainder size is equal to the size of the divisor.
2) The quotient occupies the portion of operand 1 that is not occupied by the remainder.
The rules make practical sense when you think about the division process. Suppose you divide an m-byte divisor into an n-byte
dividend. Without knowing the specific values, we can see that in an integer division, the remainder might be as large as m bytes,
and the quotient might be as large as n-bytes. This observation leads to the following rule of thumb for creating work fields in
which to perform the calculation,
If the dividend is an n-byte field, and the divisor is an m-byte field, make the work field for the computation at least n+m
bytes.
Following this rule of thumb will insure that the dividend contains a sufficient number of bytes of leading zeroes before the
computation. Specifically, the number of bytes of leading zeroes in the dividend must be at least large as the number of bytes in
the divisor. Here is a sample computation where we want to divide APK by BPK. Since APK is 3 bytes and BPK is 2 bytes, we
create a work area called “WORK” which is 5 bytes. This will provide the required number of bytes of leading 0’s for our
computation.
DP does not set the condition code.
1. Don’t divide by zero. An attempt to divide by zero causes an “0CB” abend. Protect your divisions by testing the divisor before
you divide.
ZAP BPK,BPK IS DIVISOR 0?
BZ ZERODIV BRANCH IF ZERO
ZAP WORK,APK OTHERWISE...
DP WORK,BPK ... WE CAN DIVIDE
...
ZERODIV EQU *
(CODE TO HANDLE A ZERO DIVISOR)
The Divide Register instruction performs 2’s complement binary integer division and returns a quotient and a remainder.
Operand 1 names an even register of an “even-odd” consecutive register pair. For instance, R2 would be used to name the R2 /
R3 even-odd register pair, and R8 would be used to name the R8 / R9 even-odd register pair. Operand 2 names a register that
contains the divisor. Before the division, the even-odd register pair must be initialized with the dividend, which is effectively a 64-
bit 2’s complement integer. After the division, the remainder is contained in the even register and the quotient is contained in the
odd register. The sign of the quotient is determined by the laws of algebra, and the sign of the remainder is the same as the sign
of the dividend.
In preparing to divide a fullword, a common practice is to load the fullword in the even register and algebraically shift it to the odd
register using SRDA. This practice propagates the appropriate sign bit throughout the even register. (If the dividend is positive, the
even register is populated with binary 0’s. If the dividend is negative, the even register is populated with binary 1’s.) Here is an
example where we compute A/B where A and B are fullwords.
L R8,A PUT THE DIVIDEND IN THE EVEN REGISTER
SRDA R8,32 ALGEBRAICALLY SHIFT R8 INTO R9
L R5,B PUT THE DIVISOR IN R5
DR R8,R5 DIVIDE A BY B
...
A DC F’19’ DIVIDEND
B DC F’5’ DIVISOR
The diagram below illustrates the above division just after R8 has been shifted.
The diagram illustrates that the results of the integer division of 19 by 5 is a remainder of 4 in R8, and a quotient of 3 in R9.
1) Know your data! If the divisor might be zero, you must protect your divisions by testing the divisor beforehand.
LTR R5,R5 ASSUME DIVISOR IS IN R5
BZ ZERODIV BRANCH IF DIVISOR IS 0
DR R8,R5 O.K. TO DIVIDE NOW
...
ZERODIV EQU *
(CODE TO HANDLE A ZERO DIVISOR)
2) Unlike the MR instruction, you must initialize the even register. The even/odd register pair must contain a 64 bit binary integer
before you execute the instruction.
Packed decimal fields can be converted to a character format using the ED instruction. Additionally, editing symbols and features
like commas, decimal points, and leading zero suppression can be included in the character version of the packed decimal field that
is being edited. The first step in editing a packed decimal field is to create an “edit word” which is a pattern of what the character
output of the edit process should look like. Typically, the edit word is moved to a field in the output buffer which is being built,
prior to printing. Then the packed decimal field is “edited” into the output field, destroying the copy of the edit word.
First, we consider how to construct an appropriate edit word for a given packed decimal field. This can be accomplished by
defining a string of hexadecimal bytes that represents the edit word. Each byte in the edit word corresponds to a byte in the edited
character representation. In creating the edit word there are a collection of standard symbols which are used to describe each
byte:
X’40’ This symbol, which represents a space, is usually coded as the first byte of the
edit word where it acts as a “fill character”. The fill character is used to replace
leading zeroes which are not “significant”.
X’20’ Called a “digit selector”, this byte represents a position in which a
significant digit from the packed field should be placed.
X’21’ This hexadecimal byte represents a digit selector and a significance starter.
Significance starts when the first non-zero digit is selected. Alternatively, we
can force significance to start by coding a single x’21’ in the edit word. In this
case, significance starts in the byte following the x’21’. Significance is
important because every significant digit is printed, even if it is a leading zero.
X’6B’ This is the EBCDIC code for a comma.
X’4B’ This is the EBCDIC code for a decimal point.
X’60’ This is the EBCDIC code for a minus sign. This symbol is sometimes coded on
the end of an edit word when editing signed fields. The x’60’ byte will be
replaced with the fill character if the number being edited is positive. If the
number is in fact negative, the x’60’ will not be “filled”, and the negative sign will
appear in the edited output.
X’C4C2’ The EBCDIC version of “DB” (Debit). This functions like the x’60’. Coding
these symbols at the end of an edit word causes “DB” to appear in the output
if the field being edited is negative, otherewise the “DB” is “filled”.
X’C3D9’ The EBCDIC version of “CR” (Credit). This functions like the Debit symbol
above. When the number being edited is negative, the “CR” symbol will
appear in the edited output, otherwise it will be “filled”.
X’5C’ The EBCDIC symbol for an asterisk. This character is sometimes used as
a fill character when editing dollar amounts on checks.
We now consider a sample edit word and the output it would create for several packed fields.
EDWD DC X’4020206B2021204B202060’
AOUT DC CL11
APK DC PL4’45387’
The diagram indicates the results of the edit process: The fill character (x’40’) is unaffected, and is left in its position. The first
decimal digit, 0, is “selected” by the first x’20’, and since leading 0’s are not significant, the x’20’ is replaced by the fill character.
The second digit, 0, is also selected, and it too, is filled with a x’40’. Since significance has not started, the x’6B’ is filled with
x’40’. The first non-zero digit, 4, is selected and this signals that significance has started. (Any non-zero digit which is selected
turns on the significance indicator.) Each digit after the 4 will appear in the edited result. The “4” is replaced with its character
equivalent - x’F4’. The “5” is selected and its x’20’ is replaced with x’F5’. The “3” is selected and is represented as x’F3’. The
x’4B’, a decimal point, remains unaffected. The “8” is selected and is represented as x’F8’. The “7” is selected and is represented
as x’F7’. Since the number being edited is positive, the x’60’ is filled with x’40’. The final result would print as “ 453.87 “.
Consider a second edit which uses the same edit word as in the previous example, but with a different value for APK.
EDWD DC X’4020206B2021204B202060’
AOUT DC CL11
APK DC PL4’-7’
Again we execute the same sequence of instructions.
MVC AOUT,EDWD
ED AOUT,APK
As in every edit, the x’40’ fill character is unaffected by the edit process. The first and second digits, both 0, are selected, and
since they are leading 0’s and significance has not started, they are filled with x’40’. The x’6B’ is also filled with x’40’ since
significance has not started. The next two digits, both 0, are selected and filled. Since the x’21’ selected a leading 0, the
significance indicator is turned on - significance starts with the next digit. This means that all other digits will appear in a character
1. There are two errors that beginners make when using ED :
1) The number of x’20’s and x’21’s does not match the number of decimal digits in the field
being edited. This is a critical error. If the packed field has length “n”, the number of
x’20’s and x’21’s is 2n - 1. For example, if you are editing a packed field of length 6, the
edit word must contain exactly 11 x’20’s and x’21’s. A bad edit word will produce
unpredictable output.
2) The output field size does not match the edit word size. For example, suppose you coded
Packed decimal fields can be converted to a character format using the EDMK instruction. Additionally, editing symbols and
features like commas, decimal points, and leading zero suppression can be included in the character version of the packed decimal
field that is being edited. EDMK is equivalent to the ED instruction but offers additional functionality which will be covered later in
this discussion.
The first step in editing a packed decimal field is to create an “edit word” which is a pattern of what the character output of the
edit process should look like. Typically, the edit word is moved to a field in the output buffer which is being built, prior to printing.
Then the packed decimal field is “edited” into the output field, destroying the copy of the edit word.
First, we consider how to construct an appropriate edit word for a given packed decimal field. This can be accomplished by
defining a string of hexadecimal bytes that represents the edit word. Each byte in the edit word corresponds to a byte in the edited
character representation. In creating the edit word there are a collection of standard symbols which are used to describe each
byte:
X’40’ This symbol, which represents a space, is usually coded as the first byte of the
edit word where it acts as a “fill character”. The fill character is used to replace
leading zeroes which are not “significant”.
X’20’ Called a “digit selector”, this byte represents a position in which a
significant digit from the packed field should be placed.
X’21’ This hexadecimal byte represents a digit selector and a significance starter.
Significance starts when the first non-zero digit is selected. Alternatively, we
can force significance to start by coding a single x’21’ in the edit word. In this
case, significance starts in the byte following the x’21’. Significance is
important because every significant digit is printed, even if it is a leading zero.
X’6B’ This is the EBCDIC code for a comma.
X’4B’ This is the EBCDIC code for a decimal point.
X’60’ This is the EBCDIC code for a minus sign. This symbol is sometimes coded on
the end of an edit word when editing signed fields. The x’60’ byte will be
replaced with the fill character if the number being edited is positive. If the
number is in fact negative, the x’60’ will not be “filled”, and the negative sign will
appear in the edited output.
X’C4C2’ The EBCDIC version of “DB” (Debit). This functions like the x’60’. Coding
these symbols at the end of an edit word causes “DB” to appear in the output
if the field being edited is negative, otherewise the “DB” is “filled”.
X’C3D9’ The EBCDIC version of “CR” (Credit). This functions like the Debit symbol
above. When the number being edited is negative, the “CR” symbol will
appear in the edited output, otherwise it will be “filled”.
X’5C’ The EBCDIC symbol for an asterisk. This character is sometimes used as
a fill character when editing dollar amounts on checks.
We now consider a sample edit word and the output it would create for several packed fields.
The diagram indicates the results of the edit process: The fill character (x’40’) is unaffected, and is left in its position. The first
decimal digit, 0, is “selected” by the first x’20’, and since leading 0’s are not significant, the x’20’ is replaced by the fill character.
The second digit, 0, is also selected, and it too, is filled with a x’40’. Since significance has not started, the x’6B’ is filled with
x’40’. The first non-zero digit, 4, is selected and this signals that significance has started. (Any non-zero digit which is selected
turns on the significance indicator.) Each digit after the 4 will appear in the edited result. The “4” is replaced with its character
equivalent - x’F4’. At this point, the address of AOUT+4 (the position occupied by the first significant digit x’F4’, is copied into
register 1. (The ED instruction would not initialize register 1.) Afterward, the “5” is selected and its x’20’ is replaced with x’F5’.
The “3” is selected and is represented as x’F3’. The x’4B’, a decimal point, remains unaffected. The “8” is selected and is
represented as x’F8’. The “7” is selected and is represented as x’F7’. Since the number being edited is positive, the x’60’ is filled
with x’40’. The final result would print as “ 453.87 “.
Consider a second edit which uses the same edit word as in the previous example, but with a different value for APK.
EDWD DC X’4020206B2021204B202060’
AOUT DC CL11
APK DC PL4’-7’
Again we execute the same sequence of instructions.
MVC AOUT,EDWD
EDMK AOUT,APK
1. There are two errors that beginners make when using EDMK :
1) The number of x’20’s and x’21’s does not match the number of decimal digits in the field
being edited. This is a critical error. If the packed field has length “n”, the number of
x’20’s and x’21’s is 2n - 1. For example, if you are editing a packed field of length 6, the
edit word must contain exactly 11 x’20’s and x’21’s. A bad edit word will produce
unpredictable output.
2) The output field size does not match the edit word size. For example, suppose you coded
the following,
AEDWD DC X’402020202120’
AOUT DS CL5
When the edit word is moved to AOUT, the last byte of the edit word is not moved since
the edit word is 6 bytes and the target field is 5 bytes. The effect is that we are using an
incorrect edit word, even though the definition of the edit word was correct.
2) When editing, start with the packed field and design an edit word that matches it. Then define the output field to match the edit
word. For example, if we start with a packed field of length 3 (5 decimal digits), we could design x’402021204B2020’ as an
appropriate edit word (5 x’20’s and x’21’s). Since the edit word is 7 bytes long, we would design a 7 byte output field to hold the
edit word.
XPK DS PL3
XEDWD DC X’402021204B2020’
XOUT DS CL7
...
MVC XOUT,XEDWD
LA R1,XOUT+3
EDMK XOUT,XPK
3) Be sure to initialize R1 before issuing the EDMK instruction. R1 should contain the address of the byte following the
significance starter (x’21’).
The Execute instruction causes the computer to execute a “target” instruction which is referenced in Operand 2 and which is
typically placed out of the normal sequence of instructions, usually among a collection of DC’s or DS’s. After the target instruction
is executed, control returns to the instruction following the EX instruction unless the target instruction was a branch. If the target
instruction is a conditional branch, then control would resume at the address specified in the branch if the condition being tested is
true. If the target instruction is an unconditional branch, then execution would resume at the address specified in the branch
instruction. Typically, the target instruction is an MVC.
If Operand 1 is not register zero, then the target instruction is temporarily modified before it is executed: The rightmost byte of
the register specified by Operand 1 (bits 24 - 31) is “OR-ed” into the second byte of the target instruction. Usually the second byte
contains x’00’ which means that the rightmost byte of Operand 1 is copied into the second byte of the target instruction just before
the target instruction is executed. In the case where the target is an MVC instruction, the second byte is the length byte (the
number of bytes to be moved). This means the length can be dynamically changed before executing the MVC instruction. This is
an important reason to use EX.
If Operand 1 is register zero, then the target instruction is executed without modification. Here is an example. We execute the
following instruction
EX R5,TARGET
In the previous example the target instruction moves a field called “Y” to a field called “X”. Notice that the length in operand 1 is
explicitly zero. By coding this we guarantee that the second byte that is assembled for the MVC instruction contains x’00’. Before
executing the target instruction, the length contained in the rightmost byte of register 5 (x’03’) is “Or-ed” into the second byte of the
MVC instruction. Since this byte is all binary 0’s, the “Or” works like a copy. At run-time, the length byte contains x’03’ which
causes 4 bytes to be moved into X. Remember that for MVC’s, the number of bytes in the object code is always 1 less than the
number of bytes that the machine moves.
1. The standard use for an execute instruction is to support variable length moves. The previous examples illustrate that
instructions other than MVC can be executed but this should be carefully considered. For instance, in executing an LR instruction,
the registers can be selected dynamically. This is probably not a wise choice and may result in a program that is very difficult to
debug.
2. When coding the target instruction, be sure and specify an explicit length of zero so the second byte of the machine code is
x’00’.
3. Place the target instruction in a place where it will never be executed except as the target of an EX instruction. Most
programmers put the target instructions among their DS’s and DC’s.
4. While the target instruction can be any instruction except another EX instruction, you should limit the target instructions to
MVC’s.
IC is used to copy a single byte from storage into the rightmost byte of a register. The register is specified in operand 1, and the
one-byte storage location is denoted by operand 2. Only the right-most byte of the register is changed. All other bytes in the
register remain unchanged. Only the first byte of the field specified in storage is copied to the register.
A common use of the IC instruction is to move a one-byte binary length into the right-most byte of a register. The register will
subsequently be used by an EX (Execute) instruction in order to move a variable number of bytes. Here is an example of this
technique.
TARGET MVC FIELDA(0),FIELDB
LENGTH DC AL1(8) A ONE-BYTE LENGTH = 8
...
IC R8,LENGTH (INITIALLY 8,LENGTH MIGHT CHANGE)
EX R8,TARGET EXECUTE THE TARGET INSTRUCTION
For the following examples, assume that R8 contains x’11223344’.
FIELDA DS X’AABBCCDD’
1. It is a standard practice to use IC in conjunction with EX for moving variable length fields. Remember that the inserted length of
“X” is treated as length “X + 1” when the MVC is executed. In other words the assembled length in a MVC instruction is 1 less
than the actual length.
ICM is used to copy consecutive bytes from memory into selected bytes of a register. Up to 4 bytes can be copied into the
register which is specified by operand 1. The bytes that are copied, come from consecutive bytes in memory specified by operand
3. Additionally, the programmer supplies a mask (pattern), usually in binary, that indicates which bytes in the register should be
changed. For example, a binary pattern of B’1010’ indicates that bytes 1 and 3 (numbering from left to right) are targets of the
copying operation. A binary mask of B’0011’ indicates that two consecutive bytes from memory should be copied into the bytes 3
and 4 of the register. Consider the following example.
Often, ICM is used instead of “LH” or “L“ to load halfwords and fullwords when these fields are not properly aligned. The use of
a load instruction for a 4-byte field that is not aligned on a fullword produces a warning from the assembler. Similar remarks apply
to the load halfword instruction.
For the following examples, assume that R8 contains x’AABBCCDD’.
FIELDA DS X’11223344’
FIELDB DS C’ABCD’
FIELDC DC HL2’20’ MAY NOT BE PROPERLY ALIGNED
1. Use ICM instead of load or load halfword when the field you are loading may not be properly aligned.
2. Remember that the mask applies to the bytes in the register and not the bytes in memory. Bytes in memory are consecutively
loaded.
3. It is good documentation to always use a binary self-defining term when creating the mask.
L is used to copy the fullword stored in the memory location designated by operand 2 into the register specified by operand 1.
Consider the following example,
L R9,AFIELD
The contents of the fullword “AFIELD” are copied to register 9, destroying the previous values in R9. The fullword is unchanged
by this operation.
Since L is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
LA is used to initialize the register specified by operand 1 with the address designated by operand 2. Operand 2 may be
expressed using explicit notation ( see Explicit Addressing) or symbolic notation, or a combination of both. Remember that each
byte in memory is numbered and that the number assigned to a byte is its address. The address of a field is the address of the
first byte of the field. Consider the following example,
LA R9,AFIELD
The address of the fullword “AFIELD” , x’00001000’, is copied to register 9, destroying the previous value in R9. The fullword is
unchanged by this operation.
Since LA is an RX instruction, an index register may be coded as part of operand 2 as in the example below. We assume that
register 6 is used as an index register and initially contains x’0000002F’. When the assembler processes the expression
AFIELD(R6), it uses the symbol AFIELD to determine a base register and a displacement, leaving R6 as the index register. The
address which is loaded into register 9 is the “effective address” computed by adding the base register contents, plus the index
register contents, plus the displacement:
Effective address = C(Base register) + C(Index register) + displacement
We assume that the contents of the base register plus the displacement is x’00001000’. Then the effective address is x’00001000’
+ x’0000002F’ = x’0000102F’ .
LA R9,AFIELD(R6)
The example above uses a mixture of symbolic and explicit addressing. The instruction could also be coded using only explicit
addresses:
LA R9,30(R7,R8)
In the example above assume that R7 contains x’00001000’ and that R8 contains x’00000020’. R7 is treated as an index register,
R8 is the base register, and 30 is a displacement. The effective address is C(R7) + C(R8) + 30 = x’00001000” + x’00000020’ +
x’0000001E’ = x’0000103E’. (Remember that a decimal 30 is 1E in hexadecimal.) After the instruction has executed, R9 contains
x’0000103E’.
The Load Complement instruction copies the two’s complement value (See Binary Arithmetic) of the contents of the register
specified by Operand 2, into the register specified by Operand 1. The contents of Operand 2 are unchanged by this operation.
Remember that if you add an integer and its two’s complement, the result is zero. (The two’s complement of 5 is -5. The two’s
complement of -33 is 33.) LCR sets the condition code based on the final contents of the Operand 1 register.
Condition Code Meaning Test With
0 (Zero) Operand 1 = 0 BE, BZ
1 (Negative) Operand 1 < 0 BL, BM
2 (Positive) Operand 1 > 0 BH, BP
3 (Overflow) Overflow BO
An overflow condition can occur only when Operand 2 contains the maximum negative value that will fit in a register (-
2,147,483,648). An overflow occurs because the complement will not fit in a single register.
Consider the instruction below. Assume R10 contains x’00000078’ = 120.
LCR R5,R10
The contents of register 10 are complemented and copied to register 5, destroying the previous value in register 5. At completion,
register 5 contains a binary number equivalent to -120 in decimal. Register 10, which contains a binary number equal to 120 in
decimal, is unaffected by the operation. Since the contents of R5 is negative after completion of the operation, the condition code
is set to 1. The diagram below illustrates this operation.
LM is used to copy a set of consecutive fullwords in main storage into a “consecutive” collection of registers. The collection of
registers is specified by coding the beginning and ending registers as the first two operands. For instance,
LM R5,R8,XWORDS
would be used to load registers 5, 6, 7, and 8. If the second operand specifies a lower register than the first operand, then a
“wrap-around” occurs. For instance,
LM R14,R12,12(R13)
would be used to load registers 14, 15, 0, 1, ..., 12 - every register except 13.
The registers are loaded starting with the fullword at the address specified in the third operand. In the first example above,
register 5 would be loaded with the fullword at XWORDS, register 6 with the fullword at XWORDS+4, register 7 with the fullword
at XWORDS+8, and register 8 with the fullword at XWORDS+12. In the second example, register 14 is loaded with the fullword at
the explicit address indicated as a 12 byte displacement off register 13. Register 15 is loaded with the fullword at a 16 byte
displacement off register 13. Register 0 is loaded with the fullword at a 20 byte displacement off register 13. The remaining
registers are loaded in a similar manner.
Here is an illustrated example.
STM R7,R9,REGWORDS
In the example above, the consecutive range of registers ( 7, 8, and 9 ) are loaded with three consecutive fullwords in memory
starting with the fullword specified as REGWORDS.
1) This instruction is helpful for creating subroutines. Branch to a subroutine and immediately save the registers with STM. This
allows your subroutine to freely use the registers. Before exiting your subroutine, restore the registers with LM. Create a register
“save area” for each subroutine.
BAS R6,SUBRTN CALL THE SUBROUTINE
...
SUBRTN EQU *
STM R14,R12,SUBSAVE SAVE THE REGISTERS
... (SUBROUTINE CODE)
LM R14,R12,SUBSAVE RESTORE THE REGISTERS
BR R6 BRANCH BACK TO CALLER
SUBSAVE DS 15F FIFTEEN FULLWORDS FOR THE REGISTERS
2) Read about the role that LM plays in implementing the Program Linkage conventions.
The Load Negative instruction copies the two’s complement of the absolute value of the contents of the register specified by
Operand 2, into the register specified by Operand 1. The contents of Operand 2 are unchanged by this operation. Recall that
absolute value of an integer x, denoted by | x | , is defined as follows,
| x | = x if x ³ 0 and | x | = -x if x < 0
For example, | 7 | = 7 since 7 ³ 0, and | -5 | = 5 since -5 < 0.
LNR insures that the contents of Operand 1 will be negative or zero after the operation has completed. Negative integers and
zero are unchanged by this instruction. For positive integers, the two’s complement of the integer is placed in Operand 1.
The condition code is set by this instruction based on the final contents of Operand 1.
Condition Code Meaning Test With
0 (Zero) Operand 1 = 0 BE, BZ
1 (Negative) Operand 1 < 0 BM, BL
An overflow condition can not occur.
Consider the instruction below.
LNR R5,R10
The contents of register 10 are examined and determined to be positive. As a result, the complement of the contents of register 10
are copied to register 5, destroying the previous value in register 5. Register 10, which contains a binary number equal to 120 in
decimal, is unaffected by the operation. Since the contents of R5 are negative after completion of the operation, the condition code
is set to 1. The diagram below illustrates this operation.
The LH instruction has two operands: the first operand is a general purpose register, and the second operand is a halfword in
memory. The effect of the instruction is to place a 32-bit signed integer, algebraically equivalent to the 16-bit halfword, into
Operand 1. The 32-bit integer can be obtained by extending the sign-bit of the halfword so that it occupies 32 bits. (Extending the
sign bit of 2’s complement data does not change its arithmetic value.) Consider the following example.
LH R9,AFIELD
The halfword “AFIELD” contains a binary 1 in the sign-bit. A sign-extended version of the halfword is copied into register 9,
destroying the previous values in the register. The halfword is unchanged by this operation.
Since LH is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
The Load Positive instruction copies the absolute value of the contents of the register specified by Operand 2, into the register
specified by Operand 1. The contents of Operand 2 are unchanged by this operation. Recall that absolute value of an integer x,
denoted by | x | , is defined as follows,
| x | = x if x ³ 0 and | x | = -x if x < 0
For example, | 7 | = 7 since 7 ³ 0, and | -5 | = 5 since -5 < 0.
LPR insures that the contents of Operand 1 will be non-negative after the operation has completed if an overflow has not
occured. Positive integers and zero are unchanged by this instruction. For negative integers, the two’s complement of the integer
is placed in Operand 1.
The condition code is set by this instruction based on the final contents of Operand 1.
Condition Code Meaning Test With
0 (Zero) Operand 1 = 0 BE, BZ
2 (Positive) Operand 1 > 0 BH, BP
3 (Overflow) Overflow BO
An overflow condition can occur only when Operand 2 contains the maximum negative value that will fit in a register (-
2,147,483,648). An overflow occurs because the absolute value will not fit in a single register.
Consider the instruction below.
LPR R5,R10
The contents of register 10 are examined and determined to be positive. As a result, the contents of register 10 are copied to
register 5, destroying the previous value in register 5. Register 10, which contains a binary number equal to 120 in decimal, is
unaffected by the operation. Since the contents of R5 is positive after completion of the operation, the condition code is set to 2.
The diagram below illustrates this operation.
The Load Register instruction copies the contents of the register specified by Operand 2, into the register specified by Operand
1. The contents of Operand 2 are unchanged as well as the condition code. Consider the instruction below.
LR R5,R10
The contents of register 10 are copied to register 5, destroying the previous value in register 5. Register 10 is unaffected by the
operation. The diagram below illustrates this operation.
The Load and Test Register instruction copies the contents of the register specified by Operand 2, into the register specified by
Operand 1. The contents of Operand 2 are unchanged by this operation. In this respect LTR is equivalent to the LR instruction.
The difference between these instructions is that LTR sets the condition code based on the final contents of the Operand 1
register.
Condition Code Meaning Test With
0 (Zero) Operand 1 = 0 BE, BZ
1 (Negative) Operand 1 < 0 BL, BM
2 (Positive) Operand 1 > 0 BH, BP
Consider the instruction below.
LTR R5,R10
The contents of register 10 are copied to register 5, destroying the previous value in register 5. Register 10 is unaffected by the
operation. Since the contents of R5 is positive after completion of the operation, the condition code is set to 2. The diagram below
illustrates this operation.
1) LTR is commonly used to test the contents of a single register in order to determine if the binary number is the register is
positive, negative or zero. For example, the following code illustrates how to test the contents of register 5.
LTR R5,R5 SET THE CONDITION CODE
BM NEGATIVE IS R5 < 0 ?
BP POSITIVE IS R5 > 0?
ZERO EQU *
...
NEGATIVE EQU *
...
POSITIVE EQU *
The Multiply instruction performs 2’s complement binary multiplication. Operand 1 names an even register of an “even-odd”
consecutive register pair. For instance, R2 would be used to name the R2 / R3 even-odd register pair, and R8 would be used to
name the R8 / R9 even-odd register pair. Operand 2 is the name of a fullword in memory containing the multiplier. Before the
multiplication, the even register can be left uninitialized, while the odd register contains the multiplicand. After the multiplication,
the product occupies the even-odd register pair in 2’s complement format.
If the product is less than 2 31 - 1 = 2,147,483,647 then the answer can be found in the odd register. We may then use CVD
and ED in order to print the product. Otherwise, the even-odd pair must be treated as a large (64 bit) 2’s complement integer.
Printing such an integer requires special treatment which we will consider later. First, lets look at an example multiplication. We
assume that AWORD is a fullword in memory containing the integer 10.
L R9,=F’47’ PUT MULTIPLICAND IN ODD REGISTER
M R8,AWORD MULTIPLY 47 TIMES 10
First the multiplicand, 47, is loaded into the odd register. The even register is left uninitialized. The multiplier, AWORD,
contains a 10 and is not affected by the multiplication. After the multiplication, the register pair R8 / R9 contains a 64 bit 2’s
complement integer. Since the product is sufficiently small, R9 by itself contains a valid representation of the product.
When the product will not fit in the odd register, we must provide special handling in order to convert the product to a packed
representation. If it takes two registers to hold the a result, we will call the answer a “double precision” result. Unfortunately, there
is no instruction that will convert a 2’s complement double precision integer to a packed decimal format. CVD can be used to
convert a single register to packed format, so we will investigate how this instruction can be used on both registers. To simplify the
computations, we will assume that the registers contain 4 bits instead of 32. Suppose a multiplication has produced a double
precision product of 83 in registers R4 and R5. Then, since 83 = B’01010011’, and assuming 4 bit registers, R4 = B’0101’ and R5
This procedure also works for some negative double precision integers. Consider the double precision integer -108. Using 4-bit
registers R4 and R5, we see that R4 contains B’1001’ and R5 contains B’0100’. CVD converts R4 to -7 when, in fact, the bits in
R4, B’1001’, represent -112 = -7 x 16. R5 = B ‘0100’ is converted to 4. Adding -112 + 4 we get the correct double precision
answer -108. This is illustrated below.
A problem with this method occurs when the odd register contains a 1 in the high-order bit. Consider the double precision
integer 60 = B’00111100’. Assume R4 contains B’0011’ and R5 contains B’1100’. The conversion is illustrated below.
R4 is converted to 3, multiplied by 16, and correctly converted to 48. On the other hand, R5 is converted to -4 since the high
order bit was a 1. R5 should have been converted to 12. We are off by a factor or 16. If we add 16, the conversion to 12 will be
correct.
These examples lead us to a conversion algorithm for double precision results:
1) Test the odd register to see if it is negative. If it is, we need to add 2 32 = 4,294,967,296 ( we are using 32-bit registers
instead of 4-bit registers ) to the final result. An easy way to do this is by adding 1 to the even register - the rightmost bit in the
even register represents 2 32 .
2) Convert the even register to packed decimal and multiply the result by 2 32 .
1) Know your data! In most cases, the product of a multiplication will fit in the odd register where it can easily be converted back
to packed decimal. If you have any doubts about the size of a generated product, you must convert the double precision result
from both the even and odd registers as described above.
MP is a SS 2 instruction which is used to multiply packed decimal fields. Operand 1 is a field in storage which initially contains a
packed decimal number representing the multiplicand. The product develops in this field, destroying the multiplicand. The
contents of Operand 2, another packed decimal field in storage, represents the multiplier. This field is unchanged by the
multiplication (unless it also participates as operand 1). The condition code is not set by this instruction.
There are three rules that must be followed concerning the lengths of the fields that participate in a multiply packed instruction.
1) The multiplier is limited to a maximum of 8 bytes.
2) The multiplicand field can be as large as 16 bytes.
3) If the length of operand 2 is “L2”, then the multiplicand must contain at least L2 bytes of leading zeroes before the instruction
is executed.
For example,
APK DC PL4’12345’ = X’0012345C’
BPK DC PL2’100’ = X’100C’
...
MP APK,BPK
The MP above causes an “0C6” abend because APK contains 1 byte of leading zeroes and BPK is 2 bytes long. In order to
multiply APK and BPK above, we must code a work area that is large enough to support a sufficient number of leading zeroes.
Adding the lengths of both fields we see that a field of length 6 is large enough to prevent this problem.
WORK DS PL6
...
ZAP WORK,APK
MP WORK,BPK
1. When creating a work field for a multiplication, the rule of thumb is to make the work area at least as large as the sum of the
fields that contain the multiplicand and the multiplier. There is no harm in overestimating the size of the work area, but an area
that is too small will cause an abend.
The Multiply Halfword instruction performs 2’s complement binary multiplication. Operand 1 names a single register (even or
odd) which will contain the multiplicand. Operand 2 is the name of a halfword in memory containing the multiplier. After the
multiplication, the product is left in Operand 1, destroying the multiplicand. It is possible to generate a product that will not fit in a
single register, but an overflow will not be indicated. Leftmost bits in the product could be truncated to 32 bits in Operand 1. The
programmer must be aware of the limits of the data being processed and protect against the possibilities of overflows. Select a
fullword multiplication (M) if you are unsure of your data.
Assume you want to multiply a fullword field called “COST” by a halfword field called “NOITEMS”. The following code would
accomplish this task and leave the product in register 5.
L R5,COST
MH R5,NOITEMS
1) Know your data! To use MH, one of the operands must be small enough to fit in a halfword. This range is -32768 to +32,767.
The product of the multiplication must fit in a single register where the range of integers is -2,147,483,648 to +2,147,483,647. In
many cases, the product of a multiplication will fit in a single register. If you have any doubts about the size of a generated
product, use M instead of MH.
The Multiply Register instruction performs 2’s complement binary multiplication. Operand 1 names an even register of an “even-
odd” consecutive register pair. For instance, R2 would be used to name the R2 / R3 even-odd register pair, and R8 would be
used to name the R8 / R9 even-odd register pair. Operand 2 names a register containing the multiplier. Before the multiplication,
the even register can be left uninitialized, while the odd register contains the multiplicand. After the multiplication, the product
occupies the even-odd register pair in 2’s complement format.
If the product is less than 2 31 - 1 = 2,147,483,647 then the answer can be found in the odd register. We may then use CVD
and ED in order to print the product. Otherwise, the even-odd pair must be treated as a large (64 bit) 2’s complement integer.
Printing such an integer requires special treatment we will examine later. First, lets look at an example multiplication.
L R9,=F’47’ PUT MULTIPLICAND IN ODD REGISTER
L R5,=F’10’ PUT MULIPLIER IN A REGISTER
MR R8,R5 MULTIPLY EVEN/ODD PAIR(8/9)TIMES R5
First the multiplicand, 47, is loaded into the odd register. The even register is left uninitialized and is shown above to contain
x’000AB356’ (this is arbitrary). The integer 10 is loaded into R5 and acts as the multiplier. After the multiplication, the register pair
R8 / R9 contains a 64 bit 2’s complement integer representing the product. Since the product is sufficiently small, R9 by itself
contains a valid representation of the product.
When the product will not fit in the odd register, we must provide special handling in order to convert the product to a packed
representation. If it takes two registers to hold the a result, we will call the answer a “double precision” result. Unfortunately, there
is no instruction that will convert a 2’s complement double precision integer to a packed decimal format. CVD can be used to
convert a single register to packed format, so we will investigate how this instruction can be used on both registers. For the
purposes of demonstration, and to simplify the computations, we will assume that the registers contain 4 bits instead of 32.
This procedure also works for some negative double precision integers. Consider the double precision integer -108. Using 4-bit
registers R4 and R5, we see that R4 contains B’1001’ and R5 contains B’0100’. CVD converts R4 to -7 when, in fact, the bits in
R4, B’1001’, represent -112 = -7 x 16. R5 = B ‘0100’ is converted to 4. Adding -112 + 4 we get the correct double precision
answer -108. This is illustrated below.
A problem with this method occurs when the odd register contains a 1 in the high-order bit. Consider the double precision
integer 60 = B’00111100’. Assume R4 contains B’0011’ and R5 contains B’1100’. The conversion is illustrated below.
R4 is converted to 3, multiplied by 16, and correctly converted to 48. On the other hand, R5 is converted to -4 since the high
order bit was a 1. R5 should have been converted to 12. We are off by a factor or 16. If we add 16, the conversion to 12 will be
correct.
These examples lead us to a conversion algorithm for double precision results:
1) Test the odd register to see if it is negative. If it is, we need to add 2 32 = 4,294,967,296 ( we are using 32-bit registers
instead of 4-bit registers ) to the final result. An easy way to do this is by adding 1 to the even register - the rightmost bit in the
even register represents 2 32 .
1) Know your data! In most cases, the product of a multiplication will fit in the odd register where it can easily be converted back
to packed decimal. If you have any doubts about the size of a generated product, you must convert the double precision result
from both the even and odd registers as described above.
2) Rather than leave the even register uninitialized, you can use it to hold the multiplier. If you do this, the multiplier will be
MVC is an instruction which is designed to copy a collection of consecutive bytes from one storage location to another. As you
can see from the instruction format above, the instruction carries with it the number of bytes to be copied, as well as the beginning
addresses of the source and target fields. Notice that the instruction does not specify the ending addresses of either field - the
instruction is no respecter of fields. MVC copies LL 1 + 1 consecutive bytes from the storage location designated by B2 D 2 D 2 D 2 to
the storage location designated by B1 D 1 D 1 D 1 . The copying occurs one byte at a time from Operand 2 to Operand 1, and within
each operand, from lower to higher numbered addresses.
The length (LL1 ) determines the number of bytes which will be copied. The length is usually determined implicitly from the
length of operand 1 but the programmer can provide an explicit length. Consider the two example MVC’s below,
Object code Assembler code
FIELDA DS CL8
FIELDB DS CL5
...
D207C008C010 MVC FIELDA,FIELDB Implicit length
D202C008C010 MVC FIELDA(3),FIELDB Explicit length
In the first example, the length implicitly defaults to 8, the length of FIELDA. In the second example, the length is explicitly 3.
Notice that the assembled length (LL1 ) is one less than the implicit or explicit length. This can be seen in the object code above
where the assembled lengths are x’07’ and x’02’.
The copying operation is usually straightforward, but can be more complicated by overlapping the source and target fields. Keep
in mind that the copy is made one byte at a time. Consider the following examples,
Object code Assembler code
ONE DC C’1’
FIELDA DC CL3’ABC’
FIELDB DC CL3’DEF’
FIELDC DC CL4’1234’
...
D202C008C00B MVC FIELDA,FIELDB After FIELDA = ’DEF’
D201C00EC008 MVC FIELDC,FIELDA After FIELDC = ’ABCD’
D201C008C007 MVC FIELDA,ONE After FIELDA = ’1111’
In the first MVC above, 3 consecutive bytes in FIELDB are simply copied to FIELDA. In the second example, 4 consecutive bytes
are copied into FIELDC (implicit length = 4) from FIELDA. Since FIELDA was only 3 bytes long the fourth byte was copied from
the first byte of the next field - FIELDB. The third MVC is complicated by the fact that the source and target fields overlap. We will
examine the third move in some detail.
The example above depends heavily on the fact that the source and target fields overlap and that bytes are copied one at a time.
In fact, it is common to use this technique to clear fields. Assume you have a buffer you would like to clear to spaces. By defining
a single blank directly in front of the field you want to clear and moving the blank field to the buffer, the blank can be propagated
throughout the buffer:
MVC BUFFER,BLANK BLANK IS PROPAGATED
...
BLANK DC C’’ BLANK MUST IMMEDIATELY PRECEDE…
BUFFER DS CL133 …THE BUFFER
1. Pay attention to the lengths of the fields involved in any MVC statement. If the target field is longer than the source field, bytes
following the source may be transferred. If the target field is shorter than the source field, bytes from the source may may be
truncated.
2. Be careful of using literals in an MVC, since stray bytes in the literal pool will be moved if the specified length is longer than
There is a 256 byte limitation when moving character data with MVC. If a field is larger than 256 bytes, one solution to moving it
in memory is to divide it into multiple parts and code multiple MVC’s. A more elegant solution involves the Move (Characters) Long
instruction (MVCL) which was designed for fields longer than 256 bytes. In fact, up to 2 24 = 16,777,216 bytes can be moved with
one MVCL instruction. This instruction is unusual because it requires the use of four registers. Operand 1 and operand 2, denoted
by R1 and R2, each represent the even register of an even-odd consecutive register pair (2-3, 4-5, 6-7, …). For example, if you
coded “MVCL R4,R8” the registers involved would be R4, R5, R8, and R9. The even registers contain the address of target and
source fields, while the odd registers contain the lengths of target and source fields. Additionally, a pad character can be placed in
the high order byte of the odd register which contains the length of the source field. The pad character is used to fill up the target
field when the source field is shorter and all of its contents have been transmitted. Here is a simple example in which we want to
move FIELDB to FIELDA:
LA R4,FIELDA POINT AT TARGET FIELD WITH EVEN REG
L R5,LENGTHA PUT LENGTH OF TARGET IN ODD REG
LA R6,FIELDB POINT AT SOURCE FIELD WITH EVEN REG
L R7,LENGTHB PUT LENGTH OF SOURCE IN ODD REG
ICM R7,B’1000’,BLANK INSERT A SINGLE BLANK PAD CHAR IN ODD REG
MVC R4,R6
…
FIELDA DC CL2000’ ’
BDATA DC 1000CL1’X’
ORG BDATA
FIELDB DS CL1000
LENGTHA DC A(L’FIELDA) CREATE AN ADDRESS CONSTANT THAT IS A LENGTH
LENGTHB DC A(L’FIELDB) CREATE AN ADDRESS CONSTANT THAT IS A LENGTH
BLANK DC C’ ’
The above code copies 1000 X’s from FIELDB into FIELDA. Since FIELDA was larger than FIELDB, the last 1000 bytes of
FIELDA are filled with the blank pad character. If the length of FIELDA were equal to or smaller than the length of FIELDB, the
pad character would not be used.
Bytes are transferred one at a time in a fashion similar to MVC, by MVCL. As each byte is copied from source to target, the
even registers are incremented by one and the odd registers are decremented by one until one of the lengths in the odd registers
becomes zero.
Consider the following scenarios with MVCL in which we are copying from field A to field B. Assume the length of A is L1 and
the length of B is L2 . Further assume A(A) and A(B) are the addresses of A and B. Lengths are specified in decimal and we
assume a blank pad character in R7.
Case 1: L1 > L2
Before execution:
R4 R5 R6 R7
MVCL detects destructive overlap conditions and prevents any bytes from being moved. Instead, MVCL sets the condition code
to indicate destructive overlap. This condition can be tested with BO.
MVCL sets the condition code to 0 (equal) if L1 = L2, to 1 (low) if L1 < L2, to 2 (high) if L1 > L2, and 3 (overflow) if no bytes are
moved due to destructive overlap.
You can use MVCL to blank out a target field by setting the length of the source to 0. This forces the pad character to be copied
to each byte of the source:
LA R8,TARGET
L R9,TARLEN
LA R4,SOURCE SOURCE DOESN’T PARTICIPATE
LA R5,0 SET THE LENGTH OF SOURCE TO 0
ICM R5,B’1000’,BLANK SET PAD BY TO A BLANK
MVCL R8,R4 COPY BLANKS
It is often difficult to find four available registers when coding MVCL. A simple solution to this problem is to store four
consecutive registers in a save area before using MVCL and restore them afterwards:
STM R4,R7,SAVE4
(use MVCL here…)
LM R4,R7,SAVE4
…
SAVE4 DS 4F FOUR FULLWORDS FOR R4,R5,R6, AND R7
Use length attributes for the lengths of the source and target fields:
LENGTHA DC A(L’FIELDA) TURN THE LENGTH INTO A FULLWORD “ADDRESS”
MVI is used to move a one byte immediate constant to a field in storage. Operand 1 denotes the field in main storage, while the
second operand is coded as a self-defining term that gets assembled as a one byte immediate constant (II 2 ) in the second byte
of the object code. Only the first byte of Operand 1 is affected by the move.
As an example, consider the following code,
MVI FIELDA,X’C1’
...
FIELDA DC X’123456’
After execution, FIELDA contains X’C13456’. Only the first byte of the field is altered by the immediate instruction.
The following example illustrates how an MVI instruction might be processed by the assembler.
LOC OBJECT CODE
000F12 92F4C044 MVI CUSTCODE,C’4’
...
001028 CUSTCODE DS CL1
In the example above, the op-code for MVI is x’92’, the self-defining term C’4’ is assembled as the one byte hexadecimal constant
x’F4’, and CUSTCODE is translated into the base/displacement address C044.
MVN perfoms in a way that is analagous to MVC. While MVC works on entires bytes, MVN only processes the numeric parts
(rightmost 4 bits) of the bytes it references. The purpose of a move numeric instruction is to move the numeric parts of a
consecutive collection of bytes from one location in memory to another location. As you can see from the instruction format above,
the instruction carries with it the number of bytes to be copied (LL1 ), as well as the beginning addresses of the source
(B2 D 2 D 2 D 2 ) and target (B1 D 1 D 1 D 1 ) fields. Notice that the instruction does not specifiy the ending addresses of either field - the
instruction is no respecter of fields. MVN copies the numeric parts of LL 1 + 1 consecutive bytes from the storage location
designated by B2 D 2 D 2 D 2 to the storage location designated by B1 D 1 D 1 D 1 .
The length (LL1 ) determines the number of “half-bytes” which will be copied. The length is usually determined implicitly from the
length of operand 1 but the programmer can provide an explicit length. Consider the two example MVN’s below,
Object code Assembler code
FIELDA DS CL8
FIELDB DS CL5
...
D107C008C010 MVN FIELDA,FIELDB Implicit length
D102C008C010 MVN FIELDA(3),FIELDB Explicit length
In the first example, the length implicitly defaults to 8, the length of FIELDA. In the second example, the length is explicitly 3.
Notice that the assembled length (LL1 ) is one less than the implicit or explicit length. This can be seen in the object code above
where the assembled lengths are x’07’ and x’02’.
The copying operation is usually straightforward, but can be more complicated by overlapping the source and target fields. Keep
in mind that the copy is made one byte at a time. Consider the following examples,
Object code Assembler code
ONE DC C’1’ ONE = X’F1’
FIELDA DC CL3’ABC’ FIELDA = X’C1C2C3’
FIELDB DC XL3’123456’ FIELDB = X’123456’
...
D102C008C00B MVN FIELDA,FIELDB After FIELDA = X’C2C4C6’
D102C00EC008 MVN FIELDB,FIELDA After FIELDB = X’113253’
D102C008C007 MVN FIELDA,ONE After FIELDA = X’C1C1C1’
In the first MVN above, 3 consecutive numeric half-bytes in FIELDB are simply copied to the numeric portions of FIELDA. The
half-bytes are copied, one at a time moving left to right within both operands. In the second example, 3 consecutive bytes are
copied into FIELDB (implicit length = 3) from FIELDA. The third MVN is complicated by the fact that the source and target fields
overlap. We will examine the third move in some detail.
1. Pay attention to the lengths of the fields involved in any MVN statement. If the target field is longer than the source field, bytes
following the source may be transferred. If the target field is shorter than the source field, bytes in the source may may be
truncated.
MVZ perfoms in a way that is analagous to MVC. While MVC works on entires bytes, MVZ only processes the zoned parts
(leftmost 4 bits) of the bytes it references. The purpose of a move zones instruction is to move the zoned parts of a consecutive
collection of bytes from one location in memory to another location. As you can see from the instruction format above, the
instruction carries with it the number of bytes to be copied (LL1 ), as well as the beginning addresses of the source (B2 D 2 D 2 D 2 )
and target (B1 D 1 D 1 D 1 ) fields. Notice that the instruction does not specifiy the ending addresses of either field - the instruction is
no respecter of fields. MVZ copies the zoned parts of LL 1 + 1 consecutive bytes from the storage location designated by
B2 D 2 D 2 D 2 to the storage location designated by B1 D 1 D 1 D 1 .
The length (LL1 ) determines the number of “half-bytes” which will be copied. The length is usually determined implicitly from the
length of operand 1 but the programmer can provide an explicit length. Consider the two example MVZ’s below,
Object code Assembler code
FIELDA DS CL8
FIELDB DS CL5
...
D307C008C010 MVZ FIELDA,FIELDB Implicit length
D302C008C010 MVZ FIELDA(3),FIELDB Explicit length
In the first example, the length implicitly defaults to 8, the length of FIELDA. In the second example, the length is explicitly 3.
Notice that the assembled length (LL1 ) is one less than the implicit or explicit length. This can be seen in the object code above
where the assembled lengths are x’07’ and x’02’.
The copying operation is usually straightforward, but can be more complicated by overlapping the source and target fields. Keep
in mind that the copy is made one byte at a time. Consider the following examples,
Object code Assembler code
ONE DC C’1’ ONE = X’F1’
FIELDA DC CL3’ABC’ FIELDA = X’C1C2C3’
FIELDB DC XL3’123456’ FIELDB = X’123456’
...
D302C008C00B MVZ FIELDA,FIELDB After FIELDA = X’113253’
D302C00EC008 MVZ FIELDB,FIELDA After FIELDB = X’C2C4C6’
D302C008C007 MVZ FIELDA,ONE After FIELDA = X’F1F2F3’
In the first MVZ above, 3 consecutive zoned half-bytes in FIELDB are simply copied to the zoned portions of FIELDA. The half-
bytes are copied, one at a time moving left to right within both operands. In the second example, 3 consecutive bytes are copied
into FIELDB (implicit length = 3) from FIELDA. The third MVZ is complicated by the fact that the source and target fields overlap.
We will examine the third move in some detail.
1. Pay attention to the lengths of the fields involved in any MVZ statement. If the target field is longer than the source field, bytes
following the source may be transferred. If the target field is shorter than the source field, bytes in the source may may be
truncated.
The And instruction performs a logical bit by bit “and” between a register and a fullword in memory. Operand 1, the target, is a
register and Operand 2, the source, specifies a fullword in memory. The fullword in memory is anded internally with the fullword in
the register and the result is placed in the register. The fullword in memory is not changed. The table below shows the results of
“anding” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 0
1 0 0
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The And Character instruction performs a logical bit by bit “and” between two fields in memory. Operand 1, the target, is a
memory field and Operand 2, the source, also specifies a storage location in memory. The number of characters which participate
in the operation is determined by the first operand, and as a result, is limited to 256 bytes. The storage fields are “and-ed”
internally with the result placed in the target field. Typically, the source is unaffected, but can be altered by this operation if the
fields overlap. The table below shows the results of “and-ing” two bits together.
Bit 1 Bit 2 Bit 1 and Bit 2
0 0 0
0 1 0
1 0 0
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The And Immediate instruction performs a logical bit by bit “and” between a byte in memory and an immediate constant.
Operand 1, the target, is a byte in memory and Operand 2, the source, specifies the immediate constant. The byte in memory is
“and-ed” internally with the immediate constant and contains the final result. The immediate constant is not changed. The table
below shows the results of “anding” two bits together.
Bit 1 Bit 2 Bit 1 and Bit 2
0 0 0
0 1 0
1 0 0
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The And Register instruction performs a logical bit by bit “and” between two registers. Operand 1, the target, is a register and
Operand 2, the source, also specifies a register. The fullword in Operand 1 is “and-ed” internally with the fullword in Operand 2,
and the result is placed in Operand 1. The table below shows the results of “and-ing” two bits together.
Bit 1 Bit 2 Bit 1 and Bit 2
0 0 0
0 1 0
1 0 0
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Or instruction performs a logical bit by bit “or” between a register and a fullword in memory. Operand 1, the target, is a
register and Operand 2, the source, specifies a fullword in memory. The fullword in memory is or-ed internally with the fullword in
the register and the result is placed in the register. The fullword in memory is not changed. The table below shows the results of
“or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Or Character instruction performs a logical bit by bit “or” between two fields in memory. Operand 1, the target, is a memory
field and Operand 2, the source, also specifies a storage location in memory. The number of characters which participate in the
operation is determined by the first operand, and as a result, is limited to 256 bytes. The storage fields are or-ed internally with
the result placed in the target field. Typically, the source is unaffected, but can be altered by this operation if the fields overlap.
The table below shows the results of “or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Or Immediate instruction performs a logical bit by bit “or” between a byte in memory and an immediate constant. Operand 1,
the target, is a byte in memory and Operand 2, the source, specifies the immediate constant. The byte in memory is or-ed
internally with the immediate constant and contains the final result. The immediate constant is not changed. The table below
shows the results of “or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Or Register instruction performs a logical bit by bit “or” between two registers. Operand 1, the target, is a register and
Operand 2, the source, also specifies a register. The fullword in Operand 1 is or-ed internally with the fullword in Operand 2, and
the result is placed in Operand 1. The table below shows the results of “or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 1
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
PACK is a SS 2 instruction which is designed to convert data from character or zoned decimal format to packed decimal format.
The operation proceeds by transferring the contents of operand 2 to operand 1. Bytes in operand 1 and 2 are referenced from
right to left within the fields. The rightmost byte of operand 2 is referenced first, and the zone and numeric parts of the byte are
reversed and placed in the rightmost byte of operand 1. Then the numeric parts of the next two bytes of operand 2 are placed in
the next byte of operand 1. This process continues by “packing” the numeric parts of operand 2 into operand 1, always moving
from right to left, taking two bytes and packing into one byte. The example below illustrates this idea. The first field, AZONED,
contains zoned decimal data, while the second field, APK, shows the results of executing “PACK APK,AZONED”. We assume
the following definitions,
AZONED DC ZL7’7893023’
APK DS PL4
...
PACK APK,AZONED
Since PACK is SS 2 , each operand contributes a 4-bit length which is stored in the second byte of the object code as pictured at
the top of this page. The maximum length in the object code is B’1111’ = 15. Since the assembler always decrements lengths by
1, packed fields are limited to a maximum of 16 bytes. It is also important to note that the lengths of both fields are used to
execute this instruction. For instance, if APK was defined as PL3, the high-order digits in the packed field (those on the left) are
truncated.
PACK APK,AZONE
On the other hand, if there are too few bytes in operand 2, zeros will be padded on the left in operand 1 as illustrated below.
Assume APK was defined as PL6.
PACK APK,AZONED
1. PACK works with any kind of data. That does not mean that you will compute correct results. It simply means that the program
will not abend because of the data contents in a field you are packing. Packed decimal problems show up when arithmetic
instructions are executed.
The Subtract instruction performs 2’s complement binary subtraction. Operand 1 is a register containing a fullword integer.
Operand 2 specifies a fullword in memory. The fullword in memory is subtracted from the fullword in the register and the result
remains in the register. The fullword in memory is not changed. Consider the following example,
S R9,AFIELD
The contents of the fullword “AFIELD”, x’0000001F’ = 31, are subtracted from register 9 which contains x’00000031’ = 49. The
difference is 18 = x’00000012’ destroying the previous value in R9. The fullword in memory is unchanged by this operation.
Since S is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing.
SLA is used to shift the 32 bits in the register specified by Operand 1 to the left. The number of bits that are shifted is indicated
by Operand 2. The second operand address is not used to address data; instead, the base/displacement address is computed
and the rightmost 6 bits are treated as a binary integer which represents the number of bits to be shifted. We will call this value
the “shift factor”. This leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SLA R9,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 5, and so the bits in register 9 are shifted to the left by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SLL R9,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting algebraically, bits shifted out on the left are lost, while 0’s replace bits on the right. The sign bit in Operand 1
remains fixed, preserving the sign of the integer. If one or more bits unlike the sign bit are shifted out on the left, an overflow
occurs and the condition code is set to 3. This will cause a program interruption if the fixed-point overflow mask is set to 1. (See
SPM.) Otherwise the condition code can be tested using BO.
The condition code is set by this instruction in all cases:
Condition Code Meaning Test With
0 Result = 0 (No overflow) BZ, BE
1 Result < 0 (No overflow) BL, BM
2 Result > 0 (No overflow) BH, BP
3 Overflow BO
Consider the following instruction.
SLA R8,3
This instruction represents a left algebraic shift of register 8 using a shift factor of 3. The shift factor has been coded directly. As a
This instruction has an RS format but the 4 low-order bits of the second byte of the object code are unused.
1) Shifting a binary number to the left one digit is equivalent to multiplying it by 2. Using SLA, it is a simple matter to multiply by
powers of 2. For instance, to multiply by 2 5 , shift left 5 digits.
Operand 1 specifies the even register of an even-odd consecutive pair of general purpose registers. For instance R4 would
represent registers 4 and 5, while R8 would represent registers 8 and 9. SLDA is used to shift the 64 bits in the even-odd pair as
if they comprised a single register. The shift is to the left. The number of bits that are shifted is indicated by Operand 2. The
second operand address is not used to address data; instead, the base/displacement address is computed and the rightmost 6 bits
are treated as a binary integer which represents the number of bits to be shifted. We will call this value the “shift factor”. This
leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SLDA R8,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address, the rightmost 6 bits
still represent the number 5, and so the bits in registers 8 and 9 are shifted to the left by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SLDA R8,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting algebraically, bits shifted out on the left are lost, while 0’s replace bits on the right. The sign bit in Operand 1
remains fixed, preserving the sign of the integer. If one or more bits unlike the sign bit are shifted out on the left, an overflow
occurs and the condition code is set to 3. This will cause a program interruption if the fixed-point overflow mask is set to 1. (See
SPM.) Otherwise the condition code can be tested using BO.
The condition code is set by this instruction in all cases:
Condition Code Meaning Test With
0 Result = 0 (No overflow) BZ, BE
1 Result < 0 (No overflow) BL, BM
2 Result > 0 (No overflow) BH, BP
3 Overflow BO
Consider the following instruction.
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
1) Shifting a binary number to the left one digit is equivalent to multiplying it by 2. Using SLDA, it is a simple matter to multiply by
powers of 2. For instance, to multiply by 2 5 , shift left 5 digits.
Operand 1 specifies the even register of an even-odd consecutive pair of general purpose registers. For instance R4 would
represent registers 4 and 5, while R8 would represent registers 8 and 9. SLDL is used to shift the 64 bits in the even-odd pair as if
they comprised a single register. The shift is to the left. The number of bits that are shifted is indicated by Operand 2. The
second operand address is not used to address data; instead, the base/displacement address is computed and the rightmost 6 bits
are treated as a binary integer which represents the number of bits to be shifted. We will call this value the “shift factor”. This
leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SLDL R8,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 5, and so the bits in registers 8 and 9 are shifted to the left by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SLDL R8,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting logically, bits shifted out on the left are lost, while 0’s replace bits on the right.
Consider the following instruction.
SLDL R8,6
This instruction represents a left shift of registers 8 and 9 using a shift factor of 6. The shift factor has been coded directly. As a
result, 6 bits, 111100, are shifted out of the register on the left. Vacated bit positions on the right are replace by 0’s. This is
illustrated in the diagram below.
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
SLL is used to shift the 32 bits in the register specified by Operand 1 to the left. The number of bits that are shifted is indicated
by Operand 2. The second operand address is not used to address data; instead, the base/displacement address is computed
and the rightmost 6 bits are treated as a binary integer which represents the number of bits to be shifted. We will call this value
the “shift factor”. This leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SLL R9,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 5, and so the bits in register 9 are shifted to the left by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SLL R9,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting logically, bits shifted out on the left are lost, while 0’s replace bits on the right.
Consider the following instruction.
SLL R8,6
This instruction represents a left shift of register 8 using a shift factor of 6. The shift factor has been coded directly. As a result, 6
bits, 111100, are shifted out of the register on the left. Vacated bit positions on the right are replace by 0’s. This is illustrated in
the diagram below.
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
SRA is used to shift the 32 bits in the register specified by Operand 1 to the right. The number of bits that are shifted is
indicated by Operand 2. The second operand address is not used to address data; instead, the base/displacement address is
computed and the rightmost 6 bits are treated as a binary integer which represents the number of bits to be shifted. We will call
this value the “shift factor”. This leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SRA R9,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 5, and so the bits in register 9 are shifted to the right by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SRA R9,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting algebraically, bits shifted out on the right are lost, while bits equal to the sign bit replace vacated bits on the left.
The sign bit in Operand 1 remains fixed, preserving the sign of the integer.
The condition code is set by this instruction in all cases:
Condition Code Meaning Test With
0 Result = 0 BZ, BE
1 Result < 0 BL, BM
2 Result > 0 BH, BP
Consider the following instruction and the diagram below.
SRA R8,3
This instruction represents a right algebraic shift of register 8 using a shift factor of 3. The shift factor has been coded directly. As
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
1) Shifting a binary number to the right one digit is equivalent to dividing it by 2 (using integer arithmetic). Using SRA, it is a
simple matter to divide by powers of 2. For instance, to divide by 2 5 , shift right 5 digits.
Operand 1 specifies the even register of an even-odd consecutive pair of general purpose registers. For instance R4 would
represent registers 4 and 5, while R8 would represent registers 8 and 9. SRDA is used to shift the 64 bits in the even-odd pair as
if they comprised a single register. The shift is to the right. The number of bits that are shifted is indicated by Operand 2. The
second operand address is not used to address data; instead, the base/displacement address is computed and the rightmost 6 bits
are treated as a binary integer which represents the number of bits to be shifted. We will call this value the “shift factor”. This
leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SRDA R8,5
In the above shift, the second operand, 5, is treated as a base/displacement address where 5 is the displacement and the base
register is omitted. The effective address is 5. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 5, and so the bits in registers 8 and 9 are shifted to the right by 5 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SRDA R8,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting algebraically, bits shifted out on the right are lost, while bits equal to the sign bit replace vacated bits on the left.
The sign bit in Operand 1 remains fixed, preserving the sign of the integer.
The condition code is set by this instruction in all cases:
Condition Code Meaning Test With
0 Result = 0 BZ, BE
1 Result < 0 BL, BM
2 Result > 0 BH, BP
Consider the following instruction.
SRDA R8,3
This instruction represents a right algebraic shift of registers 8 and 9 using a shift factor of 3. The shift factor has been coded
directly. As a result, 3 bits, 000, are shifted out of the register on the right. Vacated bit positions on the left are replace by 1’s (the
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
1) SRDA is a helpful instruction to use when dividing binary numbers. Remember that the divide instruction requires that the
even-odd pair or registers be initialized with the dividend. In other words, the even-odd pair contains a 64-bit 2’s complement
integer. One way to initialize the pair is to load the even register with a fullword that represents the dividend, and then shift it
using SRDA to the odd register. This operation propagates the sign bit throughout the even register. For example, to divide the
fullword X by the fullword Y, the following code could be used.
L R4,X PUT DIVIDEND IN THE EVEN REGISTER
SRDA R4,32 SHIFT DIVIDEND TO THE ODD REGISTER
D R4,Y READY TO DIVIDE
Operand 1 specifies the even register of an even-odd consecutive pair of general purpose registers. For instance, R4 would
represent registers 4 and 5, while R8 would represent registers 8 and 9. SRDL is used to shift the 64 bits in the even-odd pair as
if they comprised a single register. The shift is to the right. The number of bits that are shifted is indicated by Operand 2. The
second operand address is not used to address data; instead, the base/displacement address is computed and the rightmost 6 bits
are treated as a binary integer which represents the number of bits to be shifted. We will call this value the “shift factor”. This
leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SRDL R8,8
In the above shift, the second operand, 8, is treated as a base/displacement address where 8 is the displacement and the base
register is omitted. The effective address is 8. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 8, and so the bits in registers 8 and 9 are shifted to the right by 8 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SRDL R6,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting logically, bits shifted out on the right are lost, while 0’s replace bits on the left.
Consider the following instruction.
SRDL R8,6
This instruction represents a right shift of registers 8 and 9 using a shift factor of 6. The shift factor has been coded directly. As a
result, 6 bits, 110000, are shifted out of the register on the right. Vacated bit positions on the left are replaced by 0’s. This is
illustrated in the diagram
below.
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
SRL is used to shift the 32 bits in the register specified by Operand 1 to the right. The number of bits that are shifted is
indicated by Operand 2. The second operand address is not used to address data; instead, the base/displacement address is
computed and the rightmost 6 bits are treated as a binary integer which represents the number of bits to be shifted. We will call
this value the “shift factor”. This leads to two distinct ways of coding the shift factor:
1) Directly - The shift factor is coded as a displacement. Consider the example below.
SRL R9,8
In the above shift, the second operand, 8, is treated as a base/displacement address where 8 is the displacement and the base
register is omitted. The effective address is 8. (See Explicit Addressing.) When represented as an address the rightmost 6 bits
still represent the number 8, and so the bits in register 9 are shifted to the right by 8 bits.
2) Indirectly - The shift factor is placed in a register and the register is mentioned as the base register in the
base/displacement address.
L R5,FACTOR PUT SHIFT FACTOR IN REG
SRL R9,0(R5) NOW SHIFT INDIRECTLY
...
FACTOR DC F’8’ SHIFT FACTOR IS 8 BITS
In this case, the effective address is computed by adding the contents of base register 5 (which is 8), with the displacement of 0.
The effective address is again 8, and the rightmost 6 bits of this address indicate that the shift factor is 8.
Each method has its uses. The direct method is useful in situations where the number of bits you want to shift is fixed. Coding
directly allows you to look at the instruction to determine the shift factor. On the other hand, the indirect method allows the shift
factor to be determined while the program is executing. If the shift factor cannot be determined until the program is running, the
indirect method must be used.
When shifting logically, bits shifted out on the right are lost, while 0’s replace bits on the left.
Consider the following instruction.
SRL R8,6
This instruction represents a right shift of register 8 using a shift factor of 6. The shift factor has been coded directly. As a result,
6 bits, 110000, are shifted out of the register on the right. Vacated bit positions on the left are replace by 0’s. This is illustrated in
the diagram below.
This instruction has an RS format but the 4 low-order bits of the second byte are unused.
SRP is a SS 1 instruction designed to shift the digits in a packed decimal field either left or right while leaving the sign of the field
fixed in its position. For right shifts, the last digit that is shifted off can be rounded using a rounding factor. As digits are shifted off
during a left shift, 0’s are shifted in on the right. On the other hand, as digits are shifted off during a right shift, 0’s are shifted in
on the left.
Consider the explicit format for this instruction.
As we can see from the diagram, operand 1 specifies the field to be shifted and its length, while the third operand is a rounding
factor. This factor is added to the last digit which is shifted off during right shifts. Typically, you would code the third operand as 5
in order to round up on a digit of 5 or greater. Coding 0 as the third operand indicates no rounding. A rounding factor must
always be coded, even when shifting left.
The second operand above receives special treatment. The notation D2(B2) is converted to an effective address and the last 6
bits of this address is treated as a two’s complement number that indicates the number of digits to be shifted and in which
direction. A positive number indicates a left shift and a negative number indicates a right shift. Because of the explicit notation,
there are two standard ways to code the second operand.
1) Displacement Only -
SRP XPK,3,0
In this case the shift factor, 3, is converted to 6-bit binary (B’000011’) and the result is interpreted as 6-bit 2’s complement. In this
format B’000011’ is considered to be positive 3 - a left shift by 3.
On the other hand consider the following example,
SRP XPK,62,5
The 62 is converted to its binary form (B’111110’) and interpreted as a 6-bit 2’s complement integer. We see that B’111110’ = -
2 in base 10. This means the previous shift is a 2-digit right shift.
There is a simple way to deal with the shift factor on right shifts. Simply express the shift factor as 64 - n, where n is the
number of digits you wish to shift to the right. For example, the previous example could be expressed as SRP XPK,64-2,5 .
1. Keep in mind that you cannot left shift off a significant digit.
2. Be sure to use the 64-n notation when coding right shifts. It is easy to read, and provides excellent documentation.
ST is used to copy the fullword stored in the register specified by operand 1 into the fullword memory location specified by
operand 2. Consider the following example,
ST R9,AFIELD
In this case, the contents of register 9 are copied to the fullword in memory denoted by AFIELD. This operation destroys the
previous contents of AFIELD but leaves R9 unchanged.
Since ST is an RX instruction, an index register may be coded as part of operand 2. Notice that in the previous example, no
index register was specified. When the index register is omitted, the assembler chooses R0, which does not contribute to the
address. The following example illustrates this idea.
ST R9,AFIELD(R5)
The assembler converts AFIELD to a base register and displacement, while R5 is the index register. For instance, the
expression AFIELD(R5) might (we can not determine the base register) be equivalent to the explicit address 0( R5,R3 ) -
displacement = 0, index register = R5, base register = R3 (see Explicit Addressing). The effective address is computed by
adding the base register contents to the index register contents plus the displacement. If the index register contains an “8”, then
AFIELD(R5) refers to the fullword that begins at an 8 byte displacement from the beginning byte of AFIELD. The following
examples illustrate several explicit addresses that include an index register.
In the first explicit address, 4( R4, R3), the effective address is computed by adding the contents of base register 5, the contents
of index register 3, and the displacement ( 1000 + 4 + 4 = 1008 ). The second address 0( R5, R3) is computed as 1000 + 8 + 0 =
1008, and the third address, 4( R5, R3 ) is computed to be 1000 + 8 + 4 = 100C (hexadecimal).
If an index register is not explicitly coded, as in the instruction “ST R9,AFIELD”, the assembler chooses R0 as the index
register, which does not contribute to the effective address.
1) Operand 2 should denote a fullword in memory. It is possible to store the contents of a register into 4 bytes of memory that are
not aligned on a fullword, but the assembler will warn you that operand 2 is not properly aligned. If the field involved cannot be
aligned conveniently, consider using STCM to copy the contents of a register into memory.
STC is used to copy the rightmost byte of a register into main storage. The register is represented by operand 1, and the main
storage area is designated by operand 2. Since STC is an RX instruction, the storage area can be designated by using an index
register.
The STC instruction above takes the rightmost byte of register 8 and copies it into the first byte of FIELDA, a field in main
storage. One advantage to STC is the ability to use an index register to move a single byte from a register to memory. STC and
IC are the only byte-oriented RX instructions. In the following example we assume that register 5 contains x’000000C1’ and that
register 7 contains x’00000003’.
STC R5,FIELDA(R7)
The instruction above would store the character “A” (x’C1’) into the fourth byte of FIELDA.
For the following examples, assume that R8 contains x’11223344’ and that R4 contains x’00000002’
FIELDA DC X’AABBCCDD’
1. Remember that STC is a byte oriented instruction that only copies the rightmost byte of a register. The companion to STC is IC
(Insert Character).
The STH instruction has two operands: the first operand is a general purpose register, and the second operand is a halfword
storage area in memory. The effect of the instruction is to copy the contents of bits 16-31 of the Operand 1 register (the rightmost
two bytes) into the halfword specified by Operand 2. The condition code is unaffected by this instruction. Consider the following
example.
STH R9,AFIELD
The rightmost two bytes of register 9 are copied to the halfword AFIELD, destroying the previous contents. The register value is
unchanged by this operation.
Since STH is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
STM is used to copy a “consecutive” collection of registers into consecutive fullwords in main storage. The collection of registers
which is copied is specified by coding the beginning and ending registers as the first two operands. For instance,
STM R5,R8,XWORDS
would be used to copy registers 5, 6, 7, and 8. If the second operand specifies a lower register than the first operand, then a
“wrap-around” occurs. For instance,
STM R14,R12,12(R13)
would be used to copy registers 14, 15, 0, 1, ..., 12 - every register except 13.
The registers are stored starting in the fullword address specified in the third operand. In the first example above, register 5
would be stored at XWORDS, register 6 at XWORDS+4, register 7 at XWORDS+8, and register 8 at XWORDS+12. In the second
example, register 14 is stored at an explicit address - a 12 byte displacement off register 13. The other registers are consecutively
stored.
Here is an example.
STM R7,R9,REGWORDS
In the example above, the consecutive range of registers ( 7, 8, and 9 ) are stored in consecutive fullwords in memory starting in
the fullword specified as REGWORDS.
1) This statement is helpful for creating subroutines. Branch to a subroutine and immediately save the registers with STM. This
allows your subroutine to freely use the registers. Before exiting your subroutine, restore the registers with LM. Create a register
“save area” for each subroutine.
BAS R6,SUBRTN CALL THE SUBROUTINE
...
SUBRTN EQU *
STM R14,R12,SUBSAVE SAVE THE REGISTERS
... (SUBROUTINE CODE)
LM R14,R12,SUBSAVE RESTORE THE REGISTERS
BR R6 BRANCH BACK TO CALLER
SUBSAVE DS 15F FIFTEEN FULLWORDS FOR THE REGISTERS
2) Read about the role that STM plays in implementing the “linkage conventions” in Program Linkage .
The Subtract Halfword instruction performs 2’s complement binary subtraction. Operand 1 is a register containing a fullword
integer. Operand 2 specifies a halfword in memory. The halfword in memory is sign extended (internally) and subtracted from the
fullword in the register. The result remains in the register. The halfword in memory is not changed. Consider the following
example,
SH R9,AFIELD
The contents of the halfword “AFIELD”, x’007F’ = 127, are subtracted from register 9 which contains x’000003FA’ = 1018. The
difference, 891 = x’0000037B’, destroys the previous value in R9. The halfword in memory is unchanged by this operation.
Since SH is an RX instruction, an index register may be coded as part of operand 2 (see Explicit Addressing).
A common error is to code a SH when the second operand is not a halfword. For example:
AMOUNT DC F’20’ AMOUNT = X’00000014’
...
SH R5,AMOUNT
The assembler will not complain about your code, but the halfword instruction will only access the first two bytes of the AMOUNT
field (x’0000’).
SP is a SS 2 instruction which is used to subtract packed decimal fields. Operand 1 is a field in storage which should contain a
packed decimal number. The resulting sum develops in this field. The contents of Operand 2, another packed decimal field in
storage, is subtracted from the contents of Operand 1 to produce the result which is stored in Operand 1. The operands are
limited to a maximum length of 16 bytes and may have different sizes since this is a SS 2 instruction.
A decimal overflow (condition code = 3) will occur if the generated result loses a significant digit when it is placed in the target
field. A decimal overflow may or may not cause a program interruption (abend). This depends on the setting of a bit in the PSW
(See SPM). Otherwise, the condition code is set to indicate whether the result was zero (condition code = 0), negative (condition
code = 1), or positive (condition code = 2). You can test these conditions with BZ or BNZ, BM or BNM, and BP or BNP.
Consider the following SP example.
SP APK,BPK
BM ANEGATIV
Assume the variables are initially in the following states,
APK DC PL4’34’ = X’0000034C’
BPK DC PL3’22’ = X’00022C’
After the SP instruction has executed, the variables have the following values.
APK = X’0000012C’
BPK = X’00022C’
The contents of BPK was subtracted from APK and the result stored in APK. BPK was unaffected by the subtract operation. The
branch is not taken since the condition code is positive.
On the other hand, consider the following example,
SP APK,BPK
...
APK DC PL2’999’ = X’999C’
BPK DC PL2’-5’ = X’005D’
After the SP instruction has executed, the variables have the following values.
APK = X’004C’
BPK = X’005D’
Notice that an overflow occurred in APK with the loss of a significant digit. APK was too small to hold the difference that
developed as a result of the SP.
1. You must be familiar with your data. The best way to prevent overflows is to plan the size of your fields based on the data at
hand. There is a rule of thumb that you can follow for subtractions: If you are subtracting two packed fields with m and n bytes,
then the difference might be as large as max(m, n) + 1 bytes. You may need to construct a work area to handle the maximum
values. For instance,
FIELDA DS PL3
FIELDB DS PL5
WORK DS PL6
In planning to subtract FIELDB from FIELDA, we construct a work field called “WORK”. The following code completes the task.
ZAP WORK,FIELDA
SP WORK,FIELDB
The Subtract Register instruction performs 2’s complement binary subtraction. Operand 1 is a register containing a fullword
integer. Operand 2 specifies a register as well. The fullword in Operand 2 is subtracted from the fullword in Operand 1, and the
difference replaces the contents of Operand 1. Operand 2 in unchanged by this operation except when Operand 1 and 2 refer to
the same register. Consider the following example,
SR R9,R8
The contents of the fullword in register 8, x’00000479’, are subtracted from the contents of register 9 which contains x’000003FA’
. The difference is x’00000181’ and replaces the previous value in R9. The contents of register 8 are unchanged by this
operation.
The condition code is set by this instruction to zero if the result is zero, minus if the result is negative, and plus if the result is
positive.
Test Under Mask is used to examine the bits of a single byte in memory and set the condition code based on the contents of the
selected bytes. Operand 1 is the address of the byte in memory that is to be examined. Operand 2 is an immediate constant
which is treated as an 8-bit binary mask (pattern). The bits in the mask correspond one for one with the bits in the Operand 1
byte. A mask bit of 1 indicates that we are interested in testing the corresponding bit in memory and we will call this bit a
“selected” bit. A mask bit of 0 indicates that we are not interested in testing the corresponding bit in memory. The condition code
is set based on the contents of the selected bits.
This instruction sets the condition code as follows:
Condition Code Meaning Test With
0 All selected bits are set to 0, BZ or BNZ. (Zeros, Not Zeros)
or all mask bits were 0
1 Selected bits mixed (0’s and 1’s) BM or BNM ( Mixed, Not Mixed)
)
3 Selected bits were all 1’s BO BNO (Ones, Not Ones)
Consider the following example.
TM AFIELD,B’11110000’
BO ALLONES
BM MIXED
...
AFIELD DC C’A’ AFIELD = B’11000001’
The immediate constant in the TM instruction is coded as B’11110000’, indicating that we are interested in testing the first four bits
in AFIELD, and that we are not interested in the last four bits. Since AFIELD contains a character “A” which is equivalent to a
binary 11000001, the condition code is set to 1 indicating that some of the bits we selected are 1’s and some are 0’s. As a result,
a branch will occur to MIXED when we execute the BO instruction.
Since the TM instruction works at the bit level, it makes sense to code the immediate constant in a binary format, although any
format may be used. For example, the following instruction is equivalent to the TM in the example above.
TM AFIELD,X’F0’
1) Make your code easier to read by representing the immediate constant in a binary form.
TR is used to translate one string of characters to another string of characters based on a translate table which defines the
substitutions which should occur. For instance, TR could be used to convert a string of characters from lower case to upper case,
or from ASCII to EBCDIC.
Operand 1 designates a string contain in memory which is to be translated. Operand 2 designates the translate table. This
table is also called a “table of functions”. TR translates one byte at a time, starting with the leftmost byte of Operand 1, proceding
from left to right. Each byte that is translated is used as a displacement into the table. The “function byte” that is found in the table
is substituted for the byte in Operand 1. Since a byte can contain any value from X’00’ to X’FF’, the table of functions is usually
256 bytes long to accommodate the range of addresses from table + X’00’ to table + X’FF’.
Let us consider how a particular byte is translated using a table of functions called “TABLE”. For example, how would a byte
containing X’A2’ be translated? Since X’A2’ = 162 in base 10, X’A2’ would be replaced by the byte at address “TABLE+162”. In
other words, the byte we are translating acts as a displacement into the table, and is replace by the table byte in that position.
Consider the following example. To keep things simple, we begin with a small ( 5 bytes ) table and assume that the bytes in the
string which is being translated generate displacements that stay inside the table. ( For safety, most TR tables are 256 bytes in
length. ) We assume the following definitions.
STRING DC X’030201’
TABLE DC X’FF01AABB00’
We issue the following command.
TR STRING,TABLE
The execution of this instruction is graphically illustrated on the next page. Let us consider a byte by byte description of the
execution of TR. The first byte of STRING, X’03’, is used as a displacement into TABLE. The byte at address TABLE+3,
which is X’BB’, replaces the first byte in STRING. This means the string temporarily looks like X’BB0200’. Next, the second byte
of STRING, X’02’, is used as a displacement into the table. As a result the byte at TABLE+2, which is X’AA’, replaces X’02’ in
STRING. Finally, the third byte in STRING, X’01’, is used as a displacement into the table and the byte at TABLE+1, X’01’,
replaces X’01’ in STRING. After the TR has executed, STRING contains X’BBAA01’.
To be safe when using TR you should always code a translate table that is 256 bytes long so that you can handle any possible
displacement that might be used in the translation. The only exception to this rule occurs when you are sure that the bytes you are
translating fall within a specified range.
How could you define a translate table that translates every character to itself? Since each character would be used as a
displacement to itself, a translate table of this type would look like X’000102030405060708090A0B0C0D0E0F10...’. There is an
easy way to construct such a table: TABLE DC 256AL1(*-TABLE)
This technique works by defining 256 byte address constants of length 1. When defining the first byte in the table the asterisk
refers to the same address as TABLE, and so *-TABLE is 0. After defining the first byte the location counter advances and *-
TABLE is 1 when defining the second byte. Continuing in this fashion, the expression “*-TABLE” takes on all the values from 0 to
256. As a result, we create a table that translates every character to itself. This is important because in many applications, most of
the characters we encounter are left unchanged by TR.
For example, suppose we want to translate lower case letters to upper case. To do this we use the following table definition.
TABLE DC 256AL1(*-TABLE)
ORG TABLE+C’a’
DC C’ABCDEFGHI’
ORG TABLE+C’j’
DC C’JKLMNOPQR’
ORG TABLE+C’s’
DC C’STUVWXYZ’
ORG
Notice that most bytes translate to themselves. An originate directive is used to position to the table position that contains a lower
case “a”. This is followed by a DC that defines the upper case letters A - I. This technique is repeated for “j” and “s”. Since the
lower case letters occur in 3 blocks ( A - I, J - R, and S - Z ) the DC’s above provide for the conversion from lower to upper case.
1. Start with a table that translates each byte to itself ( TABLE DC 256AL1(*-TABLE) ). Use “ORG” to position yourself to an
appropriate character ( ORG TABLE+C’X’ positions you at ‘X’.) Redefine the area with a ‘DC’.
2. Avoid translation errors by defining all translate tables with 256 bytes.
TRT is used to scan a string of characters, searching for the occurrence of any the characters which are specified in a translate
table. The translate table is usually 256 bytes in length - one for each possible EBCDIC character that might be encountered
during the search. Unlike TR which provides automatic translation of character strings, TRT sets up the conditions for a translate
to occur, but leaves the programmer with the task of making the translation. In many cases, TRT is used for scanning strings with
no intention of making a translation.
Operand 1 designates a string contained in memory which is to be scanned and possibly translated. Operand 2 designates the
translate table. This table is also called a “table of functions”. TRT scans one byte at a time, starting with the leftmost byte of
Operand 1, proceding from left to right. Each “string byte” that is scanned is used as a displacement into the table. The byte in the
translate table at the given offset is called the “function byte”. If the function byte is X’00’, the scanning process continues with the
next byte in Operand 1. In other words, a X’00’ in a function byte indicates that we are not interested in finding the string byte that
was used as a displacement. On the other hand, if the function byte is not X’00’, then TRT modifies register 1 to contain the
address of the current string byte and also modifies register 2 to contain the corresponding function byte in bits 24 - 31 (the
rightmost byte of the register). The TRT operation is terminated when a nonzero function byte is encountered. At this point the
programmer is free to make the translation using registers 1 and 2.
Since a string byte can contain any value from X’00’ to X’FF’, the table of functions is usually 256 bytes long to accommodate the
range of addresses from table + X’00’ to table + X’FF’. Let us consider how a particular string byte is processed using a table of
functions called “TABLE”. For example, how would a byte containing X’A2’ be processed? Since X’A2’ = 162 in base 10, the
function byte at address “TABLE+162” would be examined. If the function byte were X’00’, execution would continue with the next
string byte (moving from left to right within the string). If the function byte contained something different from X’00’, then register 1
would contain the address of the current string byte and register 2 would contain the corresponding function byte.
TRT also sets the condition code to indicate the results of the scanning operation as follows:
Condition Code Indications
0 ( Zero ) All function bytes encountered were X’00’.
1 ( Minus ) A nonzero function byte was found before the end of operand 1
2 ( Positive ) A nonzero function byte was found at the end of the operand 1
The condition code can be tested using BZ, BNZ, BM, BNM, BP, or BNP.
Consider the following example. To keep things simple, we begin with a small ( 5 bytes ) table and assume that the bytes in the
string which is being scanned generate displacements that stay inside the table. We assume the following definitions.
STRING DC X’04010303’
TABLE DC X’0000FFFF00’
Notice that the table indicates that we are interested in finding a string byte that contains X’02’ or X’03’. Those bytes contain
X’FF’. We are not interested in scanning for X’00’, X’01’, or X’04’ since those table bytes contain X’00’.
We issue the following command.
TR STRING,TABLE
The previous diagram indicates the result of the TRT. First the string byte X’04’ is used as a displacement into the table of
functions. The function byte in this position is X’00’. As a result, execution continues with the next string byte. Using X’01’ as a
displacement we find the function byte X’00’. Execution continues with the next string byte. Finally, X’03’ is used as a
displacement into the table of functions and we find a nonzero function byte X’FF’. Execution of TRT terminates at this point with
the condition code set to “Minus” to indicate that a nonzero function byte was found before the end of the string.
When defining a TRT table we are usually interested in finding only a few selected characters. This means we can begin
defining a TRT table by starting with a table of all zeros and use a collection of ORG’s to redefine the pertinent characters. The
following example shows how to
code a table to scan for a dollar sign or a question mark.
TABLE DC 256AL1(0)
ORG TABLE+C’$’ Scan for a dollar sign
DC X’FF’
ORG TABLE+C’?’ Scan for a question mark
DC X’FF’
ORG
1. TRT can be used to test a field for numeric data (X’F0’ - X’F9’) by using the following table.
TABLE DC 256X’FF’
ORG TABLE+X’F0’
DC 10X’00’ 10 DIGITS OCCUR IN ORDER
ORG
Suppose we want to test a field called “FIELD” to see if it is numeric in the sense described above. This can be accomplished as
follows.
TRT FIELD,TABLE
BZ ALLNUMS
If all the bytes in “FIELD” are numeric, they will be translated to table bytes that contain zeros and the condition code is set to
zero. If a nonzero byte is found, the condition code is either minus or positive and the branch is not taken.
This technique can be used to verify that a field contains only characters from a given subset.
UNPK is a SS 2 instruction which is designed to convert data from a packed format to a zoned decimal format. The operation
proceeds by transferring the contents of operand 2 to operand 1. Bytes in Operand 1 and 2 are referenced from right to left within
the fields. The rightmost byte of operand 2 is referenced first, and the zone and numeric parts of the byte are reversed and placed
in the rightmost byte of operand 1. The next byte (moving right to left) in Operand 1 is processed by taking it numeric part,
prefixing it with bits 1111, and storing it in the next byte (moving right to left) of Operand 1. Similarly the zone portion of the byte
is prefixed with bits 1111 and stored in the “next” byte of Operand 1. This process of splitting the zone and numeric portions of a
byte and prefixing them with bits 1111 continues with all subsequent bytes in Operand 2. The process is terminated (with possible
truncation) if Operand 1 becomes filled. Keep in mind that the lengths of both operands are provided in the instruction since it has
an SS 2 format. If all the bytes in Operand 2 are processed and there are bytes remaining in Operand 1, the bytes are filled with
X’F0’s. If Operand 1 is filled before processing all the bytes in Operand 2, high-order truncation of the value in Operand 1 will
occur.
The example below illustrates this idea. The first field, APK, contains packed decimal data, while the second field, AZONED, shows
the results of executing the code below.
UNPK AZONED,APK
We assume the following definitions,
APK DC PL4’7893023’
AZONED DS ZL7
Since UNPK is SS 2 , each operand contributes a 4-bit length which is stored in the second byte of the object code as pictured at
the top of this page. The maximum length in the object code is B’1111’ = 15. Since the assembler always decrements lengths by
1, packed fields are limited to a maximum of 16 bytes. It is also important to note that the lengths of both fields are used to
execute this instruction. For instance, if AZONED were defined as ZL3, the high-order digits in the packed field (those on the left)
are truncated in the result. Consider execution of the the following instruction.
UNPK AZONED,APK
We assume the following definitions,
APK DC PL6’7893023’
AZONED DS ZL4
The rightmost bytes of APK are processed and placed in AZONED. When this field is full, the remaining bytes in APK are
truncated.
On the other hand, if there are too few bytes in operand 2, zeros will be padded on the left in operand 1 as illustrated below.
Assume the following declarations,
APK DC P’ ’
AZONED DS ZL6
Suppose we execute the following instruction.
UNPK AZONED,APK
All the bytes of APK are processed and fill up five of the bytes in AZONED. Since AZONED was defined as a seven byte field, the
leftmost 2 bytes are padded with X’F0’s.
1. UNPK will operate on any kind of data. That does not mean that you will like the results. It simply means that the program will
not abend because of the data contents in a field you unpacking.
2. Use ED or EDMK to convert data to a printable format. UNPK leaves packed data in a format that is not acceptable for
printing. For example, consider unpacking XPK into XZONE.
XPK DC P’15’ XPK = X’015C’
XZONE DS ZL3
After executing “UNPK XZONE, XPK”, XZONE contains X’F0F1C5’. When printed the field would appear as 01E, since X’C5’ is
The Exclusive Or instruction performs a logical bit by bit “exclusive or” between a register and a fullword in memory. Operand 1,
the target, is a register and Operand 2, the source, specifies a fullword in memory. The fullword in memory is exclusive or-ed
internally with the fullword in the register and the result is placed in the register. The fullword in memory is not changed. The
table below shows the results of “exclusive or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 0
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Exclusive Or Character instruction performs a logical bit by bit “exclusive or” between two fields in memory. Operand 1, the
target, is a memory field and Operand 2, the source, also specifies a storage location in memory. The number of characters which
participate in the operation is determined by the first operand, and as a result, is limited to 256 bytes. The storage fields are
exclusive or-ed internally with the result placed in the target field. Typically, the source is unaffected, but can be altered by this
operation if the fields overlap. The table below shows the results of “exclusive or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 0
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The XC instruction is occasionally used to clear a character field by exclusive or-ing it with itself:
XC FIELDA,FIELDA
The result is a field that contains binary 0’s. If the field is printed, it will appear as sequence of blanks since binary 0’s are
unprintable. While this technique may work for reports, keep in mind that binary 0’s are not blanks. If you need blanks, the
following code might be used:
MVI FIELDA,C’ ’ MOVE THE 1ST BLANK
MVI FIELDA+1(L’FIELDA-1),FIELDA MOVE THE OTHER BLANKS
The Exclusive Or Immediate instruction performs a logical bit by bit “exclusive or” between a byte in memory and an immediate
constant. Operand 1, the target, is a byte in memory and Operand 2, the source, specifies the immediate constant. The byte in
memory is exclusive or-ed internally with the immediate constant and contains the final result. The immediate constant is not
changed. The table below shows the results of “exclusive or-ing” two bits together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 0
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.
The Exclusive Or Register instruction performs a logical bit by bit “exclusive or” between two registers. Operand 1, the target, is
a register and Operand 2, the source, also specifies a register. The fullword in Operand 1 is exclusive or-ed internally with the
fullword in Operand 2, and the result is placed in Operand 1. The table below shows the results of “exclusive or-ing” two bits
together.
Bit 1 Bit 2 Result
0 0 0
0 1 1
1 0 1
1 1 0
This instruction sets the condition code as follows:
0 if all target bits are set to 0. Test this condition with BZ or BNZ.
1 if any target bit is set to 1. Test this condition with BM or BNM.