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.
▶
1. What is CHIP-8?
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
| Register | Size | Description |
|---|---|---|
| V0-VF | 8-bit | 16 general purpose (VF = flag register) |
| I | 16-bit | Index/Address register |
| PC | 16-bit | Program Counter (starts at 0x200) |
| SP | 8-bit | Stack Pointer |
| DT | 8-bit | Delay Timer (decrements at 60Hz) |
| ST | 8-bit | Sound 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
| Opcode | Mnemonic | Description | Cat |
|---|---|---|---|
| 0NNN | SYS addr | Call machine code routine at NNN (ignored on modern) | flow |
| 00E0 | CLS | Clear the display | display |
| 00EE | RET | Return from subroutine | flow |
| 1NNN | JP addr | Jump to address NNN | flow |
| 2NNN | CALL addr | Call subroutine at NNN | flow |
| 3XKK | SE Vx, byte | Skip next instruction if Vx == KK | flow |
| 4XKK | SNE Vx, byte | Skip next instruction if Vx != KK | flow |
| 5XY0 | SE Vx, Vy | Skip next instruction if Vx == Vy | flow |
| 6XKK | LD Vx, byte | Set Vx = KK | load |
| 7XKK | ADD Vx, byte | Set Vx = Vx + KK | math |
| 8XY0 | LD Vx, Vy | Set Vx = Vy | load |
| 8XY1 | OR Vx, Vy | Set Vx = Vx OR Vy | math |
| 8XY2 | AND Vx, Vy | Set Vx = Vx AND Vy | math |
| 8XY3 | XOR Vx, Vy | Set Vx = Vx XOR Vy | math |
| 8XY4 | ADD Vx, Vy | Set Vx = Vx + Vy, VF = carry | math |
| 8XY5 | SUB Vx, Vy | Set Vx = Vx - Vy, VF = NOT borrow | math |
| 8XY6 | SHR Vx | Set Vx = Vx >> 1, VF = bit 0 | math |
| 8XY7 | SUBN Vx, Vy | Set Vx = Vy - Vx, VF = NOT borrow | math |
| 8XYE | SHL Vx | Set Vx = Vx << 1, VF = bit 7 | math |
| 9XY0 | SNE Vx, Vy | Skip next instruction if Vx != Vy | flow |
| ANNN | LD I, addr | Set I = NNN | load |
| BNNN | JP V0, addr | Jump to NNN + V0 | flow |
| CXKK | RND Vx, byte | Set Vx = random byte AND KK | math |
| DXYN | DRW Vx, Vy, n | Draw N-byte sprite at (Vx,Vy), VF = collision | display |
| EX9E | SKP Vx | Skip if key with value Vx is pressed | input |
| EXA1 | SKNP Vx | Skip if key with value Vx is NOT pressed | input |
| FX07 | LD Vx, DT | Set Vx = delay timer value | timer |
| FX0A | LD Vx, K | Wait for key press, store in Vx | input |
| FX15 | LD DT, Vx | Set delay timer = Vx | timer |
| FX18 | LD ST, Vx | Set sound timer = Vx | timer |
| FX1E | ADD I, Vx | Set I = I + Vx | math |
| FX29 | LD F, Vx | Set I = sprite addr for digit Vx | load |
| FX33 | LD B, Vx | Store BCD of Vx at I, I+1, I+2 | load |
| FX55 | LD [I], Vx | Store V0..Vx in memory starting at I | load |
| FX65 | LD Vx, [I] | Read V0..Vx from memory starting at I | load |
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.