Overview

This project is a Chip8 emulator implemented in C++. It aims to faithfully emulate the Chip8 virtual machine, which was originally designed to run simple games on 1970s microcomputers. The emulator uses SDL3 for graphics rendering and window management, allowing Chip8 games to be played with modern graphical output.

Key features:
- Written in modern C++
- SDL3-based window and rendering support (Note: integrating with SDL3 is completed, it is open to create examples with actual Chip8 games)
- Loads and executes Chip8 ROMs
- Modular code structure for easy extension

The project is currently under development. Contributions and feedback

About Chip8 Emulator

A Chip8 emulator is a software program that mimics the behavior of the original Chip8 virtual machine, allowing classic Chip8 games to run on modern hardware. For an emulator to function, it must accurately implement the Chip8 system’s core components:

  • CPU: Executes Chip8 instructions and manages program flow.

  • Memory: Stores program code, data, and system variables.

  • Display: Renders graphics output, typically a 64x32 monochrome screen.

  • Input: Handles key presses from the user.

  • Timers: Implements delay and sound timers as specified by the Chip8 architecture.

Emulator Structure and Approach

A well-structured emulator separates these responsibilities into distinct modules or classes. In this project, the approach is modular and extensible:

  • Core Emulator Logic: Handles instruction decoding, execution, and state management.

  • Graphics Module: Uses SDL3 for window creation and rendering the Chip8 display.

  • Input Handling: Maps keyboard input to Chip8 keys.

  • ROM Loader: Loads Chip8 game files into emulator memory.

  • Timers: Implements the delay and sound timers.

This modular design makes it easier to maintain, extend, and test individual components. SDL3 integration is used for graphics and input, providing a modern interface for running Chip8 games. The codebase is organized for clarity, with separate files and directories for core logic, examples, and documentation.

Core Emulator Logic

Fetch, Decode, Execute

A Chip8 emulator operates in a cycle known as "fetch-decode-execute." This cycle is fundamental to interpreting and running Chip8 programs:

  • Fetch: The emulator reads the next instruction (opcode) from memory, typically 2 bytes at a time.

  • Decode: The opcode is analyzed to determine which instruction it represents and what operands it requires.

  • Execute: The corresponding instruction logic is performed, updating the emulator state (registers, memory, timers, display, etc.).

In this project, the core logic is implemented in include/chip8/core.hpp. The file manages the main emulation loop, handling memory access, program counter updates, and invoking the instruction set. The fetch step reads the opcode from memory, decode uses helper structures to interpret the opcode and extract operands, and execute dispatches the correct instruction handler.

Flexible Instruction Set Expansion

The instruction set is designed for flexibility and extensibility. In include/chip8/details/instruction.hpp, instructions are defined as modular entities, allowing developers to easily add, modify, or extend supported instructions. Each instruction can be registered with its opcode pattern and handler function, making it straightforward to support new instructions or custom behaviors.

This modular approach is tightly integrated with:

  • include/chip8/details/operands.hpp: Provides robust operand extraction and validation, ensuring instructions receive the correct data types and values.

  • include/chip8/details/opcodes.hpp: Defines opcode patterns and utilities for matching and decoding instructions.

By separating opcode decoding, operand handling, and instruction execution, the emulator codebase remains clean and maintainable. Developers can expand the instruction set by simply adding new instruction definitions and handlers, without modifying the core emulation loop. This design encourages experimentation and supports future enhancements.

Core

Details on design and implementation of a clean API for the core emulator logic, allowing users to interact with the emulator without needing to understand its internal workings can be found below. The APIs provide methods for fetching, decoding, and executing instructions, as well as loading programs and accessing emulator resources.