# Addressing modes

*How an instruction names its operand*

An addressing mode is the rule a CPU uses to find an instruction's operand: immediate keeps the value inside the instruction, direct (absolute) keeps the operand's memory address in the instruction, indirect keeps the address of the address, and indexed adds a base and an offset to compute the address.

Group: Processor
URL: https://digiwleea.wleeaf.dev/learn/addressing-modes/

Every instruction in our [machine code](https://digiwleea.wleeaf.dev/learn/machine-code/) is an opcode plus an operand, and for `LOAD`, `ADD`, and `STORE` that operand is a **memory address**: `LOAD 14` means "read the byte at address 14 into the accumulator." The [labels](https://digiwleea.wleeaf.dev/learn/assembly-labels/) lesson let you name those addresses, but we never named the **rule** itself, that the operand is an address and the CPU should go read the memory there. That rule is one **addressing mode**, called *direct*, and it is the only one our small machine has. Real processors offer several. This lesson names ours and, honestly, contrasts it with the modes x86, ARM, and RISC-V add, so you can read those instruction sets and see what extra hardware each mode needs.

One idea ties every mode together: the **effective address** (EA), the address the operand actually resolves to. A mode is just a recipe for computing the EA (or, for one mode, for skipping memory altogether). Throughout, take a concrete memory: `memory[14] = 42` is the data we want, `memory[5] = 14` is a pointer cell that *holds* the address 14, and imagine two registers `R1 = 14` and `R2 = 10` for the modes that use them.

## Direct (absolute): our machine's mode

In **direct** (also called **absolute**) addressing, the operand *is* the effective address: the CPU reads the memory at exactly that number. `LOAD 14` sets `EA = 14`, so the accumulator gets `memory[14] = 42`. This is precisely what our [instruction register](https://digiwleea.wleeaf.dev/learn/instruction-register/) and datapath already do, and it assembles to a single byte: opcode `0x1` (LOAD) packed with operand `0xE` (14) gives `0x1E`. Direct addressing is simple and needs no extra hardware, which is why a first CPU uses it, but the operand field's width caps how far it can reach (our 4-bit operand can only name addresses `0` to `15`).

## Immediate: the operand is the value

In **immediate** addressing the operand is not an address at all, it *is* the value, sitting right inside the instruction. Written `LOAD #14` (the `#` marks a literal), it puts `14` straight into the accumulator with **no memory read** at all. That makes it the fastest mode and the natural way to load a constant (a loop count, a mask, the number `1`). Its cost is the mirror image of direct's: the value is fixed when you assemble, and it can only be as wide as the operand field, so a 4-bit immediate can only be `0` to `15`.

## Indirect: an address of an address

In **indirect** addressing the operand points to a cell that itself holds the real address, an address *of* an address. `LOAD [5]` reads `memory[5]` first to get the address `14`, then reads `memory[14] = 42`. Two memory accesses instead of one, so `EA = memory[5] = 14`. A common variant is **register-indirect**, where a register holds the address rather than a memory cell: `LOAD (R1)` with `R1 = 14` gives `EA = R1 = 14`, again reaching `42`. Indirection is what makes **pointers** possible: change the value in the pointer cell (or register) and the same instruction now operates on a different location, without rewriting the code.

## Indexed: base plus offset

In **indexed** (also **base-plus-displacement** or register-relative) addressing the effective address is a **base plus an offset**. `LOAD 4(R2)` with base register `R2 = 10` computes `EA = R2 + 4 = 14`, so again the accumulator gets `42`. This is the mode that makes **arrays and loops** cheap: point the base at the start of an array, keep the index in a register, and one instruction reads element after element as you bump the index. Its close relative is **PC-relative** addressing, where the base is the [program counter](https://digiwleea.wleeaf.dev/learn/counter/): `EA = PC + offset`. That is how branches work and how code stays *position-independent* (relocatable), because a jump target is written as a distance rather than a fixed address.

## The four modes side by side

| mode | example | effective address | ACC gets |
| --- | --- | --- | --- |
| immediate | LOAD #14 | none (value in instruction) | 14 |
| direct / absolute | LOAD 14 | 14 | 42 |
| indirect | LOAD [5] | memory[5] = 14 | 42 |
| register-indirect | LOAD (R1) | R1 = 14 | 42 |
| indexed | LOAD 4(R2) | R2 + 4 = 14 | 42 |

_With memory[14] = 42, memory[5] = 14, R1 = 14, R2 = 10: every mode but immediate resolves to address 14 and loads 42; immediate skips memory and loads the literal 14. Same number in the instruction, different operand, because the mode decides how it is read._

```asm
      LOAD 14       ; direct:    ACC = memory[14] = 42        -> 0x1E  (valid here)
      LOAD #14      ; immediate: ACC = 14, the literal (no read)
      LOAD [5]      ; indirect:  ACC = memory[memory[5]] = memory[14] = 42
      LOAD 4(R2)    ; indexed:   ACC = memory[R2 + 4] = memory[14] = 42   (R2 = 10)
```

_Only the first line assembles on our CPU (to the byte 0x1E). The others are shown to contrast: immediate needs the operand field to carry a value not an address, indirect needs a second memory read, and indexed needs an index register, none of which our accumulator machine has._

> **KEY:** The mode, not just the number, decides the operand, and that is what unlocks real programs. **Immediate** gives you constants; **indirect** gives you pointers; **indexed** and **PC-relative** give you arrays, loops, and relocatable branches. This is also the classic **CISC vs RISC** tradeoff: CISC designs like x86 offer many rich modes (fewer, more expressive instructions, but harder to decode), while RISC designs like ARM and RISC-V keep only a few (typically register, immediate, and base-plus-offset for loads and stores) to keep decoding simple and pipelines fast. Our machine sits at the far simple end with exactly one mode: direct.

> **WARN:** **Common mistakes.** Do not confuse **immediate** (the operand is the value) with **direct** (the operand is the address of the value): `LOAD #14` loads `14`, `LOAD 14` loads `memory[14]`. Do not confuse **register-indirect** (the register holds the *address*) with plain register-direct (the register holds the *value*). When computing an indexed effective address, do not drop the offset: `4(R2)` is `R2 + 4`, not `R2` and not `4`. And do not assume our built CPU supports these modes: it does direct only. Immediate, indirect, and indexed would each need a new opcode (and, for the register modes, registers we do not have), which is exactly the pressure that grows a real instruction set.

**Q (Try it):** Let `memory[9] = 3`, `memory[3] = 8`, and `R1 = 9`. What does each of these put in the accumulator: `LOAD #9`, `LOAD 9`, `LOAD [9]`, and `LOAD (R1)`?

**A:** `LOAD #9` is **immediate**: `ACC = 9`, the literal. `LOAD 9` is **direct**: `ACC = memory[9] = 3`. `LOAD [9]` is **indirect**: read `memory[9] = 3` to get the address, then `ACC = memory[3] = 8`. `LOAD (R1)` is **register-indirect** with `R1 = 9`: `ACC = memory[9] = 3`. Four modes, four routes: `9`, `3`, `8`, `3`. The same operand `9` means a value, an address, or a pointer depending only on the mode.

### FAQ

**Q:** What is an addressing mode?

**A:** An addressing mode is the rule a CPU uses to find an instruction's operand. Immediate keeps the value inside the instruction, direct (absolute) keeps the operand's memory address, indirect keeps the address of the address, and indexed adds a base register and an offset. Each mode is a recipe for the **effective address** the instruction actually acts on.

**Q:** What is the difference between immediate and direct addressing?

**A:** In **immediate** addressing the operand IS the value: `LOAD #14` loads the number `14` with no memory access. In **direct** (absolute) addressing the operand is the value's address: `LOAD 14` loads `memory[14]`. Same number in the instruction, but immediate treats it as data and direct treats it as an address.

**Q:** What is indirect addressing?

**A:** Indirect addressing means the operand points to a location that itself holds the real address, an address of an address. `LOAD [5]` reads `memory[5]` to find the address (say 14), then reads `memory[14]`. It costs a second memory access but enables pointers: change the pointer's contents and the same instruction reaches a new location. Register-indirect is the variant where a register, not a memory cell, holds the address.

**Q:** What addressing modes does a simple accumulator CPU use?

**A:** Just one: **direct** addressing. Our LOAD, ADD, and STORE take a memory address as the operand and read or write the byte there, with no immediate, indirect, or indexed modes. Adding those would require new opcodes and, for the register-based modes, registers the accumulator machine does not have, which is why larger ISAs like x86, ARM, and RISC-V grew richer addressing.
