Unit 9.1 -- Base Registers
Program
Move some numbers around as indicated
PED
To learn about Base Register Usage
Concepts
Implicit address (label) --- A,B,IF001
Explicit address --- 0(0,1) 4(2,12)
Form is offset(index_#,base_#)
Limit on offset is 4096
An implicit address in an RX instruction is converted to an
explicit address
The base register used is selected from those appearing in
the second operand of the USING statement.
Offset is address of label - address of first operand of
USING statements
Where multiple base registers are provided, one is chosen so
as to ensure that offset is 4095 or less
Addressability error--no such base register found
To deal with programs more than 4096 bytes
loc1 - some address still addressable (original base
register or another address done this way)
loc2 - some address not addressable
lab1 - a label at loc1
Put at loc2
length1 equ *-lab1
In the code, we write
LA regb,lab1
A regb,=a(length1)
USING loc2,regb
SF
USING *,regA
USING label,regA
indicates that regA is assumed to contain the address of
next instruction
label
BALR regA,0
loads regA with address of next instruction. Doesn't branch
anywhere. Often used in conjunction with "USING *,regA"
LTORG
causes literals to be dumped into memory at current
location. Used to ensure that there is no addressability
error concerning the literals.
62.html
Unit 9.1 Base Registers
In the past sections, we have been including the code:
BALR 12,0
USING *,12
with little or no explanation of what these lines mean.
There was a brief mention that these two instructions
establish a "base register," that they establish
"addressability."
We will learn what these instructions do and what these
concepts mean. We will also learn that some times, we need
to have more than one base register. This occurs when we
have a lot of code or large arrays.
We will also start learning how assembly code is converted
into "machine code." This is what the computer actually
runs. The hex version of the machine code is found on the
second column in your listing. The hex numbers left of each
line of ASSEMBLER code tells you what is in the machine, and
what is actually executed.
Let's review some basic concepts about how memory is
addressed.
When we write an instruction like:
L 3,0(0,4)
L 3,BLAH
A 3,4(0,2)
A 5,ZOOEY
the second operand in all of these instructions is a memory
address. In the above cases, 0(0,4), BLAH, 4(0,2) and ZOOEY
all are ways of talking about memory.
The form "offset(X1,B1)" is known as an explicit address.
Offset is an integer from 0 to 4095. X1 and B1 are both
registers--other than zero. The address used is calculated
as follows:
The contents of register X1 and register B1 are added to
produce a temporary value. Then the integer, offset, is
added to this. This value is used as the address in memory.
(If either X1 or B1 specify the register zero, they are not
used in the address calculation.)
The addresses such as BLAH and ZOOEY are converted to the
same form by the ASSEMBLER. These are thus known as implicit
addresses, as the base register to be used is implicit. The
ASSEMBLER determines the base register to be used from the
USING instruction(s).
(X1, the index register, is never used for implicit
addresses.)
Thus, if there is only one base register, that will always
be used. That is, if there is only one USING instruction,
then all implicit addresses will use the value of the second
operand as B1.
For example, let's say there is one USING. And, let's call
its first operand, address1. E.G., we have something like
"USING address1,B1". Let's call the address of the implicit
item, the address of the second operand of the instruction,
address2. (E.G., we have something like L 3,address2.) The
offset is the value address2-address1. (If this value is
between 0 and 4095, then the second operand is
"addressable.")
If there is more than one USING, then the ASSEMBLER will
check the address associated with each register specified in
a USING. Again, call the address of the first operand in
that register, address1. Offset is again address2-address1.
If the value is between 0 and 4095, we will use that
register as the base register for this instruction. If not,
we keep on trying other registers for one where the offset
is between 0 and 4095. If none can be found, then the second
operand is not "addressable" and an error message will be
generated.
Thus, we see that when we have large arrays, or even a large
amount of code, we will have to use multiple registers.
Otherwise, some of the addresses we will be using will not
be addressable. That is, there will be no base register
that is within 4095 of them.
What happens at run time? How is the base register and
offset that the ASSEMBLER computes as described above, used?
This is where the other instruction, we kept putting in,
becomes useful. That is the BALR 12,0.
BALR Rega,0 loads register Rega with the address of the next
instruction. (This is similar to the BALR Rega,Regb or BAL
Rega,label. Both of these instructions will also load Rega
with the address of the next instruction. However, these
two branch. When we write "BALR Rega,0," the machine just
executes the next instruction. The zero is a special code
meaning don't branch, I just need the address of the next
instruction.)
For example, when we write
BALR RegA,0
USING blah,RegA
blah equ *
L 4,7
A 3,addr1
The BALR will make "RegA" contain the address of "blah" the
next instruction. The assembler will use RegA as the base
register in the "A 3,addr1" instruction. The offset chosen
will be addr1-blah. RegA will contain the address of blah.
When, the "A 3,addr1" is executed, the machine will add the
"addr1-blah" in the offset field to the "blah" contained in
RegA. This, of course, means that the "effective address"
will be "addr1-blah" + "blah." The "-blah" and "blah"
cancel leaving addr1. Recall, an address is computed by
adding the offset plus the base register. (Remember, that
the index register is always zero in implicit addresses and
that means no index-register contents are added.)
Now, that we understand what happens in the simple case of a
single base register, let's learn how to use multiple base
registers. Remember, that we have to do this when our data
or code is so big that there are more than 4096 bytes
between the address in the USING and the last item we need
to address. For each base register used, we have to have
a)a USING statement that will tell the ASSEMBLER which
base register to use (the second argument) and what
address (the first argument) to subtract before
determining the "offset" in the instructions.
b)The statement that will load the base register with the
address specified in the first argument of the USING
instruction. That way, when we add the "addr-first
argument of USING" to the base register, we get the
"addr" used in the instruction.
The first base register, we define with the
BALR RegA,0
USING blah,RegA
For each of the remaining base registers to be defined, we
need to determine two addresses in the program:
The first, loc1, will be some address that is already
addressable. (I.E., it will be a location that will be less
than 4096 bytes from some other address." Ensure, that
there is a label at this location. Call it "lab1") The
second, loc2, will be some address after loc1, that is not
addressable.
At the location, "loc2," we put the ASSEMBLER statement,
length1 equ *-lab1
Often, loc1 will be the beginning of a large array and loc2
will be just after the large array. In this case, "length1"
will simply be the length of the array.
To establish addressability for "loc2" and the next 4095
bytes, we write:
LA Regb,loc1
A Regb,=a(length1)
USING loc2,Regb
There is one little gotcha. Any literals, such as the
=a(length1), would normally come out at the end of the
program. Since these wouldn't be within the address of range
of all but the last base register, we won't be able to
address them. The solution to this is to use the "LTORG"
command within 4095 bytes of the beginning of the program.
This forces the literals to come out where the initial base
register can apply to them.
Let us look at our example. There are three large arrays,
A,B and C. Each is larger than 4095 bytes. Remember, 1024F
means 1024 fullwords at 4 bytes each for a length of 4096.
Thus, anything that appears after the definition of A won't
be addressable by the initial base register. Anything that
appears after the definition of B won't be addressable by
whatever base register we set up to handle that which is
after A. (Since, nothing appears after C, we don't have to
worry about it.) Lines 5 through 7 set up the addressability
of B and B1. Thus, in the above template, "loc1" is the
address of A, and "loc2" is the addres of B, or more
appropriately, just after A. "A" will serve as "lab1" in
the template above. "ALENGTH" will serve as the length. Note
that we let "RegA" be register 13, and we add the length of
A to it. Then B is associated with base register 13.
We do some assignments statements with B and A, just to
prove we can, in lines 9 through 11.
Next, we have to establish addressability for C, C1 and C2.
"loc1" is the address of B1. "loc2" is the address of C,
just after B1. "BLENGTH" will serve as the length. Note
that we let RegA be 11 and we add the length of B1 to it.
Then, C is associated with base register 11. After this,
line 17 and 18 does some assignment statements with C1 and
C2, just to prove we can.