A CHIP-8 interpreter written in C++20 with SDL2 rendering. Supports the full standard CHIP-8 instruction set and runs classic ROMs including Pong, Breakout, Tetris, and more.
CHIP-8 is an interpreted programming language developed in the mid-1970s by Joseph Weisbecker for the COSMAC VIP microcomputer. It was designed to make game development easier on early home computers. CHIP-8 programs run on a virtual machine with:
- 4096 bytes of memory
- 16 8-bit general purpose registers (V0–VF)
- A 16-bit index register (I)
- A program counter starting at address 0x200
- A 16-level call stack
- Two timers (delay and sound) that count down at 60Hz
- A 64×32 monochrome display
- A 16-key hexadecimal keypad
- Full CHIP-8 instruction set (35 opcodes)
- 60Hz timer emulation
- Keyboard input with standard CHIP-8 key mapping
- Scalable display via SDL2
- Generic renderer that is not tied to CHIP-8 specifically — reusable for other emulators
- Sprite clipping at screen edges
- C++20 compiler
- CMake 3.20+
- SDL2 (via vcpkg)
- vcpkg with
x64-mingw-dynamictriplet (for MinGW/CLion on Windows)
git clone https://github.com/microsoft/vcpkg C:/vcpkg
cd C:/vcpkg
bootstrap-vcpkg.bat
vcpkg install sdl2:x64-mingw-dynamicgit clone https://github.com/yourusername/Chip8Emulator
cd Chip8EmulatorIn CLion go to Settings → Build, Execution, Deployment → CMake and set CMake options to:
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-mingw-dynamic
Open the project in CLion and hit Run, or from the command line:
cmake -B build
cmake --build buildCopy C:/vcpkg/installed/x64-mingw-dynamic/bin/SDL2.dll into the same folder as Chip8Emulator.exe so it runs standalone.
Place your .ch8 ROM file in a roms/ folder next to the executable, then update main.cpp:
chip8.loadROM("./roms/YourROM.ch8");Rebuild and run. ROMs are not included in this repository — you can find public domain CHIP-8 ROMs at various emulation archives online.
CHIP-8 uses a 16-key hexadecimal keypad. This emulator maps it to the following keyboard layout:
CHIP-8 Key Keyboard
---------- --------
1 2 3 C 1 2 3 4
4 5 6 D Q W E R
7 8 9 E A S D F
A 0 B F Z X C V
Press Escape to quit.
Chip8Emulator/
├── Chip8.h # CHIP-8 class declaration
├── Chip8.cpp # CHIP-8 interpreter implementation
├── renderer.h # Generic SDL2 renderer declaration
├── renderer.cpp # SDL2 renderer implementation
├── main.cpp # Main loop, input handling, timing
├── CMakeLists.txt # Build configuration
└── roms/ # Place your .ch8 ROM files here
The core interpreter. Responsible for:
- Loading ROMs into memory at address
0x200 - Fetching, decoding, and executing opcodes each cycle
- Managing all registers, stack, timers, and display state
- Exposing the display buffer and draw flag to the renderer
- Accepting keypad state updates from the input system
A generic SDL2 renderer that knows nothing about CHIP-8 specifically. It accepts any pixel buffer with a given width, height, and scale factor. Each logical pixel is drawn as a scaled rectangle, making it reusable for other emulator projects.
The main loop runs at ~60fps with approximately 10 CPU cycles per frame (~600Hz effective clock speed). Timers are decremented every 16ms independently of the CPU cycle rate, matching the CHIP-8 spec of 60Hz timer updates.
| Opcode | Description |
|---|---|
00E0 |
Clear display |
00EE |
Return from subroutine |
1NNN |
Jump to address NNN |
2NNN |
Call subroutine at NNN |
3XNN |
Skip if VX == NN |
4XNN |
Skip if VX != NN |
5XY0 |
Skip if VX == VY |
6XNN |
Set VX = NN |
7XNN |
Set VX = VX + NN |
8XY0 |
Set VX = VY |
8XY1 |
Set VX = VX OR VY |
8XY2 |
Set VX = VX AND VY |
8XY3 |
Set VX = VX XOR VY |
8XY4 |
Set VX = VX + VY, VF = carry |
8XY5 |
Set VX = VX - VY, VF = no borrow |
8XY6 |
Shift VX right by 1, VF = shifted bit |
8XY7 |
Set VX = VY - VX, VF = no borrow |
8XYE |
Shift VX left by 1, VF = shifted bit |
9XY0 |
Skip if VX != VY |
ANNN |
Set I = NNN |
BNNN |
Jump to NNN + V0 |
CXNN |
Set VX = random AND NN |
DXYN |
Draw N-byte sprite at (VX, VY), VF = collision |
EX9E |
Skip if key VX is pressed |
EXA1 |
Skip if key VX is not pressed |
FX07 |
Set VX = delay timer |
FX0A |
Wait for key press, store in VX |
FX15 |
Set delay timer = VX |
FX18 |
Set sound timer = VX |
FX1E |
Set I = I + VX |
FX29 |
Set I = font sprite address for digit VX |
FX33 |
Store BCD of VX at I, I+1, I+2 |
FX55 |
Store V0–VX in memory starting at I |
FX65 |
Load V0–VX from memory starting at I |
- Sound timer is tracked but no audio is produced (no SDL audio implementation)
- CHIP-8 has two conventions for shift opcodes (8XY6/8XYE) — this emulator uses VX directly rather than copying VY first, which is the more common modern interpretation
- Some ROMs may behave unexpectedly depending on which CHIP-8 quirks they were written for
MIT License. Feel free to use, modify, and distribute.