Memory Layout
CHIP-8 has 4 kilobytes of memory — 4096 bytes, addressable from 0x000 to 0xFFF. That is the entire address space.
The map
0x000 ┌─────────────────────┐
│ Reserved │ interpreter, font sprites (0x000–0x04F)
0x1FF ├─────────────────────┤
0x200 │ Program (ROM) │ ← all programs load here
│ │
0xFFF └─────────────────────┘
The first 512 bytes (0x000–0x1FF) were reserved for the original CHIP-8 interpreter that ran on the host machine. ROMs always start at 0x200 — this is a hard convention that every CHIP-8 program follows without exception. PC is initialized to 0x200 for this reason.
The range 0x000–0x04F is used by us for the built-in font sprites (16 digits × 5 bytes). See Font Sprites.
The Memory struct
#![allow(unused)] fn main() { pub const MEMORY_SIZE: usize = 4096; pub const PROGRAM_START: u16 = 0x200; pub struct Memory { ram: [u8; MEMORY_SIZE], // private — access only through read/write } }
ram is private. Nothing outside memory.rs can touch it directly. All reads and writes go through explicit methods:
#![allow(unused)] fn main() { impl Memory { pub fn read(&self, address: u16) -> u8 { self.ram[address as usize] } pub fn write(&mut self, address: u16, value: u8) { self.ram[address as usize] = value; } } }
This encapsulation means we can add bounds checking or memory-mapped I/O later without changing any other code.
Loading a ROM
#![allow(unused)] fn main() { pub fn load_rom(&mut self, data: &[u8]) { let start = PROGRAM_START as usize; self.ram[start..start + data.len()].copy_from_slice(data); } }
data is a byte slice — a reference to a sequence of bytes of any length. The ROM is placed starting at 0x200. copy_from_slice copies every byte from data into the correct position in RAM.
Memory is owned by the CPU
Memory is a field of Cpu, not a global. This mirrors how the hardware works — the CPU has direct access to its memory. The CPU accesses memory through self.memory.read(addr) and self.memory.write(addr, value).
Rust concepts used here: The
&[u8]parameter type forload_romis explained in Slices and Ranges. The privateramfield andpubmethods are covered in the same chapter. File and module organization is in Modules.