Skip to content
Techniques & Technology

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.

nintendo-entertainment-systemcommodore-64sinclair-zx-spectrumsega-master-system memoryhardwarecartridge 1970–present

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

AspectDetail
Problem solved16-bit address limit (64KB)
MethodSwap memory regions via hardware
Common platformsNES, Game Boy, C64, ZX Spectrum 128K
Modern equivalentVirtual memory, paging

The Address Space Problem

An 8-bit CPU with 16-bit addressing:

AddressingMaximum
16-bit address bus2^16 = 65,536 bytes
64KB ceilingHard limit for direct access
Game requirementsOften exceeded 64KB

How Bank Switching Works

The concept:

StepAction
1CPU sees fixed address range (e.g., $8000-$BFFF)
2Hardware maps this to physical ROM/RAM
3Writing to special register selects which bank
4New bank appears at same addresses
5Program code switches banks as needed

Platform Examples

NES Mappers

The NES used cartridge hardware called "mappers":

MapperFeaturesTypical games
NROM (0)No switching, 16KB or 32KB PRGDonkey Kong, Mario Bros
UxROM (2)256KB PRG bank-switching, fixed last bankMega Man, Castlevania
CNROM (3)32KB PRG fixed, 32KB CHR bank-switchingPaperboy
MMC1 (1)Up to 512KB PRG + 128KB CHR, mirroring control, 5-bit serial registerZelda, Metroid
MMC3 (4)512KB PRG + 256KB CHR, scanline IRQ via PPU A12 edge, paired even/odd writesSuper Mario Bros 3
MMC5 (5)1MB PRG + 1MB CHR, extended attributes, expansion audioCastlevania III

Different games used different mappers depending on complexity. The NES 2.0 spec catalogues several hundred distinct mappers across licensed and unlicensed cartridges.

Commodore 64

The C64 banks system ROMs and I/O in and out via the 6510's on-chip processor port at $01:

RegionBanks (controlled by $01 bits 0-2)
$8000-$9FFFRAM, or cartridge LO ROM (when /EXROM is asserted)
$A000-$BFFFRAM, BASIC ROM, or cartridge HI ROM (LORAM bit)
$D000-$DFFFRAM, character ROM, or I/O area (CHAREN bit)
$E000-$FFFFRAM, KERNAL ROM, or cartridge HI ROM (HIRAM bit)

Bit 0 = LORAM, bit 1 = HIRAM, bit 2 = CHAREN. The Ultimax cartridge mode (/EXROM=0, /GAME=0) replaces large parts of the map with cartridge ROM regardless of $01.

ZX Spectrum 128K

The 128K Spectrum banked RAM at $C000-$FFFF:

FeatureDetail
Fixed Bank 5Always at $4000-$7FFF (the regular screen)
Fixed Bank 2Always at $8000-$BFFF
SwitchableEight 16KB banks at $C000-$FFFF (banks 0-7, selected by $7FFD bits 0-2)
ControlPort $7FFD (write-only); bit 5 locks paging until reset

The +2A/+3 add a second paging port at $1FFD for "all-RAM" configurations and ROM disk routing.

Technical Challenges

ChallengeConsequence
Code can't span banksJump targets must be in same bank
Data access planningKnow which bank contains what
Interrupt handlingBank state during interrupts
Performance overheadBank switching takes cycles

Programming Patterns

PatternPurpose
Fixed bankCode that must always be accessible
Data banksLevel data, graphics, audio
Trampoline codeJump between banks via fixed code
Bank tablesTrack what's where

Trampoline pattern

The trampoline lives in a fixed bank (e.g. MMC3's last 8 KB at $E000-$FFFF, which never switches). It saves the current bank, switches to the target bank, calls into it, and restores the original bank on return. Code in switchable banks calls foreign functions only via the trampoline:

; Lives at $E000 in the fixed bank
far_call:
    PHA                  ; save bank arg & target addr (pushed by caller)
    ; ... swap to target bank using mapper-specific writes ...
    JSR (target_addr)    ; run the routine in the now-paged bank
    ; ... swap back to caller's bank ...
    RTS

Without a trampoline, an RTS from a foreign bank would land back in the wrong bank's code.

NES bank switching by mapper

The bank-select interface varies enormously between mappers. Three patterns cover most of them.

UxROM, CNROM, AxROM — direct write

A single write to any address in the cartridge range latches the bank number:

    LDA #$03
    STA $8000        ; UxROM: select PRG bank 3 at $8000-$BFFF
                     ; (last bank stays fixed at $C000-$FFFF)

MMC1 — 5-bit serial shift register

MMC1 collects five sequential writes into an internal shift register. Each write latches one bit (bit 0 of the value); on the fifth write the assembled 5-bit value is committed to one of four registers, picked by the address of the fifth write:

    LDA #%10000000   ; bit 7 set = reset shift register
    STA $8000        ; (use this to abort a partial write sequence)

    ; Now write the 5 bits of the bank number, LSB first
    LDA #$1          ; bit 0
    STA $E000
    LDA #$1
    STA $E000
    LDA #$0
    STA $E000
    LDA #$0
    STA $E000
    LDA #$0
    STA $E000        ; fifth write to $E000-$FFFF latches PRG bank %00011 = 3

MMC3 — paired bank-select / bank-data

MMC3 splits the operation across even and odd addresses. Write the register index to an even address in $8000-$9FFF, then the bank value to the odd address one byte later:

    LDA #$06         ; index 6 = PRG bank at $8000 (in default mode)
    STA $8000        ; bank select
    LDA #$0A
    STA $8001        ; bank data — PRG bank $0A now at $8000

MMC3 also holds an 8-bit IRQ counter that decrements on each rising edge of PPU A12, used for split-screen and status-bar effects.

Historical Context

EraApproach
Arcade boardsCustom banking hardware
Console cartridgesMapper chips in cart
Home computersSystem-level banking
CD-ROM eraStreaming 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.

See Also