The Thumb instruction set used in ARM processors has a reduced number of addressing modes compared to ARM mode. This is done to compress the size of instructions when in Thumb state. The main addressing modes supported in Thumb state are:
Register Addressing
This is the most basic addressing mode where the operands are registers such as R0-R7. Instructions like add, sub, mov use register addressing. For example: add r0, r1, r2
Here two registers r1 and r2 are added and stored in r0. This mode is very fast as accessing registers takes only 1 cycle.
Immediate Addressing
In this mode, one operand is a register while the other is an immediate constant embedded in the instruction itself. For example: mov r0, #10
Loads the value 10 into register r0. Being able to access a constant operand makes coding faster and requires less load instructions. The range of immediate values is smaller in Thumb vs ARM mode to keep instruction size 16-bit.
PC-relative Addressing
This mode specifies the address of an operand relative to the current Program Counter(PC). The address is specified as a signed 8-bit or 11-bit offset from the PC. For example: ldr r0, [pc, #8]
Loads the value at PC+8 into r0. This avoids having to materialize a full 32-bit address. PC-relative addressing improves code density.
Register-relative Addressing
In this mode, the operand address is specified as an offset from a register. For example: ldr r0, [r1, #8]
Loads the value at address r1+8 into r0. The offset can be a 3-bit unsigned number allowing access up to +7 or -8 from the base register’s address.
Absolute Addressing
This mode specifies the full 32-bit address of the operand. For example: ldr r0, [0x12345678]
Loads the value at address 0x12345678 into r0. This requires more bytes than other modes so is rarely used.
Load/Store Multiple
Special instructions allow loading/storing multiple registers from a sequential memory region. For example: ldmia r1!, {r2, r3, r4}
Loads registers r2,r3,r4 from memory starting at r1. r1 is updated to point to next location after the load. This is efficient way to push/pop stack contents.
Conditional Execution
Most Thumb instructions can be conditionally executed based on the status flags in the CPSR. For example: beq label1
Branches to label1 if Z flag is set. Conditional execution avoids having to explicitly compare and branch.
Shifted Register
The value of a register can be shifted left/right before being used in an operation: add r0, r1, r2, LSL #3
Adds r1 and r2 left shifted by 3 bits. This is useful for multiply/divide and accessing bitfields.
Memory Hint
Special instructions provide hints to the processor about expected memory access patterns: pld [r1]
Preloads data at r1 into cache. This helps optimize caching and reduce stalls.
Branch and Exchange (BX)
BX can be used branch to a register’s contents: bx r1
Jumps to the address in r1. This allows efficient jumps between ARM and Thumb state code.
Long Branch with Link (BL)
Branch with Link allows branching to a PC-relative offset up to 16MB: bl label
Branches to label within +/- 16MB. Link saves return address to the Link Register (LR). BL provides range not available in short branches.
Summary of Addressing Modes
To summarize, the main addressing modes supported in Thumb state are:
- Register Addressing
- Immediate Constant
- PC-relative Addressing
- Register-relative Addressing
- Absolute Addressing
- Load/Store Multiple
- Conditional Execution
- Shifted Register
- Memory Hints
- BX
- BL
Thumb mode has a reduced number of addressing modes compared to ARM mode. This is to compress instructions into 16-bit formats improving code density. However, Thumb still supports a rich set of modes needed for most application use cases while maintaining high performance.
Immediate and PC-relative addressing allow embedded constants and labels efficiently. Register-relative and load/store multiple modes reduce instruction count for register access. Conditional execution avoids explicit compare branches. Features like shifted register, memory hints and BX/BL enhance speed and flexibility.
Overall, the addressing modes in Thumb state balance code size and performance. They provide compact access to memory and registers while retaining ARM’s versatile instruction set architecture advantages. The careful subset of ARM addressing modes was a key factor in Thumb’s success in embedded applications requiring small code size.