The Z80 microprocessor contains a rich set of registers designed to optimise data handling and control program flow. Understanding how each register works is essential for efficient assembly programming.
The Z80 includes two main groups of eight-bit general-purpose registers:
A B C D E F H L
These registers can be used either individually as eight-bit registers or paired to form sixteen-bit registers:
BC DE HL AF
A secondary, alternate set of these registers is also available, denoted with a prime symbol ('):
A' B' C' D' E' F' H' L'
This alternate set can only be accessed through the instructions EX AF,AF' and EXX. These commands exchange the contents of the main and alternate register sets. Only one set is active at a time, providing an efficient way to preserve data during complex operations or interrupt handling.
Besides the general-purpose registers, the Z80 includes several sixteen-bit special registers:
IX IY SP PC I R
Each has a specific purpose in program control, indexing, or hardware operations.
The Program Counter (PC) holds the address of the next instruction to execute. It automatically increments after each instruction fetch, ensuring that program flow continues sequentially unless altered by a jump, call, or interrupt.
The programmer cannot directly manipulate the PC, but its value can be changed indirectly through control instructions such as JP, CALL, and RET.
The Stack Pointer (SP) holds the sixteen-bit address of the current top of the stack. The stack is an area of RAM organised as a last in, first out (LIFO) structure. Data pushed onto the stack can only be retrieved in the reverse order it was placed.
Each PUSH instruction decreases the stack pointer by two bytes (since each entry is sixteen bits), while each POP increases it by two. The stack is used primarily for storing register contents during subroutines and interrupt handling.
Example:
PUSH BC ; Save BC on stack
PUSH DE ; Save DE on stack
CALL SUBR ; Call subroutine
POP DE ; Restore DE
POP BC ; Restore BC
Proper stack management is crucial. Every PUSH must have a matching POP, otherwise the stack becomes unbalanced, leading to program crashes or unpredictable behaviour.
The A register, or accumulator, is central to most arithmetic and logical operations. It stores the result of operations such as addition, subtraction, and bitwise logic.
The F register, or flag register, holds status flags that reflect the outcome of arithmetic and logical operations. These flags include indicators such as Zero, Sign, Carry, Parity, and Half-Carry. They influence conditional branching and control decisions during program execution.
Example:
DEC A ; Decrement accumulator
JR NZ,LOOP ; Jump if the Zero flag is not set
These registers can be used individually as eight-bit registers or combined into sixteen-bit pairs:
Example operations:
LD HL,4000h ; Load HL with memory address 4000h
LD (HL),A ; Store accumulator at address in HL
INC HL ; Move to next memory location
The HL register pair supports direct memory addressing and can participate in stack and arithmetic operations, making it essential to most routines.
The IX and IY registers are sixteen-bit registers used primarily for indexed addressing. They are ideal for accessing data structures such as tables or arrays. By adding an offset to these registers, you can address memory locations relative to a base pointer.
Example:
LD IX,DATA ; Load base address
LD A,(IX+5) ; Load A with the byte at DATA+5
Offsets can range from –128 to +127, providing flexible indexed memory access. Although these instructions use slightly more memory (as they include an additional byte for the offset), they enable sophisticated data handling in structured programs.
The IX and IY registers function identically, and their use is generally interchangeable.
The I (Interrupt Vector) and R (Memory Refresh) registers serve specialised roles:
These registers are rarely modified directly in general-purpose programming but are essential for low-level system control.
Mastering the Z80 registers involves more than memorising their functions. Each register’s purpose, accessibility, and operational characteristics determine how efficiently you can write and structure your code. Efficient assembly programming often depends on selecting the right register for each task.
For example:
As you gain experience, these decisions become instinctive, allowing you to balance speed, clarity, and memory efficiency in your code.
Would you like me to include modernised diagrams (for example, simplified register maps showing the relationships between AF, BC, DE, HL, and the special registers)? These would make the rewritten section visually clearer and more educational.