VIC-20 Memory Expansion: Map the Blocks Before Loading Software
Understand the VIC-20's non-contiguous RAM expansion blocks, screen relocation, and VICE memory profiles before placing BASIC or machine-code data.
The VIC-20’s expansion memory is not a single contiguous upgrade added after the built-in RAM. The 6502 address map has several separate expansion windows, and ROM, I/O, system RAM, screen memory, and cartridge hardware occupy or influence the gaps between them. A program that assumes “16K expansion” means one uninterrupted 16-kilobyte region can place code or video data in the wrong place.
The Commodore VIC-20 Programmer’s Reference Guide and User Guide describe the original machine and its memory behavior. VICE’s manual and source code provide a practical way to reproduce named expansion configurations in an emulator. The claims here concern the standard VIC-20 memory map and VICE’s documented profiles, not every later board modification or third-party cartridge.
Read the map as windows, not one RAM pool
The standard map contains a built-in 1 KiB working area at $0000-$03FF and built-in BASIC RAM at $1000-$1FFF. Optional RAM expansion can occupy the following distinct windows:
| Expansion block | Address range | Nominal capacity | Important boundary |
|---|---|---|---|
| Block 0 | $0400-$0FFF |
3 KiB | The small low-memory expansion window. |
| Block 1 | $2000-$3FFF |
8 KiB | The first large expansion window. |
| Block 2 | $4000-$5FFF |
8 KiB | The second large expansion window. |
| Block 3 | $6000-$7FFF |
8 KiB | The third large expansion window. |
| Block 5 | $A000-$BFFF |
8 KiB | Cartridge-area space that can be mapped by supported expansion hardware. |
The gaps are intentional. $8000-$8FFF is character-generator ROM; $9000-$9FFF contains memory-mapped video and I/O regions; $C000-$DFFF is BASIC ROM; and $E000-$FFFF is KERNAL ROM. The programmer’s map labels some expansion areas as RAM/ROM because the expansion port can host different devices. A cartridge that occupies an address window is not interchangeable with a RAM pack configured for that same window.
This is why product labels such as 8 KiB, 16 KiB, and 24 KiB need translation into blocks. VICE documents its 8 KiB profile as block 1, 16 KiB as blocks 1 and 2, and 24 KiB as blocks 1, 2, and 3. Its 3 KiB profile enables block 0. A profile called “all” enables the available expansion blocks, not a new contiguous address range.
Screen memory moves when large expansion is present
The visible screen is a 22-column by 23-row character area. Its start address changes with the configuration. The Commodore User Guide documents that an unexpanded VIC-20 and a machine with only the 3 KiB low-memory expansion place screen memory at decimal 7680, or $1E00. With 8 KiB or more in the large expansion area, the screen moves to decimal 4096, or $1000; BASIC program memory then begins at $1200, while the 3 KiB block is not used as BASIC program space.
The machine keeps a BASIC memory byte at location 648 containing the screen page. Multiplying PEEK(648) by 256 gives the screen base. This is safer than assuming that screen RAM is always at 7680:
10 SB=256*PEEK(648)
20 PRINT "SCREEN BASE:";SB
The same configuration change also affects the color-memory base documented by Commodore: the manual lists $9600 for no expansion or the 3 KiB case, and $9400 for the large-expansion case. Software that directly reads or writes screen and color memory should derive both locations from the active machine configuration rather than transplanting constants from a different VIC-20.
Reproduce the configuration without risking a physical machine
VICE’s documented xvic -memory option can start an unexpanded profile, the 3 KiB low block, or a named large-memory layout:
xvic -memory none
xvic -memory 3k
xvic -memory 16k
Run the BASIC diagnostic in each emulator instance and compare the printed screen base. The manual’s expected distinction is $1E00 for the unexpanded and 3 KiB cases, and $1000 for a configuration with at least 8 KiB in the large expansion area. This is a read-only test: it observes the BASIC screen pointer and does not overwrite screen, color, or expansion memory.
For a program that loads at a fixed address, match its documented memory requirement to the exact VICE profile or physical cartridge configuration. A 16 KiB profile is blocks 1 and 2 in the documented emulator mapping; it does not imply block 0 is available to BASIC. If a title or machine-language program expects a cartridge ROM at $A000, enabling RAM block 5 instead can alter what the CPU sees at that address. Inspect cartridge state and memory profile together.
Do not copy an expansion map from the Commodore 64. The VIC-20 has different built-in RAM, video hardware, and address decoding. Likewise, an emulator command line is evidence about VICE’s emulated configuration, not a guarantee about a modified board, a cartridge expander, or a different emulator. When debugging a real machine, record its model/board revision and the exact cartridge switches or expansion device.
The practical sequence is simple: identify the software’s target memory windows, select a matching expansion profile, query the screen pointer, and only then load code or use direct PEEK/POKE. The VIC-20’s small blocks make a consistent map more useful than a large headline RAM number.
Related:
- MAME Address Maps: Decoding Arcade Buses, Banks, Mirrors, and Handlers
- TI-99/4A GROM: Cartridge Addressing and GPL Execution
Sources:
- Commodore VIC-20 Programmer’s Reference Guide, scanned first edition, sixth printing
- Commodore VIC-20 User Guide, screen location and memory expansion discussion
- VICE Manual: VIC-20 memory configuration profiles and command-line options
- VICE VIC-20 memory mapping at immutable commit fa7f1e1ec4f1b97d00c5b8117e12a592992f7262