Retro Emulator Workshop

A hands-on guide to building CHIP-8 and Apple-1 emulators from scratch

1. What is CHIP-8?

CHIP-8 is an interpreted programming language developed in the mid-1970s by Joseph Weisbecker for the COSMAC VIP and Telmac 1800 microcomputers. It was designed to make game programming easier on those early systems. Today, CHIP-8 is the classic "first emulator project" — a rite of passage for anyone interested in emulation development. Its simplicity (only 35 opcodes!) makes it approachable, while still teaching all the fundamental concepts.

RAM:4 KB (4096 bytes)
Registers:16 general (V0-VF) + I, PC, SP
Display:64 x 32 pixels, monochrome
Input:16-key hexadecimal keypad
Timers:Delay Timer, Sound Timer (60 Hz)
Stack:16 levels of nesting
Clock:~500 Hz typical
Programs:Loaded at address 0x200

2. Architecture Overview

Memory Map

0x000 - 0x1FFInterpreter / Font Data
0x200 - 0xE9FProgram / Data Space
0xEA0 - 0xEFFStack / Internal Use
0xF00 - 0xFFFDisplay Refresh (optional)

Registers

RegisterSizeDescription
V0-VF8-bit16 general purpose (VF = flag register)
I16-bitIndex/Address register
PC16-bitProgram Counter (starts at 0x200)
SP8-bitStack Pointer
DT8-bitDelay Timer (decrements at 60Hz)
ST8-bitSound Timer (beeps when > 0, decrements at 60Hz)

Display

64x32 monochrome pixels. Sprites are XOR'd onto the display — if any pixel is erased, VF is set to 1 (collision detection). Sprites are always 8 pixels wide and 1-15 pixels tall.

Keypad Layout

1
2
3
C
4
5
6
D
7
8
9
E
A
0
B
F

Original layout — typically mapped to keyboard: 1234/QWER/ASDF/ZXCV

3. Opcode Table (35 Instructions)

Categories: ● math● display● flow● load● input● timer
OpcodeMnemonicDescriptionCat
0NNNSYS addrCall machine code routine at NNN (ignored on modern)flow
00E0CLSClear the displaydisplay
00EERETReturn from subroutineflow
1NNNJP addrJump to address NNNflow
2NNNCALL addrCall subroutine at NNNflow
3XKKSE Vx, byteSkip next instruction if Vx == KKflow
4XKKSNE Vx, byteSkip next instruction if Vx != KKflow
5XY0SE Vx, VySkip next instruction if Vx == Vyflow
6XKKLD Vx, byteSet Vx = KKload
7XKKADD Vx, byteSet Vx = Vx + KKmath
8XY0LD Vx, VySet Vx = Vyload
8XY1OR Vx, VySet Vx = Vx OR Vymath
8XY2AND Vx, VySet Vx = Vx AND Vymath
8XY3XOR Vx, VySet Vx = Vx XOR Vymath
8XY4ADD Vx, VySet Vx = Vx + Vy, VF = carrymath
8XY5SUB Vx, VySet Vx = Vx - Vy, VF = NOT borrowmath
8XY6SHR VxSet Vx = Vx >> 1, VF = bit 0math
8XY7SUBN Vx, VySet Vx = Vy - Vx, VF = NOT borrowmath
8XYESHL VxSet Vx = Vx << 1, VF = bit 7math
9XY0SNE Vx, VySkip next instruction if Vx != Vyflow
ANNNLD I, addrSet I = NNNload
BNNNJP V0, addrJump to NNN + V0flow
CXKKRND Vx, byteSet Vx = random byte AND KKmath
DXYNDRW Vx, Vy, nDraw N-byte sprite at (Vx,Vy), VF = collisiondisplay
EX9ESKP VxSkip if key with value Vx is pressedinput
EXA1SKNP VxSkip if key with value Vx is NOT pressedinput
FX07LD Vx, DTSet Vx = delay timer valuetimer
FX0ALD Vx, KWait for key press, store in Vxinput
FX15LD DT, VxSet delay timer = Vxtimer
FX18LD ST, VxSet sound timer = Vxtimer
FX1EADD I, VxSet I = I + Vxmath
FX29LD F, VxSet I = sprite addr for digit Vxload
FX33LD B, VxStore BCD of Vx at I, I+1, I+2load
FX55LD [I], VxStore V0..Vx in memory starting at Iload
FX65LD Vx, [I]Read V0..Vx from memory starting at Iload
35 of 35 opcodes shown

4. Step-by-Step Implementation Guide

5. Try It — Mini CHIP-8 Demo

A bouncing digit demo. The hex digit changes each time it bounces off a wall. Uses font sprites and basic collision logic.