The Limitation: 64 KB Address Space
The Z80 uses 16-bit address lines, meaning it can only directly address 64 kilobytes (65,536 bytes) of memory (from address 0000H
to FFFFH
). Since many systems (like the MSX or larger Spectrums) have $128$ KB or more of RAM/ROM, they must use Memory Banking to access it all.
How Memory Banking Works
Memory Banking is the technique of using an I/O port to physically switch which $16$ KB or $8$ KB block of memory is visible to the CPU at a specific address range.
Example: A system might reserve the address range C000H
to FFFFH
for a switchable $16$ KB RAM bank. By writing a value (e.g., 00H
, 01H
, 02H
) to the banking port, you can select RAM Bank 0, Bank 1, or Bank 2 to appear in that address range.
Switching Commands
Memory banking is always controlled by the standard Z80 OUT
instruction.
Example: Switching RAM Banks
Assume the banking port is 7FFDH
(a common address on the ZX Spectrum).
BANKING_PORT EQU 7FFDH ; The I/O port that controls the bank switch
SELECT_BANK_3:
LD A, 03H ; Value 3 selects RAM Bank 3
OUT (BANKING_PORT), A ; Write the value to the port
; RAM Bank 3 is now visible in the address range &C000H-&FFFFH.
SELECT_BANK_0:
LD A, 00H
OUT (BANKING_PORT), A ; Switch back to RAM Bank 0
RET
The ROM/RAM Dilemma
The operating system’s ROM (Read-Only Memory) always needs to be at the start of the address space (0000H
) during startup. Once the OS is running, the CPU often switches the ROM out and replaces it with RAM so the user program can utilize that crucial low memory space.
Switching ROM/RAM: The banking port often has one specific bit dedicated to controlling the ROM/RAM swap for the 0000H–3FFFH
address range. Setting that bit to 1
might enable RAM, and 0
might enable ROM.
Writing Bank-Aware Code: When writing modular assembly code, you must be extremely careful to ensure your code does not place its jump tables or data in a memory range that is about to be switched out by a banking command. Always check the target system’s memory map documentation!