A home computer game had a fixed budget of memory, and everything competed for it: the program, the graphics, the music, the screen itself, and whatever the machine’s own system software kept for itself. Memory management on these machines meant deciding, byte by byte, where things went and what was left out. Sometimes what was left out was a whole level.
The budget
The numbers on the box were not the numbers a programmer could use.
- Commodore 64. 64K of RAM, but a C64 switched on with “38911 BASIC BYTES FREE”. Commodore’s Programmer’s Reference Guide explains the gap: the machine also has 20K of ROM and 4K of input/output chips, all inside a 64K address space, so some of the RAM sits hidden behind them.
- ZX Spectrum 48K. The screen alone takes 6,912 bytes, starting at address 16384, before the system variables, the BASIC program and its variables. Steven Vickers’ manual describes BASIC’s areas as packed end to end, each “only large enough for the information that they actually contain”, with everything above shuffled up when a line or variable is added.
- NES. 2K of work RAM in the console. The rest of a game’s memory came on the cartridge, as ROM switched in by a mapper; see bank switching.
- Amiga 500. 512K of chip memory, shared between the processor and the custom chips that draw the screen and play the sound.
Taking memory back from the system
A C64 game did not need BASIC, and often did not need the KERNAL either. Three bits of the 6510’s own port at address 1 bank the BASIC ROM, the KERNAL ROM and the character ROM in and out, with RAM underneath each. Commodore’s guide points out a convenience: “a WRITE (a POKE) to a ROM location will store data in the RAM ‘under’ the ROM”, so “a hi-resolution screen [can] be kept underneath a ROM, and be changed without having to bank the screen back into the processor address space”. A program that switches both big ROMs out has nearly all 64K to itself, but must then supply its own interrupt handling. The bank switching entry has the port settings.
There is a second constraint on where things go. The C64’s VIC-II “can access (‘see’) 16K of memory at a time”, so the screen, the character set and the sprite shapes it draws must all sit in the same 16K bank, wherever the program keeps everything else.
Spending it
ZZAP!64’s 1986 interview with Chris Butler shows the budget being spent. His conversion of Commando for Elite was, he said, “completely finished”, until Rob Hubbard arrived to write the music: “he said that he needed about 6K for the music, and there wasn’t room. So Steve Wilcox, the man, said, ‘Right — hack out level three.’”
Butler’s next job was Space Harrier, and he expected the same problem: “you’re going to fill at least 64K with graphics and then find you’ve got no memory left.” His plan was a format decision: “I’ll be using character graphics rather than sprites”, which he expected to save a great deal of memory. A sprite image stores every pixel of every frame; a character set stores each 8-by-8 block once and builds larger shapes by repeating its codes, a byte per position.
That trade, describing a picture as references to shared pieces, runs through most of the techniques that saved memory:
- Tiles and characters. A screen of tile numbers plus one set of tile patterns is far smaller than a bitmap of the same screen.
- Compression. Data stays packed until it is needed, at the cost of a decoder and the time it takes.
- Lookup tables go the other way, spending memory to save time. Choosing between a table and a calculation is a memory decision too.
- Self-modifying code stores a changing address inside the instruction that uses it, saving both a variable and the time to fetch it.
Fast memory and the rest
Not all memory cost the same. On the 6502 the first 256 bytes, zero page, can be reached with a one-byte address. MOS’s programming manual introduced zero-page addressing “to allow the user a shortening of both memory space and execution time, particularly when dealing with working registers and intermediate values”: two bytes and three cycles for a load, against three bytes and four cycles for anywhere else. On the C64 the BASIC interpreter and KERNAL use most of zero page. Sheldon Leemon’s Mapping the Commodore 64 lists four bytes, $FB-$FE, as “Four Free Bytes of Zero Page for User Programs”, so a machine-code program that keeps BASIC and the KERNAL running saves them for the pointers it uses most.
The Amiga divides its memory by who can reach it. Chip memory is “memory accessible to the Amiga custom chips”; fast memory is “not accessable by the custom chips”, and Commodore’s manual warns that “care must be taken to present only chip memory address to the custom chips”. Screens, sprite images, sound samples and anything else the custom chips fetch by DMA must be in chip memory. On an expanded machine, a program has to ask for chip memory for that data, because the custom chips cannot fetch it from anywhere else.
Fixed places for everything
With no memory to spare for bookkeeping, a game can give each kind of object a fixed table of slots, sized for the worst case and reused as objects come and go, instead of allocating memory while it runs. Nothing can then run out at an awkward moment, because the worst case was paid for in advance. The object pooling entry covers the pattern.
Sources
- Commodore, Commodore 64 Programmer’s Reference Guide (1982), pp. 260-261 (memory management, the 6510 port and RAM under ROM), p. 101 (the VIC-II’s 16K) and p. 109 (“38K available for a BASIC program”).
- Steven Vickers, ZX Spectrum BASIC Programming (Sinclair Research, 1982), chapter 20 (the 6,912-byte display file at 16384) and chapter 24 (how BASIC’s areas are laid out).
- Gary Penn, “The Butler Did It”, interview with Chris Butler, ZZAP!64 issue 17, September 1986, pp. 104-105.
- MOS Technology, MCS6500 Microcomputer Family Programming Manual (1976), section 5.6, p. 61: zero page addressing.
- Sheldon Leemon, Mapping the Commodore 64 (COMPUTE! Books, 1984), entry for locations 251-254 (
$FB-$FE): the free zero-page bytes. - Commodore-Amiga, Amiga Hardware Reference Manual (1989 edition), glossary, pp. 366 and 368: chip memory and fast memory.