A GameBoy (DMG-01) emulator written in Python using Pygame and NumPy.
- CPU: Accurate LR35902 instruction set implementation with a fast opcode dispatch table.
- Memory: Support for common Memory Bank Controllers (MBC0, MBC1, MBC2, MBC3, MBC5).
- Video: PPU with support for Background, Window, and Sprites (OBJ). High-performance rendering using NumPy vectorization.
- Audio: APU implementation with 4 channels (Pulse 1, Pulse 2, Wave, Noise), stereo output, and volume envelopes.
- Input: Configurable keyboard mapping via Pygame.
- Bootloader: Support for original DMG boot ROM (
DMG_ROM.bin).
Writing an emulator in pure CPython that maintains an unthrottled 60 FPS is notoriously difficult due to the Global Interpreter Lock (GIL) and function-call overhead.
To achieve real-time performance, we relied on an arsenal of aggressive, non-idiomatic optimizations, including:
- Meta-Programmed Register Inlining: Regex scripts that rewrite the emulator's Python source code to strip out dictionary and property lookups.
- Flat-Earth Memory: Shadowing MBC ROM banks and Echo RAM into a monolithic C-backed
bytearrayto eliminate bounds-checking overhead. - Vectorized Scanlines: Offloading PPU pixel and sprite rendering to bulk array operations in C via NumPy.
- Audio-Slaved Synchronization: Hooking the emulator's execution loop directly to the soundcard's hardware DAC clock via PyAudio ring buffers to eliminate OS sleep drift.
Read the full technical breakdown in ARCHITECTURE.md.
The emulator includes a synthetic CPU benchmark suite (benchmark_cpu.py) to measure the raw throughput of the execution engine. Measurements are taken on an M-class processor using standard CPython 3.9 (no JIT, no C-extensions for the CPU).
To achieve 100% real-time emulation, the CPU must sustain 4.19 million cycles per second.
The engine currently comfortably exceeds real-time requirements across all execution branches:
| Instruction Category | Operations per second | Emulated Cycles per second | Real-time Multiple |
|---|---|---|---|
| NOP Dispatch (Peak throughput) | ~1.6 Million ops/s | ~6.3 Million Hz | 1.5x speed |
| JUMP Dispatch (Control Flow) | ~1.4 Million ops/s | ~18.9 Million Hz | 4.5x speed |
| CALL/RET Trampoline (Stack) | ~875,000 ops/s | ~17.5 Million Hz | 4.1x speed |
| 16-bit Math (HL, BC, DE) | ~820,000 ops/s | ~7.7 Million Hz | 1.8x speed |
| 8-bit Math (ADD, SUB, XOR) | ~880,000 ops/s | ~5.3 Million Hz | 1.2x speed |
| High I/O Load (Hardware Regs) | ~890,000 ops/s | ~9.8 Million Hz | 2.3x speed |
Note: Real-world emulation throughput is bounded by the PPU rendering speed and audio-sync thread locks. Without an audio sink restricting the frame-rate, the raw logic engine will naturally exceed 60 FPS.
- Python 3.10+
- [Optional]
sounddevicefor audio support.
-
Clone the repository:
git clone https://github.com/yourusername/pygameboy.git cd pygameboy -
Create and activate a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install pygame numpy sounddevice
-
[Optional] Place the original GameBoy boot ROM in the root directory as
DMG_ROM.bin.
Run the emulator by providing a path to a GameBoy ROM:
python emulator.py path/to/your/rom.gb| GameBoy | Keyboard |
|---|---|
| D-Pad | Arrow Keys |
| A | Z |
| B | X |
| Start | Enter |
| Select | Space / Right Shift |
--scale N: Set the window scale factor (default: 4).--no-audio: Disable audio output.--verbose: Enable verbose CPU logging.--profile: Enable opcode profiling.
emulator.py: Main entry point, UI loop, and system integration.cpu/: CPU core and opcode definitions.memory.py: Memory bus and mapping logic.video.py: PPU implementation and scanline renderer.apu.py: APU implementation and audio synthesis.mbc.py: Memory Bank Controller implementations.joypad.py: Input handling.clock.py: System timing and synchronization.
- GB Opcodes Table (Interactive)
- GameBoy Opcode Summary
- Opcodes JSON
- RGBDS Instruction Reference
- GameBoy CPU Manual (Gekkio)
- Improve PPU timing accuracy (Pixel FIFO).
- Complete STAT interrupt implementation.
- Implement Pulse 1 Sweep in APU.
- Support for MBC3 Real-Time Clock (RTC).
- GameBoy Color (CGB) support.
- Save state support.
This project is open-source and available under the MIT License.