ARM processors support a variety of addressing modes that allow accessing operand data in flexible ways. The addressing modes determine how the processor calculates the effective address of an instruction’s operand. Choosing the right addressing mode can help optimize code size, performance, and efficiency.
Register Addressing
In register addressing mode, the operand value is located in one of the CPU’s general purpose registers R0-R15. For example: ADD R1, R2, R3
This adds the contents of register R2 and R3 and stores the result in R1. No memory access is required as the values are read from registers.
Immediate Addressing
In immediate addressing, the operand value is encoded directly in the instruction. For example: MOV R1, #10
This loads the immediate value 10 into register R1. Immediate addressing is useful for loading constant values into registers.
Direct Addressing
In direct addressing mode, the operand address is specified as a literal value encoded directly in the instruction. For example: LDR R1, [0x4000]
This loads the 32-bit value from memory address 0x4000 into register R1. Direct addressing is good for accessing data at absolute memory locations.
Register Indirect Addressing
In register indirect addressing, the operand address is specified in a register. For example: LDR R1, [R2]
This loads data from the memory address contained in register R2 into register R1. Register indirect addressing is useful for accessing data pointed to by registers.
Indexed Addressing
In indexed addressing, the operand address is calculated by adding an offset to a base register. For example: LDR R1, [R2, #8]
This loads the 32-bit value from memory address R2 + 8 into register R1. The offset can be positive or negative. Indexed addressing provides flexible access for array-like data structures.
Pre-Indexed Addressing
In pre-indexed addressing, the base register is updated with the offset before the memory access. For example: LDR R1, [R2, #8]!
This adds 8 to R2 to form the memory address, loads data from that address into R1, and then updates R2 with the new address. This increments R2 to point to the next data object.
Post-Indexed Addressing
Post-indexed addressing is similar but updates the base register after the memory access. For example: LDR R1, [R2], #8
This forms the memory address from R2, loads data from that address into R1, and then increments R2 by 8. The value of R2 contains the original address during the load.
PC-Relative Addressing
PC-relative addressing specifies the address as an offset from the current Program Counter value. For example: LDR R1, [PC, #8]
This loads data from an address calculated as PC + 8 into R1. PC-relative addressing allows position-independent code.
Load/Store Multiple Addressing
ARM provides LDM and STM instructions to load/store multiple registers from a single base address. For example: STM R2, {R1-R5}
This stores registers R1 through R5 sequentially to memory starting at the address in R2. This provides efficient access for register spills/fills.
Push/Pop Addressing
The PUSH and POP instructions provide stack-like access to store and load multiple registers. For example: PUSH {R4-R8}
Push stores registers R4-R8 to the stack sequentially. The stack pointer is adjusted automatically. Pop loads them back in reverse order.
Load/Store Exclusive Addressing
LDREX and STREX provide atomic read-modify-write access to memory for synchronization. LDREX loads a value and locks the address. STREX stores a value only if the address is still locked. For example: LDREX R1, [R2] ADD R1, R1, #1 STREX R3, R1, [R2]
This loads R2 atomically, increments it, and stores back to R2. If another core modified R2, STREX will fail and rollback can be attempted.
Load/Store Unsigned Byte/Halfword
LDRB/STRB and LDRH/STRH allow smaller 8-bit and 16-bit memory accesses. For example: LDRB R1, [R2] LDRH R3, [R4]
LDRB loads an 8-bit byte into R1. LDRH loads a 16-bit halfword into R3. Smaller access can be more efficient than 32-bit loads/stores.
Scaled Register Offset Addressing
ARMv6 introduced an addressing mode with a register offset multiplied by a power of 2 scale factor. For example: LDR R1, [R2, R3, LSL #3]
This scales R3 left logically by 3 bits before adding it to R2 to form the address. This is useful for accessing arrays with pointers.
Load/Store Doubleword
ARMv7 introduced LDRD/STRD to load/store two words to/from consecutive memory addresses. For example: LDRD R2, R3, [R1]
This loads the 64-bit doubleword from addresses R1 and R1+4 into R2 and R3. This provides more efficient 64-bit memory access.
Summary
ARM supports a rich set of addressing modes to access operand data: – Register addressing for fast access – Immediate addressing for constant values – Direct addressing for absolute locations – Register indirect addressing for pointer dereferencing – Indexed addressing for array access – Pre/post-indexed addressing for automatic pointer updates – PC-relative addressing for position independence – Load/store multiple for register spills/fills – Exclusive access instructions for synchronization – Smaller memory access for byte/halfword data – Scaled register offsets for efficient array indexing – 64-bit doubleword loads/stores Flexibly utilizing these addressing modes can help optimize ARM code for size, speed, and efficiency.