A cycle-accurate Nintendo Entertainment System (NES) emulator written in PHP, implementing the 6502 CPU and PPU. It makes use of the PHP-GLFW extension for OpenGL graphics rendering via the VISU framework.
This is a technical demonstration project showcasing low-level emulation techniques in PHP. The emulator prioritises accuracy over performance, implementing cycle-accurate CPU execution and proper PPU timing for authentic NES behaviour.
This is a technical demo. Do not expect high performance or production-ready gameplay. The project is intended for educational purposes and as a proof-of-concept for emulation in PHP.
- PHP 8.5 (required - no earlier versions supported)
- PHP-GLFW extension (for graphics rendering via OpenGL)
- Composer (for dependency management)
Disable Xdebug for acceptable performance. Running the emulator with Xdebug enabled will result in extremely poor performance. Ensure Xdebug is disabled when running the emulator:
php -d xdebug.mode=off bin/start.php path/to/rom.nesOr disable it in your php.ini:
xdebug.mode=off- Clone the repository:
git clone https://github.com/oliverearl/nes-php-glfw.git
cd nes-emulator- Install dependencies:
composer install- Ensure PHP-GLFW extension is installed and enabled.
For more information on getting this installed on your platform, refer to their website for easy instructions.
Run the emulator with a NES ROM file:
php bin/start.php path/to/rom.nesIf you don't start the emulator with a loaded ROM, it will display a graphical pattern. You can also drag and drop a ROM file onto the window to load it.
Enable performance debugging to see detailed timing metrics by passing the --profile flag:
php bin/start.php path/to/rom.nes --profileThis will output performance statistics every second to stderr, showing:
- Average time spent in update/draw cycles
- CPU, PPU, and rendering breakdown
- NES frames per second
- Iterations per update
Example debug output:
[NES Debug] Updates: 28 (avg 35.61ms) | Draws: 3 (avg 0.95ms) | NES frames: 28 | Iters/update: 9696
[NES Debug] Breakdown: CPU 13.80ms | PPU 5.63ms | Render 14.02ms (per update avg)
- Arrow Keys: D-Pad
- Z: A Button
- X: B Button
- Enter: Start
- Backspace: Select
-
6502 CPU Emulation
- Official and unofficial opcodes
- Cycle-accurate execution
- Interrupt handling (NMI, IRQ)
-
PPU (Picture Processing Unit)
- Background rendering
- Sprite rendering with priority
- Proper VRAM and palette management
- VBlank timing and interrupts
-
Memory Subsystem
- Accurate RAM mirroring
- Memory-mapped I/O
- Direct Memory Access (DMA)
-
Input Handling
- Keyboard controls via VISU framework
- Proper controller polling
-
Graphics
- OpenGL rendering via PHP-GLFW
- Authentic NES colour palette
- 256x224 resolution output
- Audio Processing Unit (APU)
- Mapper support beyond NROM (Mapper 0)
- Save states
- Controller configuration
- Performance optimisations
The emulator is structured around the actual NES hardware architecture:
src/Cpu/- 6502 CPU implementationsrc/Graphics/- PPU and rendering pipelinesrc/Bus/- Memory buses and addressingsrc/Cartridge/- ROM loading and cartridge emulationsrc/Input/- Controller input handling
The project includes comprehensive test coverage with PHPUnit:
# Run all tests
composer test
# Run with coverage
composer test:coverage
# Run static analysis
composer phpstan
# Check code style
composer pintThis project follows strict code quality standards:
- PHPStan for static analysis
- Laravel Pint for code formatting (PER)
- PHPUnit for comprehensive testing (234+ tests, 266,000+ assertions)
AI-assisted development guidelines are available for Claude, Copilot/Codex, JetBrains Junie, and Cursor.
- CPU: ~1.79 MHz (NTSC)
- PPU: 3x CPU speed
- Frame rate: ~60 FPS (262 scanlines per frame)
-
CPU Address Space: $0000-$FFFF
- $0000-$07FF: 2KB internal RAM (mirrored)
- $2000-$2007: PPU registers (mirrored)
- $4000-$4017: APU and I/O registers
- $8000-$FFFF: Cartridge ROM space
-
PPU Address Space: $0000-$3FFF
- $0000-$1FFF: Pattern tables
- $2000-$2FFF: Nametables
- $3F00-$3F1F: Palette RAM
This project is open source. See the LICENSE file for details.
Built with the VISU framework for graphics rendering and the PHP-GLFW extension for OpenGL bindings.
Inspiration and PHP reference was drawn from various PHP emulation projects, including:
- This incredibly impressive Chip8 emulator using Visu and PHP-GLFW
- A PHP emulator that renders to the terminal
- A similar Game Boy emulator that also renders to the terminalhttps://github.com/gabrielrcouto/php-terminal-gameboy-emulator)
- A Hello World ROM that is used as as test fixture
Nintendo, NES, Super Mario Bros, and related logos are trademarks of Nintendo. This project is not affiliated with or endorsed by Nintendo. All trademarks and copyrights are the property of their respective owners.
Do not distribute copyrighted ROMs!
Note: This is a technical demonstration project. The focus is on accuracy and educational value, not on performance or completeness. Contributions and feedback are welcome.
