Visual walkthrough — Memory addressing modes — immediate, register, direct, indirect, indexed
Before Step 1 we have no notation yet — so we cannot even write the snapshot. We build the two pieces of notation ( for memory, for registers) in Step 1, and only then pin down the concrete numbers we will reuse.
Step 1 — What is memory (and what is a register)? (numbered boxes)
WHAT. Before any "mode" makes sense, we must agree on two kinds of storage.
- Memory is a long row of numbered boxes. Each box has a number that names it (its address) and a number stored inside it (its contents).
- Registers are a tiny separate set of boxes living inside the CPU, numbered (see Registers and the Register File). They are not part of the memory row.
WHY. Every addressing mode is a rule for producing one location. If you do not see storage as "numbered boxes," the phrase "the address of the address" is gibberish. And two of the five modes read a register instead of memory, so we must name registers too, right at the start.
PICTURE. Look at the figure. The label under each memory box (in orange) is its address. The number inside each box (in navy) is its contents. We write "the contents of memory box number " as , and "the contents of register number " as :
- ::: the whole row of memory boxes (Memory).
- ::: "go to the box whose address is ."
- ::: the number sitting inside that memory box.
- ::: the little set of CPU Registers.
- ::: the number sitting inside register . (We often write the same register as
R2in assembly; on this pageR2and mean the exact same thing — the contents of register 2.)
Now that the notation exists, here is the concrete snapshot we reuse for every step below:
So reads: "memory box #100 contains the number 200," and reads "register 2 currently holds 4." Notice a box's contents can itself look like an address (200 is both a value and a valid box number) — that coincidence is the seed of indirect mode.
Step 2 — Immediate: the operand needs no box at all
WHAT. The instruction MOV R1, #100 carries the operand inside itself. The # means "this is the literal number, not an address."
WHY. Sometimes you just want a constant — the number 5, the number 100. Storing it in a box and then reading that box would waste a memory trip. So the CPU writes the constant right into the instruction word, which was already fetched when the instruction was read. (See Instruction Encoding & Opcodes for how that field is packed.)
PICTURE. The green arrow goes straight from the instruction's value field into the register. It never touches the memory row.
- The EA here does not name a memory box at all — it names the location inside the instruction word where 100 already sits. That is why we say the memory row is untouched.
- No appears ⇒ 0 memory accesses to get the operand.
Step 3 — Direct: one arrow into the boxes
WHAT. LOAD R1, [100]. The square brackets mean "this number is an address, go open that box." So here the instruction hands us the box number directly.
WHY. Global variables live at a fixed, known box for the whole program (see Registers and the Register File for the contrast — registers are not fixed boxes). Direct mode is the simplest way to name that one box.
PICTURE. Exactly one arrow: from the instruction, straight to box #100, and read what is inside.
- One appears ⇒ 1 memory access.
Step 4 — Indirect: the address of the address (two arrows)
WHAT. LOAD R1, [[100]]. The double brackets say: "box #100 does not hold the data — it holds the box number where the data lives." A box holding an address is called a pointer (see Pointers in C).
WHY. Linked lists, trees, and any structure whose target changes at runtime need a box that can be made to point anywhere. Direct mode is frozen to one address; indirect lets the contents of box #100 redirect us.
PICTURE. Follow two arrows.
- First arrow: open box #100, read its contents → . This 200 is not the answer; it is the next box number.
- Second arrow: open box #200, read its contents → . That is the operand.
- Two symbols nested ⇒ 2 memory accesses. This is why indirect is the slowest — two round trips over the memory bus (see Memory Hierarchy and Access Latency).
Step 5 — Indexed: base plus a counter (an addition, not a trip)
WHAT. LOAD R1, [100 + R2] with . Here register 2 is an index register — a small CPU counter (from the Registers and the Register File). We add its contents to the base address 100.
WHY. An array is a run of boxes starting at some base. To reach element number you do — the multiplication by element size is called scaling (see Arrays and Stride). In our snapshot each element is 4 bytes wide, so element sits at offset , i.e. already holds the scaled offset. That is why keeping the base in the instruction and the scaled offset in register 2 lets us walk the array without rewriting the instruction: bump by the element size (4) each loop and the same instruction reaches the next element.
PICTURE. The base 100 and the register contents 4 meet at a + box. Their sum, 104, is the single arrow into memory. Crucially, computing the sum is arithmetic inside the CPU — it costs no memory trip.
- Only one in the operand ⇒ 1 memory access. The
+(and any scaling multiply) is free CPU arithmetic.
Step 6 — The degenerate & edge cases (nothing left unshown)
WHAT. We check the corners so no scenario surprises you.
WHY. A rule you trust must survive its extremes: register mode (no boxes at all), a zero index, and a self-pointer.
PICTURE. Three mini-panels:
-
Register mode
ADD R1, R2— the operand is inside the CPU register 2, no memory row touched at all. Here the EA is a register number, not a memory box address: means "register slot 2," and the operand is its contents . Using the notation from Step 1, the operand is . 0 memory accesses, same cost as immediate but reusable. -
Indexed with — a degenerate index. Then , and indexed collapses to direct. This shows direct is just indexed with a zero offset: the modes form a family, not a random list.
-
Indirect self-pointer — suppose . Then and : the pointer points at itself. Still two reads, still well-defined — the recipe never breaks, even in a loop-back.
The one-picture summary
WHAT. All five arrows, side by side, over the same memory row. Read from left: immediate/register stop before the boxes; direct/indexed take one hop; indirect takes two.
WHY. If you can redraw this single figure, you have re-derived the entire parent note.
Recall Feynman retelling — the whole walkthrough in plain words
Memory is a street of numbered houses; each house has a number on the door (its address) and a note inside (its contents), and I write "note inside house " as . My pockets are the CPU registers; "what's in pocket " is . The effective address is simply "which place I finally open" — sometimes a house, sometimes a pocket, sometimes the card in my hand.
- Immediate: the prize is printed on my instruction card — the EA points at the card itself, I keep the number, I visit no house. Zero trips.
- Register: the prize is in my pocket () — the EA names the pocket, not a house. Zero trips too, but I can reuse the pocket.
- Direct: the card says "house 100" — I walk to house 100 and take the note. One trip.
- Indexed: the card says "house 100, then walk forward pocket-2's-count more houses." Because houses are counted in bytes, my counter already holds the scaled offset (4 bytes per element), so I add (that's mental arithmetic, no house-visit to do it) and go to house 104. One trip — and by bumping the counter by one element size I walk a whole array with one card.
- Indirect: the card says "house 100 holds another house number." I visit house 100 (trip one), read that it points to house 200, then visit house 200 (trip two) for the real prize. The cost of a mode is simply how many houses I must open: count the boxes and you have the answer — 0, 0, 1, 1, 2.
Recall Quick self-test
Operand expression for indirect on address 100 ::: — two nested boxes, two accesses.
Indexed EA with base 100 and index register value ::: , then read .
Why is the + in indexed free? ::: It is arithmetic inside the CPU; only the final touches the memory bus.
Indexed with index 0 becomes which mode? ::: Direct — .
What does mean? ::: The contents of CPU register number 2 (the same thing assembly writes as R2).
For a 4-byte-element array, what must the index register hold to reach element ? ::: The scaled offset , not itself (memory is byte-addressed).
What is the EA in register mode? ::: A register number (which slot), not a memory address — the operand is that register's contents.