Bank Switching
Expanding memory through hardware tricks
Bank switching allows systems with limited address space to access more memory by swapping different memory regions into the same address range.
Overview
Bank switching solves a fundamental problem: CPUs with 16-bit address buses can only address 64KB of memory, but games and programs often need more. The solution involves mapping different physical memory regions into the same address range, swapping “banks” as needed. This technique enabled NES cartridges to contain megabytes of data despite the console’s limited addressing.
Fast Facts
| Aspect | Detail |
|---|---|
| Problem solved | 16-bit address limit (64KB) |
| Method | Swap memory regions via hardware |
| Common platforms | NES, Game Boy, C64, ZX Spectrum 128K |
| Modern equivalent | Virtual memory, paging |
The Address Space Problem
An 8-bit CPU with 16-bit addressing:
| Addressing | Maximum |
|---|---|
| 16-bit address bus | 2^16 = 65,536 bytes |
| 64KB ceiling | Hard limit for direct access |
| Game requirements | Often exceeded 64KB |
How Bank Switching Works
The concept:
| Step | Action |
|---|---|
| 1 | CPU sees fixed address range (e.g., $8000-$BFFF) |
| 2 | Hardware maps this to physical ROM/RAM |
| 3 | Writing to special register selects which bank |
| 4 | New bank appears at same addresses |
| 5 | Program code switches banks as needed |
Platform Examples
NES Mappers
The NES used cartridge hardware called “mappers”:
| Mapper | Features |
|---|---|
| NROM (0) | No switching, 32KB PRG |
| MMC1 (1) | 256KB PRG, CHR switching |
| MMC3 (4) | 512KB PRG, IRQ counter |
| MMC5 (5) | 1MB PRG, extended features |
Different games used different mappers depending on complexity.
Commodore 64
The C64 used ROM/RAM banking:
| Region | Banks |
|---|---|
| $A000-$BFFF | BASIC ROM or RAM |
| $D000-$DFFF | I/O or character ROM or RAM |
| $E000-$FFFF | Kernal ROM or RAM |
Switching via the processor port at $01.
ZX Spectrum 128K
The 128K Spectrum banked RAM at $C000-$FFFF:
| Feature | Detail |
|---|---|
| Fixed bank | Bank 5 always at $4000-$7FFF |
| Switchable | Eight 16KB banks at $C000-$FFFF |
| Control | Port $7FFD |
Technical Challenges
| Challenge | Consequence |
|---|---|
| Code can’t span banks | Jump targets must be in same bank |
| Data access planning | Know which bank contains what |
| Interrupt handling | Bank state during interrupts |
| Performance overhead | Bank switching takes cycles |
Programming Patterns
| Pattern | Purpose |
|---|---|
| Fixed bank | Code that must always be accessible |
| Data banks | Level data, graphics, audio |
| Trampoline code | Jump between banks via fixed code |
| Bank tables | Track what’s where |
NES Bank Switching Code
A simplified example:
; Switch to bank 3
LDA #$03
STA $8000 ; Bank select register (mapper-specific)
; Now $8000-$BFFF contains bank 3's data
The exact mechanism varies by mapper hardware.
Historical Context
| Era | Approach |
|---|---|
| Arcade boards | Custom banking hardware |
| Console cartridges | Mapper chips in cart |
| Home computers | System-level banking |
| CD-ROM era | Streaming replaced banking |
Legacy
Bank switching was the bridge between limited addressing and modern virtual memory. Developers learned to structure code and data around bank boundaries—skills that translated into understanding memory hierarchies, caching, and modern paging systems. Emulator developers must accurately emulate mapper behaviour to run games correctly.