Addressing Modes as Hardware - How the CPU Computes Where
An assembly instruction is not only an operation. It is also a compact set of clues that tells the CPU where each operand comes from. The addressing mode is the hardware answer to that question.
In a small microcontroller, addressing modes are implemented with register-file read ports, immediate fields, multiplexers, address adders, incrementers, the program counter, and the memory bus. A mode that looks like a tiny syntax change in assembly can add a real mux input, an adder path, a write-back path, or an extra memory access.
Learning Objectives
By the end of this lesson, you should be able to:
- explain effective address calculation as real datapath hardware;
- compare immediate, register, direct, indirect, indexed, and PC-relative modes;
- identify why some modes cost more cycles than others;
- connect AVR and ARM examples to mux, adder, and memory-bus behavior;
- choose efficient addressing forms in simple embedded code.
The Two Questions Behind Every Operand
The decoder first identifies the operation: add, load, store, branch, compare, and so on. Then the addressing-mode hardware decides where the operand is:
- inside the instruction word itself;
- in a register;
- at an absolute memory address;
- at the memory address stored in a register;
- at a base address plus an offset;
- at a target computed relative to the program counter.
The important point is that "addressing mode" is not a documentation category. It is a selected path through the datapath.
Immediate Addressing: The Value Is in the Instruction
Immediate mode carries the operand value in the instruction word.
; AVR
LDI R16, 0x42 ; R16 = 0x42
; ARM Thumb
MOVS R0, #4 ; R0 = 4, flags updated
There is no data-memory read. The immediate field is routed to an ALU input or register write path. This is fast and code-dense when the constant fits the instruction's immediate field.
Hardware path: instruction register -> immediate extract/extend -> mux -> ALU or register file.
Common limits: the immediate may be narrow, may be split across bit fields, may be signed or unsigned, and may only target a subset of registers. Classic AVR LDI, for example, loads only R16 through R31.
Register Direct: The Operand Is Already On-Chip
Register direct mode names a register. The instruction contains a register index, not a memory address.
; AVR
ADD R1, R2 ; R1 = R1 + R2
; ARM Thumb
ADDS R0, R1, R2 ; R0 = R1 + R2, flags updated
The register-file decoder selects the requested source registers. No external memory address has to be formed.
Hardware path: instruction register -> register index fields -> register-file read ports -> ALU.
This is why compilers try to keep hot variables in registers. A register operand is available inside the CPU, while a memory operand requires address calculation and a bus access.
Direct or Absolute Addressing: The Instruction Names Memory
Direct addressing embeds the memory address, or part of it, in the instruction stream.
; AVR
LDS R16, 0x0150 ; load R16 from SRAM address 0x0150
On classic AVR, LDS is commonly a 32-bit instruction: one word for the opcode and register field, and another word for the address. That extra program-memory word must be fetched before the data-memory read can happen.
Hardware path: instruction stream -> address field -> address bus -> memory -> data bus -> register file.
Direct addressing is easy to understand and useful for fixed hardware registers, but it can cost more code space and cycles than a register pointer.
Register-Indirect: A Register Holds the Address
In register-indirect mode, a register or register pair contains the memory address.
; AVR
LD R16, X ; X is R27:R26, load byte at address X
; ARM
LDR R0, [R1] ; load word from address held in R1
The instruction names the pointer register. The register content drives the address bus.
Hardware path: pointer register -> address mux -> address bus -> memory -> data bus -> destination register.
This is the hardware basis for pointers in C. When C code says value = *p;, the generated instruction usually uses a register-indirect load.
Indexed Addressing: Base Plus Offset
Indexed addressing adds a constant or register offset to a base pointer.
; ARM
LDR R0, [R1, #4] ; R0 = memory[R1 + 4]
; AVR
LDD R16, Y+3 ; load from address Y + 3, on devices that support it
LD R17, X+ ; load from X, then increment X
The CPU must either add base plus offset or update the pointer after the access.
Indexed modes are valuable for arrays, structures, stacks, buffers, and table lookups. The cost is extra datapath support: an adder, offset extension logic, and sometimes pointer write-back.
PC-Relative Addressing: The Program Counter Is the Base
Branches usually do not store full target addresses. They store a signed offset from the current program counter.
; AVR
RJMP +10 ; PC = PC + 1 + signed offset
; ARM Thumb
B label ; PC-relative branch
For an AVR RJMP, the 12-bit offset is a signed word offset added to PC + 1. A 12-bit signed value gives a range of -2048 to +2047 words from the next instruction.
Hardware path: PC -> branch adder; signed offset -> branch adder; selected result -> PC input.
PC-relative addressing supports relocatable code and compact branches. The trade-off is limited reach: if the target is too far away, the assembler must use a longer branch sequence or an absolute jump.
Worked Example: Array Access in C
Consider this C statement on a 32-bit microcontroller:
uint32_t y = samples[i];
If samples is in register R1 and i is in R2, the CPU may form:
effective address = base + index * element_size
effective address = R1 + R2 * 4
Some architectures have scaled-index hardware. Small microcontrollers often do not, so the compiler may emit a shift plus an add:
LSLS R2, R2, #2 ; i * 4
LDR R0, [R1, R2] ; load samples[i]
The addressing mode therefore influences both speed and code size. If the hardware cannot perform the exact address calculation in one instruction, the compiler builds it from simpler datapath operations.
Cycle Cost and Hardware Cost
| Mode | Example | Main hardware | Memory reads before data | Typical cost |
|---|---|---|---|---|
| Immediate | LDI R16, 0x42 |
immediate mux | 0 | very low |
| Register direct | ADD R1, R2 |
register-file ports | 0 | very low |
| Direct/absolute | LDS R16, 0x0150 |
address field path | often 1 extra program word | higher |
| Register indirect | LD R16, X |
pointer register path | 0 | moderate |
| Indexed | LDR R0, [R1,#4] |
address adder | 0 | moderate |
| Auto-increment | LD R16, X+ |
address path plus write-back | 0 | moderate |
| PC-relative | RJMP k |
PC adder | 0 | low, reach-limited |
Do not memorize cycle counts from this table for a specific chip. Always check the device datasheet or architecture manual. The table's purpose is to show the reason: extra fetches, address adders, and write-back paths are not free.
Practical Design Checks
When reading generated assembly, ask:
- Is this operand a literal, register, pointer, absolute address, or PC-relative offset?
- Does the instruction need a data-memory access?
- Does it fetch an extra instruction word for an address or long immediate?
- Does the pointer get updated as a side effect?
- Is the branch target within the encoded offset range?
- Is the load/store width aligned as the architecture requires?
Common Mistakes
- Treating an immediate as an address.
#4means value 4 on many assemblers;[R1,#4]means addressR1 + 4. - Forgetting AVR
LDItargets only high registers on classic AVR cores. - Assuming all loads cost the same. Absolute loads, indirect loads, and indexed loads may have different timings.
- Ignoring side effects of pre-decrement and post-increment modes.
- Confusing byte offsets and word offsets in branch instructions.
- Assuming a C pointer access always becomes one instruction.
Summary
Addressing modes are hardware choices. Immediate and register modes stay mostly inside the CPU. Direct and indirect modes involve the memory interface. Indexed and PC-relative modes use adders to compute effective addresses. The syntax is small, but the hardware consequences affect cycle count, code size, and compiler output.
Further Reading
- Microchip, AVR Instruction Set Manual, addressing modes and instruction timing.
- Arm, Armv7-M Architecture Reference Manual, load/store and branch encodings.
- Patterson and Hennessy, Computer Organization and Design, datapath and control chapters.
- Bryant and O'Hallaron, Computer Systems: A Programmer's Perspective, machine-level data and control flow.
Mind Map
-> Interrupts