This document covers Nexen's comprehensive debugging subsystem, which provides powerful tools for reverse engineering and development across all supported platforms.
Debugger Architecture
═════════════════════
┌─────────────────────────────────────────────────────────────────┐
│ Debugger │
│ (Central coordinator for all debugging features) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────┴─────────┬────────────────┬────────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌───────────┐ ┌────────────┐
│ IDebugger│ │ Disassembler │ │ScriptMgr │ │ CDL/Label │
│ per-CPU │ │ multi-CPU │ │ Lua API │ │ Managers │
└──────────┘ └──────────────┘ └───────────┘ └────────────┘
│
├── BreakpointManager
├── CallstackManager
├── ExpressionEvaluator
├── TraceLogger
├── StepBackManager
└── EventManager
Core/Debugger/
├── Core Components
│ ├── Debugger.h/cpp - Main debugger class
│ ├── IDebugger.h - Per-CPU debugger interface
│ ├── DebugTypes.h - Type definitions
│ └── DebugUtilities.h - Helper utilities
│
├── Breakpoints
│ ├── Breakpoint.h/cpp - Breakpoint definition
│ ├── BreakpointManager.h/cpp - Breakpoint management
│ └── FrozenAddressManager.h - Memory freeze support
│
├── Disassembly
│ ├── Disassembler.h/cpp - Multi-CPU disassembler
│ ├── DisassemblyInfo.h/cpp - Disassembly metadata
│ ├── DisassemblySearch.h/cpp - Search functionality
│ ├── Base6502Assembler.h/cpp - 6502/65816 assembler
│ └── IAssembler.h - Assembler interface
│
├── Expression Evaluation
│ ├── ExpressionEvaluator.h/cpp - Core evaluator
│ ├── ExpressionEvaluator.Nes.cpp - NES registers
│ ├── ExpressionEvaluator.Snes.cpp - SNES registers
│ ├── ExpressionEvaluator.Spc.cpp - SPC700 registers
│ ├── ExpressionEvaluator.Gameboy.cpp - GB registers
│ ├── ExpressionEvaluator.Gba.cpp - GBA/ARM registers
│ ├── ExpressionEvaluator.Sms.cpp - SMS/Z80 registers
│ ├── ExpressionEvaluator.Pce.cpp - PC Engine registers
│ ├── ExpressionEvaluator.Ws.cpp - WonderSwan registers
│ ├── ExpressionEvaluator.Gsu.cpp - Super FX registers
│ ├── ExpressionEvaluator.Cx4.cpp - Cx4 registers
│ └── ExpressionEvaluator.*.cpp - Other CPUs
│
├── Tracing & Logging
│ ├── BaseTraceLogger.h - Trace logger base
│ ├── ITraceLogger.h - Trace logger interface
│ ├── TraceLogFileSaver.h - File output
│ └── CallstackManager.h/cpp - Call stack tracking
│
├── Code/Data Logging
│ ├── CodeDataLogger.h/cpp - CDL core
│ ├── CdlManager.h/cpp - CDL file management
│ └── AddressInfo.h - Address mapping
│
├── Memory Tools
│ ├── MemoryDumper.h/cpp - Memory access
│ ├── MemoryAccessCounter.h/cpp - Access statistics
│ └── Profiler.h/cpp - Performance profiling
│
├── PPU Tools
│ ├── PpuTools.h/cpp - Graphics debugging
│ └── BaseEventManager.h/cpp - Event logging
│
├── Scripting
│ ├── ScriptManager.h/cpp - Script management
│ ├── ScriptHost.h/cpp - Script execution
│ ├── ScriptingContext.h/cpp - Script context
│ ├── LuaApi.h/cpp - Lua bindings
│ └── LuaCallHelper.h/cpp - Lua utilities
│
└── Step Execution
├── StepBackManager.h/cpp - Rewind debugging
└── DebugBreakHelper.h - Break helpers
The Genesis debugger runtime now exposes deterministic bridge tooling surfaces through debug memory read/write paths in GenesisMemoryManager.
$a12000-$a1201fSega CD bridge window (debug read/write supported)$a13000-$a1301fSega CD bridge lane 2 window (debug read/write supported)$a14000-$a1401fSega CD bridge lane 3 window (debug read/write supported)$a15000-$a1501f32X bridge window (debug read/write supported)$a16000-$a1601fSega CD bridge lane 5 window (debug read/write supported)$a18000-$a1801fSega CD bridge lane 6 window (debug read/write supported)
$a12016Sega CD tooling event-count byte (low byte)$a12017Sega CD tooling event-count byte (high byte)$a12018Debug-lane telemetry count byte (low byte)$a12019Debug-lane telemetry digest byte (low byte)$a1501832X tooling event-count byte (low byte)$a1501932X tooling event-count byte (high byte)$a1201aSega CD tooling capability byte$a1201bSega CD tooling digest byte$a1201cControl port 1 deterministic capability byte$a1201dControl port 1 deterministic digest byte$a1201eControl port 2 deterministic capability byte$a1201fControl port 2 deterministic digest byte
These status bytes are intended for parity and regression checks in debugger-facing validation workflows and are replay-stable across save/load when the same write/read sequence is applied.
The debug memory path also surfaces Genesis IO and Z80 handshake windows with deterministic behavior for parity validation:
$a10000-$a1001fIO window (version/data/control/ext registers)$a11100-$a11101Z80 bus-request handshake window$a11200-$a11201Z80 reset handshake window
Additional debugger parity windows are now exposed through Genesis debug memory access paths:
$a00000-$a0ffffZ80 memory window (ownership-aware debug parity)$c00000-$c0001fVDP/PSG window (null-safe debug path when VDP backend is unavailable)
Debug writes to controller control registers ($a10009/$a1000b/$a1000d) and handshake control bytes are persisted through save/load and can be replay-validated in runtime transcript tests.
Debug-path bridge and handshake access is tracked through a dedicated debug transcript lane, enabling regression-gate checks on debug-driven event sequences without perturbing runtime transcript state.
Genesis runtime metadata also exposes a dedicated debug transcript lane (separate from the runtime lane) for debugger-driven bridge/handshake traffic, so acceptance gates can validate debug parity evidence independently.
The dedicated debug transcript lane also captures debugger-driven IO ($a100xx), Z80 window ($a000xx), and VDP window ($c000xx) access pathways, providing a broader regression-gate evidence surface for debug memory activity.
Debugger tooling can query dedicated lane metadata directly through GenesisMemoryManager::GetDebugTranscriptLaneCount() and GenesisMemoryManager::GetDebugTranscriptLaneDigest(), and can explicitly reset lane evidence between phases with GenesisMemoryManager::ClearDebugTranscriptLane().
Compatibility matrix checkpoints now include GEN-COMPAT-DEBUG-LANE, which enforces deterministic replay parity for debug-lane command/response evidence in scaffold-based regression gates.
Compatibility matrix checkpoints also include GEN-COMPAT-32X-TELEMETRY, which validates deterministic replay parity for 32X tooling event telemetry bytes ($a15018/$a15019) in scaffold-based regression gates.
Compatibility matrix checkpoints also include GEN-COMPAT-SCD-TELEMETRY, which validates deterministic replay parity for Sega CD tooling event telemetry bytes ($a12016/$a12017) in scaffold-based regression gates.
Performance-gate result lines (GEN_PERF_RESULT) now include deterministic replay and telemetry evidence markers (REPLAY_OK, SCD_LANE_CT, SCD_EVT_CT, and M32X_EVT_CT) on every result line (including early-fail entries), so gate summaries can be correlated with replay stability and bridge/tooling activity surfaces.
Performance-gate summary lines (GEN_PERF_GATE_SUMMARY) now include aggregate tooling counters (SCD_LANE_TOTAL, SCD_EVT_TOTAL, and M32X_EVT_TOTAL) to provide one-line activity totals across the evaluated corpus.
Performance-gate summary lines also include AVG_SCD_LANE_PER_CASE so one-line summaries expose average Sega CD command-response lane activity per evaluated case.
Performance-gate summary lines also include AVG_SCD_EVT_PER_CASE so one-line summaries expose average Sega CD tooling event activity per evaluated case.
Performance-gate summary lines also include AVG_M32X_EVT_PER_CASE so one-line summaries expose average 32X tooling event activity per evaluated case.
Performance-gate summary lines also include ELAPSED_TOTAL_US so one-line summaries expose aggregate measured elapsed microseconds across the evaluated corpus.
Performance-gate summary lines also include AVG_ELAPSED_US so one-line summaries expose average measured elapsed microseconds per evaluated case.
Performance-gate summary lines also include BUDGET_UTIL_PCT so one-line summaries expose aggregate elapsed-vs-class-budget utilization as an integer percentage.
Performance-gate summary lines also include OVER_BUDGET_US_TOTAL so one-line summaries expose aggregate elapsed microseconds beyond the aggregate class-adjusted budget envelope.
Debugger memory probes now isolate transcript lanes: DebugRead8/DebugWrite8 record into the debug transcript lane only and no longer mutate the runtime Sega CD/32X transcript lane count or digest.
Performance-gate summary lines also include CLASS_BUDGET_TOTAL_US so one-line summaries expose the aggregate class-adjusted budget envelope across the evaluated corpus.
Performance-gate summary lines also include AVG_CLASS_BUDGET_US so one-line summaries expose average class-adjusted budget per evaluated case.
Performance-gate summary lines also include CASE_TOTAL so one-line summaries explicitly report the evaluated corpus size.
Performance-gate summary lines also include PASS_RATIO_PCT so one-line summaries expose pass-rate quality as an integer percentage derived from summary pass/fail counts.
Performance-gate summary lines also include FAIL_RATIO_PCT so one-line summaries expose failure-rate quality as an integer percentage derived from summary pass/fail counts.
Performance-gate summary lines also include REPLAY_MISMATCH_PCT so one-line summaries expose replay instability as an integer percentage of evaluated cases.
Performance-gate summary lines also include REPLAY_OK_TOTAL and REPLAY_FAIL_TOTAL so one-line summaries expose aggregate replay-parity pass/fail counts across the evaluated corpus.
For scaffold-based gate workflows, GenesisPlatformBusStub::ClearCommandResponseLane() is the deterministic phase-reset primitive for command/response evidence and related tooling/control parity staging state.
Central coordinator managing all debugging features.
Key Responsibilities:
- Coordinates per-CPU debuggers
- Manages script execution
- Controls execution flow (step, run, pause)
- Provides unified memory access
CPU Debugger Management:
// CpuInfo holds per-CPU debugging state
struct CpuInfo {
unique_ptr<IDebugger> Debugger; // CPU-specific debugger
unique_ptr<ExpressionEvaluator> Evaluator; // Expression evaluation
};
// Array indexed by CpuType enum
CpuInfo _debuggers[(int)DebugUtilities::GetLastCpuType() + 1];Shared Components:
ScriptManager- Lua scriptingMemoryDumper- Memory read/writeMemoryAccessCounter- Access trackingCodeDataLogger- CDL trackingDisassembler- Multi-CPU disassemblyLabelManager- Symbol managementCdlManager- CDL file I/O
Per-CPU debugger interface implemented by each CPU.
Implementations:
NesDebugger- 6502 (NES)SnesDebugger- 65816 (SNES main CPU)SpcDebugger- SPC700 (SNES audio)GameboyDebugger- LR35902 (Game Boy)GbaDebugger- ARM7TDMI (GBA)SmsDebugger- Z80 (SMS/Game Gear)PceDebugger- HuC6280 (PC Engine)WsDebugger- V30MZ (WonderSwan)GsuDebugger- Super FXCx4Debugger- Cx4 coprocessor
High-performance breakpoint evaluation.
Design Goals:
- Minimal overhead when no breakpoints
- Fast path for common cases
- Support complex conditions
Breakpoint Types:
enum class BreakpointType {
Global, // Always trigger
Execute, // On instruction execution
Read, // On memory read
Write // On memory write
};Organization:
// Breakpoints grouped by operation type for fast lookup
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
// Quick check if any breakpoints of type exist
bool _hasBreakpointType[BreakpointTypeCount];Evaluation Flow:
- Fast path check:
if(!_hasBreakpoint) return -1; - Type filter: Check
_hasBreakpointType[opType] - Address match: Linear search breakpoints
- Condition eval: RPN expression if present
- Return: Breakpoint ID or -1
Conditions use the ExpressionEvaluator:
// Example conditions
"A == $50" // Register equals value
"[addr] & $80" // Memory bit test
"PpuScanline < 100" // PPU state check
"Value == $FF" // Access value checkEvaluates expressions for breakpoint conditions and watch windows.
Operator Categories:
- Arithmetic:
+ - * / % - Bitwise:
<< >> & | ^ ~ - Logical:
== != < <= > >= && || - Memory:
[addr](byte),{addr}(word),{addr}w(dword) - Unary:
+ - ~ !
Platform-Specific Registers:
| Platform | Registers |
|---|---|
| 6502/NES | A, X, Y, SP, PC, PS, P.Carry, P.Zero, etc. |
| 65816/SNES | + DB, PB, DP, K, M, X flags |
| SPC700 | A, X, Y, SP, PC, YA, PSW |
| Z80/SMS | A, B, C, D, E, F, H, L, AF, BC, DE, HL, IX, IY, I, R |
| LR35902/GB | A, B, C, D, E, F, H, L, AF, BC, DE, HL, SP, PC |
| ARM7/GBA | R0-R15, CPSR, SPSR |
| HuC6280/PCE | A, X, Y, SP, PC, PS, MPR0-7 |
| V30MZ/WS | AX, BX, CX, DX, SI, DI, BP, SP, CS, DS, ES, SS, IP |
Special Values:
// PPU state
PpuFrameCount, PpuCycle, PpuScanline, PpuVramAddress
// Interrupts
Nmi, Irq
// Memory operation context
IsRead, IsWrite, IsDma, IsDummy
Value // Value being read/written
Address // Address being accessed
// Platform-specific
Sprite0Hit, VerticalBlank // NESRPN Compilation: Expressions are compiled to Reverse Polish Notation for fast evaluation:
// "A == $50" compiles to:
// [RegA] [0x50] [Equal]
vector<int64_t> _rpnList; // Pre-compiled tokensTracks which ROM bytes are code vs data.
CDL Flags:
enum CdlFlags : uint8_t {
None = 0x00,
Code = 0x01, // Executed as instruction
Data = 0x02, // Read as data
JumpTarget = 0x04, // Jump/branch destination
SubEntryPoint = 0x08, // Subroutine entry
IndexData8 = 0x10, // 8-bit indexed access
IndexData16 = 0x20, // 16-bit indexed access
PcmData = 0x40, // Audio sample data
DrawingTile = 0x80 // Graphics tile data
};File Format:
CDL File Format (CDLv2)
════════════════════════
Offset Size Content
0x00 5 "CDLv2" magic
0x05 4 ROM CRC32
0x09 N Flag bytes (1 per ROM byte)
Use Cases:
- ROM hacking: Find unused space
- Disassembly: Improve code detection
- Coverage: Verify code paths executed
- Size optimization: Strip unused data
Manages CDL file operations and multi-memory CDL tracking.
Multi-CPU disassembly engine.
Supported CPUs:
- 6502 (NES)
- 65816 (SNES)
- SPC700 (SNES audio)
- LR35902 (Game Boy)
- ARM7TDMI (GBA, ARM + Thumb)
- Z80 (SMS, Game Gear)
- HuC6280 (PC Engine)
- V30MZ (WonderSwan)
- Super FX
- Cx4, NEC DSP, ST018
Features:
- Label integration
- Comment support
- CDL-guided code/data detection
- Address mapping (CPU ↔ ROM)
Metadata for disassembled instructions.
struct DisassemblyInfo {
uint8_t OpSize; // Instruction size in bytes
uint8_t Flags; // Code/data flags
uint8_t ByteCode[8]; // Raw bytes
uint32_t Address; // CPU address
AddressInfo AbsAddress; // Absolute/ROM address
};Interactive assembler for 6502/65816 code.
Features:
- Real-time assembly in debugger
- Label resolution
- Address mode detection
- Immediate error feedback
Instruction-level execution logging.
Log Format:
PC Op Operand A X Y SP Flags Cycle
$8000 LDA $0300,X A:00 X:10 Y:00 SP:FD N-BdIZC 1234
Options:
- CPU registers
- Memory values
- PPU state
- Timestamps
- Custom formatting
Tracks subroutine calls and returns.
Features:
- JSR/RTS tracking
- Interrupt context
- Stack depth monitoring
- Call graph building
Unified memory access interface.
Operations:
- Read/write any memory type
- Address translation
- Memory type enumeration
- Bulk operations
Tracks memory access patterns.
Statistics:
- Read count per address
- Write count per address
- Execute count per address
- First/last access timing
Performance profiling per function/address.
Metrics:
- Cycle counts
- Call frequency
- Inclusive/exclusive time
- Hotspot detection
Lua script management and execution.
Script Types:
- Startup scripts
- Per-frame scripts
- Event-triggered scripts
Comprehensive Lua bindings.
API Categories:
-- Memory access
emu.read(addr, memType)
emu.write(addr, value, memType)
emu.readWord(addr, memType)
-- Debugger control
emu.breakExecution()
emu.resume()
emu.step(count)
-- Event callbacks
emu.addEventCallback(callback, eventType)
emu.removeEventCallback(id)
-- State management
emu.saveSavestate()
emu.loadSavestate(slot)
-- Drawing (overlays)
emu.drawPixel(x, y, color)
emu.drawLine(x1, y1, x2, y2, color)
emu.drawString(x, y, text, color)
-- Input
emu.getInput(port)
emu.setInput(port, state)Rewind/step-back debugging.
Features:
- Instruction-level rewind
- Savestate ring buffer
- Configurable history depth
Implementation:
// Ring buffer of savestates for rewind
vector<vector<uint8_t>> _history;
int _historyIndex = 0;
int _historySize = 1000; // ConfigurableGraphics debugging utilities.
Features:
- Tile viewer
- Sprite viewer
- Palette viewer
- Tilemap viewer
- VRAM viewer
- OAM viewer
Debug event logging for analysis.
Event Types:
- Memory reads/writes
- Register access
- Interrupt triggers
- DMA transfers
- PPU events
// Create execute breakpoint at $8000
Breakpoint bp;
bp.SetType(BreakpointType::Execute);
bp.SetStartAddress(0x8000);
bp.SetEnabled(true);
// With condition
bp.SetCondition("A == $FF && X > $10");
breakpointManager->SetBreakpoints(&bp, 1);// Evaluate expression in current CPU context
EvalResultType resultType;
int64_t result = evaluator->Evaluate(
"A + X * 2",
cpuState,
resultType,
operationInfo
);-- Log when specific address is written
function onWrite()
local value = emu.read(0x0300, emu.memType.nesInternalRam)
emu.log("Address $0300 = " .. string.format("%02X", value))
end
emu.addEventCallback(onWrite, emu.eventType.write)- ARCHITECTURE-OVERVIEW.md - Overall structure
- NES-CORE.md - NES debugger specifics
- SNES-CORE.md - SNES debugger specifics
- GB-GBA-CORE.md - GB/GBA debugger specifics
- SMS-PCE-WS-CORE.md - Other platform debuggers