Addressing Modes and Operands
Addressing Modes and Operands
Register. Most instructions operate on the registers. In general, data flows towards the
op code (right to left). In other words, the register closest to the op code gets the result
of the operation. In each of these instructions, the result goes into R2.
Register list. The stack push and stack pop instructions can operate on one register or
on a list of registers. SP is the same as R13, LR is the same as R14, and PC is the
same as R15.
Immediate addressing. With immediate addressing mode, the data itself is contained in
the instruction. Once the instruction is fetched no additional memory access cycles are
required to get the data. Notice the number 100 (0x64) is embedded in the machine
code of the instruction shown in Figure 2.14. Immediate addressing is only used to get,
load, or read data. It will never be used with an instruction that stores to memory.
Indexed addressing. With indexed addressing mode, the data is in memory and a
register will contain a pointer to the data. Once the instruction is fetched, one or more
additional memory access cycles are required to read or write the data. In these
examples, R1 points to RAM. In this class, we will focus on just the first two forms of
indexed addressing.
In Figure 2.15, R1 points to RAM, the instruction LDR R0,[R1] will read the 32-bit
value pointed to by R1 and place it in R0. R1 could be pointing to any valid object in the
memory map (i.e., RAM, ROM, or I/O), and R1 is not modified by this instruction.
Figure 2.15. An example of indexed addressing mode, data is in memory.
In Figure 2.16, R1 points to RAM, the instruction LDR R0,[R1,#4] will read the 32-bit
value pointed to by R1+4 and place it in R0. Even though the memory address is
calculated as R1+4, the Register R1 itself is not modified by this instruction.
Figure 2.16. An example of indexed addressing mode with offset, data is in memory.
The same addressing mode is used for a function call. Upon executing
the BL instruction, the return address is saved in the link register (LR). In assembly
language, we simply specify the label defining the start of the function, and the
assembler creates the appropriate PC-relative offset.
Typically, it takes two instructions to access data in RAM or I/O. The first instruction
uses PC-relative addressing to create a pointer to the object, and the second instruction
accesses the memory using the pointer. We can use the =Something operand for any
symbol defined by our program. In this case Count is the label defining a 32-bit variable
in RAM.
The operation caused by the above two LDR instructions is illustrated in Figure 2.17.
Assume a 32-bit variable Count is located in the data space at RAM address
0x2000.0000. First, LDR R1,=Count makes R1 equal to 0x2000.0000. I.e., R1 points
to Count. The assembler places a constant 0x2000.0000 in code space and translates
the =Count into the correct PC-relative access to the constant (e.g., LDR
R1,[PC,#28]). In this case, the constant 0x2000.0000, the address of Count, will be
located at PC+28. Second, the LDR R0,[R1] instruction will dereference this pointer,
bringing the 32-bit contents at location 0x2000.0000 into R0. Since Count is located at
0x2000.0000, these two instructions will read the value of the variable into R0.
Figure 2.17. Indexed addressing using R1 as a register pointer to access memory. Data
is moved into R0. Code space is where we place programs and data space is where we
place variables.
Flexible second operand <op2>. Many instructions have a flexible second operand,
shown as <op2> in the descriptions of the instruction. <op2> can be a constant or a
register with optional shift. The flexible second operand can be a constant in the
form #constant
where constant is calculated as one of these four, X and Y are hexadecimal digits:
• Constant produced by shifting an unsigned 8-bit value left by any
number of bits
• Constant of the form 0x00XY00XY
• Constant of the form 0xXY00XY00
• Constant of the form 0xXYXYXYXY
where Rm is the register holding the data for the second operand, and shift is an
optional shift to be applied to Rm. The optional shift can be one of these five formats:
If we omit the shift, or specify LSL #0, the value of the flexible second operand is Rm. If
we specify a shift, the shift is applied to the value in Rm, and the resulting 32-bit value is
used by the instruction. However, the contents in the register Rm remain unchanged. For
example,
ADD R0,R1,LSL #4 ; R0 = R0 + R1*16 (R1 unchanged)
LDRSH Load 16-bit signed halfword (sign extend bit 15 to bits 31-16)
LDRSB Load 8-bit signed byte (sign extend bit 7 to bits 31-8)
All other read and write memory operations generate a usage fault exception if they
perform an unaligned access, and therefore their accesses must be address aligned.
Also, unaligned accesses are usually slower than aligned accesses, and some areas of
memory do not support unaligned accesses. But unaligned accesses may allow
programs to use memory more efficiently at the cost of performance. The tradeoff
between speed and size is a common motif.
Observation: We add a dot in the middle of 32-bit hexadecimal numbers (e.g., 0x2000.0000).
This dot helps the reader visualize the number. However, this dot should not be used when
writing actual software.
Checkpoint 2.36
The addressing mode defines the format for the effective address for that instruction. In other
words, it defines how the instruction will access the data it needs.
Checkpoint 2.37
Assume R3 equals 0x2000.0000 at the time LDR R2,[R3,#8] is executed. What address will
be accessed? If R3 is changed, to what value will R3 become?
Assume R3 equals 0x2000.0000 at the time LDR R2,[R3],#8 is executed. What address will
be accessed? If R3 is changed, to what value will R3 become?