Z80 Addressing Modes and the Stack
8-Bit CPUs — 6502/6510 & Z80
Chapter 7 · Z80 Addressing Modes and the Stack
This closes out the Z80 block. cpu8bit1-6 previewed IX/IY and HL-as-pointer; this chapter delivers the full addressing-mode picture, including the real cost the Z80's flexibility carries — and finishes with the stack, where the Z80 turns out to be a genuine synthesis of what LC-3 and the 6502 each did separately.
Register-Indirect Addressing — (HL), (BC), (DE)
cpu8bit1-6 already introduced (HL) as a direct pointer dereference. (BC) and (DE) work identically in principle — reading or writing whatever address the register pair currently holds — though in practice they're supported by a narrower set of instructions (mainly simple loads and stores), while HL remains the chip's general-purpose pointer workhorse, usable with far more of the instruction set. All three are simpler than assembly1-3's own LC-3 indirect mode (LDI), which required a two-step "read a pointer from a PC-relative address, then follow it" — here, the pointer already sits directly in a register, one step only.
Indexed Addressing With Displacement — IX+d and IY+d
IX and IY support a genuinely powerful addressing mode: a base register plus a signed 8-bit displacement (d, roughly -128 to +127), computed at execution time:
LD IX, $4000 LD A, (IX+5) ; reads the byte at $4000 + 5 = $4005
This is a natural fit for accessing individual fields of a data structure at fixed offsets from a base pointer — IX holding the structure's address, d selecting which field — and unlike the 6502's own indexed modes from cpu8bit1-4, it isn't tied to zero page at all. IX and IY can point anywhere in the full 64KB space.
That flexibility has a real, measurable cost. Recall cpu8bit1-4's own cycle table for the 6502's addressing modes:
| Chip | Instruction | Cycles | Notes |
|---|---|---|---|
| Z80 | LD A,(HL) | 7 | Direct register-pointer dereference |
| Z80 | LD A,(IX+d) | 19 | Prefix byte + opcode + displacement byte, plus real address-calculation time |
| 6502 | LDA zero page | 3 | cpu8bit1-4 |
| 6502 | LDA (zp),Y | 5 | cpu8bit1-4 — the closest 6502 equivalent to a flexible pointer-plus-offset read |
LD A,(IX+d) costs nearly four times what (HL) costs, and almost four times what the 6502's own (zp),Y costs for a broadly comparable "pointer plus offset" access. The Z80's version can reach anywhere in memory rather than needing a zero-page base — but that extra reach is paid for in real, per-instruction cycles, not just extra transistors.
cpu8bit1-5 and cpu8bit1-6 both measured the Z80's richness in transistor count. This is the same story showing up at runtime instead of at manufacturing time — IX/IY addressing genuinely does more, but every use of it costs real, measurable extra cycles compared to the chip's own simpler modes. A capability existing isn't the same as it being free to use.
The Stack — Real Hardware, Genuinely Flexible
cpu8bit1-3 covered the 6502's real but page-1-locked hardware stack, itself a genuine improvement over assembly1-7's entirely software-built LC-3 stack. The Z80's stack is a third point on that same spectrum: SP is a full 16-bit register, free to point anywhere in the 64KB address space — no fixed page, no artificial ceiling.
Push and pop are native instructions, and — reflecting cpu8bit1-6's own register pairing — they operate on a full 16-bit register pair at once, not a single byte the way the 6502's PHA does:
PUSH BC ; pushes both B and C together, 16 bits in one instruction POP BC ; pulls both back
The stack still grows downward — SP decrements on every push — the same convention assembly1-7's own LC-3 example and cpu8bit1-3's 6502 stack both already used.
| Architecture | Where the stack can live | Hardware support | Push/pop granularity |
|---|---|---|---|
| LC-3 (assembly1-7) | Anywhere in memory — the programmer's own choice | None — manually built from ADD/STR/LDR | One value at a time, via generic instructions |
| 6502 (cpu8bit1-3) | Locked to page 1 only ($0100–$01FF) | Real — dedicated SP register, PHA/PLA/PHP/PLP | One byte at a time |
| Z80 (this chapter) | Anywhere in the full 64KB space | Real — dedicated 16-bit SP register, PUSH/POP | One 16-bit register pair at a time |
Put side by side, the Z80's stack genuinely combines the best of both predecessors covered so far: LC-3's freedom to live anywhere, with real dedicated hardware doing the actual work — the flexibility of a software stack with the speed of a hardware one.
cpu8bit1-8, which implements one identical routine in both 6502 and Z80 assembly, side by side — the course's first direct, concrete payoff of studying the two chips in parallel rather than in isolation.
Hands-On Exercises
Given IX = $4000, compute the effective address of LD A,(IX+5) using this chapter's own formula, and show your work.
Using this chapter's own cycle table, explain why LD A,(IX+d) (19 cycles) costs almost four times as much as the 6502's own LDA (zp),Y (5 cycles), even though both are broadly "flexible pointer plus offset" addressing modes.
Using this chapter's own three-way stack comparison table, explain what each of LC-3, the 6502, and the Z80 trades away in exchange for its own particular combination of flexibility and hardware support.
📄 View solutionChapter 7 Quick Reference
- (HL)/(BC)/(DE) — direct register-pointer dereference, simpler than LC-3's own two-step LDI
- IX+d / IY+d — a base register plus a signed 8-bit displacement, reaching anywhere in the full 64KB space
LD A,(IX+d)costs 19 cycles vs.(HL)'s 7 and the 6502's own (zp),Y at 5 — flexibility has a real runtime cost, not just a transistor one- The Z80's SP is a full 16-bit register — the stack can live anywhere in memory, with no page restriction
- PUSH/POP move a full 16-bit register pair in one instruction, vs. the 6502's single-byte PHA/PLA
- Three-way stack comparison: LC-3 (flexible, software-only) → 6502 (hardware, page-locked) → Z80 (hardware AND flexible)
- This closes the Z80 block — cpu8bit1-8 puts every addressing mode and stack mechanic from both chips to work side by side