Nexen is a multi-system emulator supporting NES, SNES, Game Boy, GBA, SMS, PC Engine, and WonderSwan. This document provides a high-level overview of the codebase architecture.
Nexen/
├── Core/ # C++ emulation cores (this document)
│ ├── NES/ # Nintendo Entertainment System
│ ├── SNES/ # Super Nintendo
│ ├── Gameboy/ # Game Boy / Game Boy Color
│ ├── GBA/ # Game Boy Advance
│ ├── SMS/ # Sega Master System / Game Gear
│ ├── PCE/ # PC Engine / TurboGrafx-16
│ ├── WS/ # WonderSwan / WonderSwan Color
│ ├── Shared/ # Cross-platform shared code
│ ├── Debugger/ # Unified debugger framework
│ └── Netplay/ # Network play support
│
├── Utilities/ # Shared utility library
│ ├── Serializer # State save/load
│ ├── File I/O # VirtualFile, archives
│ ├── Graphics filters # HQ2x, xBRZ, NTSC, etc.
│ └── Platform abstraction
│
├── Core.Tests/ # C++ unit tests (Google Test)
├── Core.Benchmarks/ # Performance benchmarks (Google Benchmark)
│
├── InteropDLL/ # C++/C# interop layer
│ └── EmuApiHandler # Expose C++ API to .NET
│
├── UI/ # .NET UI application
│ ├── Views/ # Avalonia XAML views
│ ├── ViewModels/ # MVVM view models
│ └── Debugger/ # Debugger windows
│
└── Linux/ # Linux-specific code
┌─────────────────────────────────────────────────────────────────┐
│ UI Layer (C#/.NET) │
│ Avalonia cross-platform UI, debugger windows, settings, menus │
└─────────────────────────────────────────────────────────────────┘
│
│ InteropDLL (P/Invoke)
│
┌─────────────────────────────────────────────────────────────────┐
│ Emulator (C++) │
│ Main emulation controller - manages consoles, runs frames │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────┬───────────┼───────────┬───────────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ NES │ │ SNES │ │ GB │ │ GBA │ │ SMS/ │
│ Console │ │ Console │ │ Console │ │ Console │ │PCE/WS │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │ │
└───────────┴───────────┼───────────┴───────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Shared Infrastructure │
│ Serializer, Debugger, Settings, Video Output, Audio Mixing │
└─────────────────────────────────────────────────────────────────┘
Each emulated system follows a consistent pattern:
class [System]Console : public IConsole, public ISerializable {
// Owns all system components
unique_ptr<[System]Cpu> _cpu;
unique_ptr<[System]Ppu> _ppu;
unique_ptr<[System]MemoryManager> _memoryManager;
unique_ptr<BaseMapper> _mapper; // Cartridge hardware
// Main emulation loop
void Run(uint64_t runUntilMasterClock);
// Frame timing
void RunFrame();
// State management
void Serialize(Serializer& s) override;
};Base interface for all emulated systems:
class IConsole : public ISerializable {
virtual void Run(uint64_t masterClock) = 0;
virtual void Reset(bool softReset) = 0;
virtual ConsoleType GetConsoleType() = 0;
virtual double GetFps() = 0;
// ... video, audio, input interfaces
};All stateful objects implement serialization:
class ISerializable {
virtual void Serialize(Serializer& s) = 0;
};Cartridge hardware abstraction:
class BaseMapper : public ISerializable {
virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0;
virtual uint8_t ReadChr(uint16_t addr) = 0;
// ... banking, mirroring, IRQ
};Each system has a memory manager that routes reads/writes:
CPU Read/Write Request
│
▼
┌─────────────────────┐
│ Memory Manager │
│ ┌───────────────┐ │
│ │ Address Map │ │
│ │ $0000-$07FF → RAM
│ │ $2000-$2007 → PPU
│ │ $4000-$401F → APU/IO
│ │ $4020-$FFFF → Mapper
│ └───────────────┘ │
└─────────────────────┘
Nexen uses a master clock for precise timing:
// Each system has a master clock relationship
// NES: CPU runs at 1/3 master clock, PPU at master clock
// SNES: CPU varies, PPU at master clock
uint64_t _masterClock; // Absolute timing reference
void Console::Run(uint64_t targetClock) {
while (_masterClock < targetClock) {
// Step CPU
_cpu->Exec();
// PPU runs proportionally
_ppu->Run(_masterClock);
// APU runs at its rate
_apu->Run(_masterClock);
}
}The unified debugger supports all systems:
┌─────────────────────────────────────────────┐
│ Debugger Framework │
├─────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────────────────┐│
│ │ Breakpoints │ │ Disassembler ││
│ │ - Read │ │ - System-specific ││
│ │ - Write │ │ - Symbol support ││
│ │ - Execute │ │ - Code labels ││
│ └─────────────┘ └─────────────────────────┘│
│ ┌─────────────┐ ┌─────────────────────────┐│
│ │ Watch │ │ Trace Logger ││
│ │ - Registers │ │ - Per-instruction log ││
│ │ - Memory │ │ - Conditional logging ││
│ └─────────────┘ └─────────────────────────┘│
└─────────────────────────────────────────────┘
Save states use a bidirectional serializer:
void NesCpu::Serialize(Serializer& s) {
// Same code for save and load!
SV(_state.PC);
SV(_state.SP);
SV(_state.A);
SV(_state.X);
SV(_state.Y);
SV(_state.PS);
// Arrays
SVArray(_ram, sizeof(_ram));
// Nested objects
SV(_apu); // Calls _apu->Serialize(s)
}PPU Frame Buffer ──► Video Filter ──► Display Output
(raw pixels) (HQ2x/etc) (SDL/UI)
Filters:
- Raw/None
- NTSC composite simulation
- HQ2x/3x/4x
- xBRZ
- Scale2x/3x
- Various CRT shaders
┌─────────┐ ┌─────────┐ ┌─────────┐
│Channel 1│ │Channel 2│ │Channel N│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└──────┬──────┴──────┬──────┘
│ │
▼ ▼
┌─────────────────────────┐
│ Sound Mixer │
│ - Resampling │
│ - Volume/Balance │
│ - Low-pass filter │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Audio Output │
│ - SDL Audio / WASAPI │
└─────────────────────────┘
| System | CPU | Resolution | Audio |
|---|---|---|---|
| NES | 6502 (2A03) | 256×240 | 5 channels |
| SNES | 65816 | 256-512×224-478 | 8 channels (SPC700) |
| Game Boy | LR35902 | 160×144 | 4 channels |
| GBA | ARM7TDMI | 240×160 | 6 channels |
| SMS | Z80 | 256×192 | 3 channels (PSG) |
| PCE | HuC6280 | 256-512×224-242 | 6 channels |
| WonderSwan | V30MZ | 224×144 | 4 channels |
Windows:
- Visual Studio solution (Nexen.sln)
- MSBuild for C++ projects
- .NET SDK for UI
Linux:
- Makefile-based build
- GCC or Clang
- .NET SDK for UI
Dependencies:
- vcpkg for C++ dependencies (Google Test, Google Benchmark)
- NuGet for .NET dependencies
- Unit Tests:
Core.Tests/using Google Test (420+ tests) - Benchmarks:
Core.Benchmarks/using Google Benchmark (220+ benchmarks) - Integration Tests: RecordedRomTest for emulation accuracy
| File | Purpose |
|---|---|
Shared/Emulator.cpp |
Main emulator controller |
Shared/BaseConsole.h |
Console base class |
Utilities/Serializer.cpp |
State serialization |
InteropDLL/EmuApiHandler.cpp |
C++/C# bridge |
[System]/[System]Console.cpp |
Per-system main entry |
- NES-CORE.md - NES-specific documentation
- UTILITIES-LIBRARY.md - Utility library
- CODE-DOCUMENTATION-STYLE.md - Documentation standards
- CPP-DEVELOPMENT-GUIDE.md - C++ coding standards