# YAZE Emulator Enhancement Roadmap

**Version**: 1.0  
**Date**: October 8, 2025  
**Status**: Planning Phase  
**Target**: Mesen2-Level Debugging + AI Integration

---

## 📋 Executive Summary

This document outlines the roadmap for evolving YAZE's SNES emulator from a basic runtime into a **world-class debugging platform** with AI agent integration. The goal is to achieve feature parity with Mesen2's advanced debugging capabilities while adding unique AI-powered features through the z3ed CLI system.

### Core Objectives
1. **Advanced Debugger** - Breakpoints, watchpoints, memory inspection, trace logging
2. **Performance Optimization** - Cycle-accurate timing, dynarec, frame pacing
3. **Audio System Fix** - SDL2 audio output currently broken, needs investigation
4. **AI Integration** - z3ed agent can read/write emulator state, automate testing
5. **SPC700 Debugger** - Full audio CPU debugging with APU state inspection

---

## 🎯 Current State Analysis

### What Works ✅
- **CPU Emulation**: 65816 core functional, runs games
- **PPU Rendering**: Display works, texture updates to SDL2
- **ROM Loading**: Can load and execute SNES ROMs
- **Basic Controls**: Start/stop/pause/reset functionality
- **Memory Access**: Read/write to CPU memory space
- **Renderer Integration**: Now using `IRenderer` interface (SDL3-ready!)
- **Stability**: Emulator pauses during window resize (macOS protection)

### What's Broken ❌
- **Audio Output**: SDL2 audio device initialized but no sound plays
- **SPC700 Debugging**: No inspection tools for audio CPU
- **Performance**: Not cycle-accurate, timing issues
- **Debugging Tools**: Minimal breakpoint support, no watchpoints
- **Memory Viewer**: Basic hex view, no structured inspection
- **Trace Logging**: No execution tracing capability

### What's Missing 🚧
- **Advanced Breakpoints**: Conditional, access-based, CPU/SPC700
- **Memory Watchpoints**: Track reads/writes to specific addresses
- **Disassembly View**: Real-time code annotation
- **Performance Profiling**: Hotspot analysis, cycle counting
- **Event Viewer**: Track NMI, IRQ, DMA events
- **PPU Inspector**: VRAM, OAM, palette debugging
- **APU Inspector**: DSP state, sample buffer, channel visualization
- **AI Integration**: z3ed agent can't access emulator yet

---

## 🔧 Phase 1: Audio System Fix (Priority: CRITICAL)

### Problem Analysis
**Current State**:
```cpp
// controller.cc:31-33
editor_manager_.emulator().set_audio_buffer(window_.audio_buffer_.get());
editor_manager_.emulator().set_audio_device_id(window_.audio_device_);

// window.cc:114-130
window.audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
SDL_PauseAudioDevice(window.audio_device_, 0);  // Unpause
```

**The Issue**: Audio device is initialized and unpaused, but `SDL_QueueAudio()` in emulator isn't producing sound.

### Investigation Steps

1. **Verify Audio Device State**
```cpp
// Add to Emulator::Run()
if (frame_count_ % 60 == 0) {  // Every second
  uint32_t queued = SDL_GetQueuedAudioSize(audio_device_);
  SDL_AudioStatus status = SDL_GetAudioDeviceStatus(audio_device_);
  printf("[AUDIO] Queued: %u bytes, Status: %d (1=playing, 2=paused)\n", 
         queued, status);
}
```

2. **Check SPC700 Sample Generation**
```cpp
// Verify snes_.SetSamples() is producing valid data
snes_.SetSamples(audio_buffer_, wanted_samples_);

// Debug output
int16_t* samples = audio_buffer_;
bool has_audio = false;
for (int i = 0; i < wanted_samples_ * 2; i++) {
  if (samples[i] != 0) {
    has_audio = true;
    break;
  }
}
if (!has_audio && frame_count_ % 60 == 0) {
  printf("[AUDIO] Warning: All samples are zero!\n");
}
```

3. **Validate Audio Format Compatibility**
```cpp
// window.cc - Check if requested format matches obtained format
SDL_AudioSpec want, have;
// ... (existing code)
window.audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);

printf("[AUDIO] Requested: %dHz, %d channels, format=%d\n", 
       want.freq, want.channels, want.format);
printf("[AUDIO] Obtained:  %dHz, %d channels, format=%d\n", 
       have.freq, have.channels, have.format);

if (have.freq != want.freq || have.channels != want.channels) {
  LOG_ERROR("Audio", "Audio spec mismatch - may need resampling");
}
```

### Likely Fixes

**Fix 1: Audio Device Paused State**
```cpp
// The audio device might be re-pausing itself
// Try forcing unpause in the emulator loop
if (frame_count_ % 60 == 0) {
  SDL_PauseAudioDevice(audio_device_, 0);  // Ensure unpaused
}
```

**Fix 2: Sample Format Conversion**
```cpp
// SPC700 might be outputting wrong format
// Ensure AUDIO_S16 (signed 16-bit) matches emulator output
void Snes::SetSamples(int16_t* buffer, int count) {
  // Verify apu_.GetSamples() returns int16_t, not float or uint16_t
  apu_.GetSamples(buffer, count);
  
  // Debug: Check for clipping or DC offset
  for (int i = 0; i < count * 2; i++) {
    if (buffer[i] < -32768 || buffer[i] > 32767) {
      printf("[AUDIO] Sample %d out of range: %d\n", i, buffer[i]);
    }
  }
}
```

**Fix 3: Buffer Size Mismatch**
```cpp
// Ensure buffer allocation matches usage
// window.cc:128
window.audio_buffer_ = std::make_shared<int16_t>(audio_frequency / 50 * 4);
// This allocates: 48000 / 50 * 4 = 3840 int16_t samples
// Emulator uses: wanted_samples_ * 4 bytes = (48000/60) * 4 = 3200 bytes
// = 1600 int16_t samples (800 per channel)
// MISMATCH! Should be:
window.audio_buffer_ = std::make_shared<int16_t>(audio_frequency / 50 * 2);  // Stereo
```

### Quick Win Actions
**File**: `window.cc`
**Line**: 128
**Change**: 
```cpp
// Before:
window.audio_buffer_ = std::make_shared<int16_t>(audio_frequency / 50 * 4);

// After:
// Allocate for stereo at 60Hz (worst case)
// 48000Hz / 60 FPS = 800 samples/frame * 2 channels = 1600 int16_t
window.audio_buffer_ = std::make_shared<int16_t>((audio_frequency / 50) * 2);
```

**File**: `emulator.cc`  
**After Line**: 216
**Add**:
```cpp
// Debug audio output
if (frame_count_ % 300 == 0) {  // Every 5 seconds
  uint32_t queued = SDL_GetQueuedAudioSize(audio_device_);
  SDL_AudioStatus status = SDL_GetAudioDeviceStatus(audio_device_);
  printf("[AUDIO] Status=%d, Queued=%u, WantedSamples=%d\n", 
         status, queued, wanted_samples_);
}
```

**Estimated Fix Time**: 2-4 hours

---

## 🐛 Phase 2: Advanced Debugger (Mesen2 Feature Parity)

### Feature Comparison: YAZE vs Mesen2

| Feature | Mesen2 | YAZE Current | YAZE Target |
|---------|--------|--------------|-------------|
| CPU Breakpoints | ✅ Execute/Read/Write | ⚠️ Basic Execute | ✅ Full Support |
| Memory Watchpoints | ✅ Conditional | ❌ None | ✅ Conditional |
| Disassembly View | ✅ Live Annotated | ❌ Static | ✅ Live + Labels |
| Memory Viewer | ✅ Multi-region | ⚠️ Basic Hex | ✅ Structured |
| Trace Logger | ✅ CPU/SPC/DMA | ❌ None | ✅ All Channels |
| Event Viewer | ✅ IRQ/NMI/DMA | ❌ None | ✅ Full Timeline |
| Performance | ✅ Cycle Accurate | ❌ Approximate | ✅ Cycle Accurate |
| Save States | ⚠️ Limited | ⚠️ Basic | ✅ Full State |
| PPU Debugger | ✅ Layer Viewer | ❌ None | ✅ VRAM Inspector |
| APU Debugger | ✅ DSP Viewer | ❌ None | ✅ Channel Mixer |
| Scripting | ✅ Lua | ❌ None | ✅ z3ed + AI! |

### 2.1 Breakpoint System

**Architecture**:
```cpp
// src/app/emu/debug/breakpoint_manager.h
class BreakpointManager {
public:
  enum class Type {
    EXECUTE,     // Break when PC reaches address
    READ,        // Break when address is read
    WRITE,       // Break when address is written
    ACCESS,      // Break on read OR write
    CONDITIONAL  // Break when condition is true
  };
  
  struct Breakpoint {
    uint32_t address;
    Type type;
    bool enabled;
    std::string condition;  // Lua expression or simple comparison
    uint32_t hit_count;
    std::function<bool()> callback;  // Optional custom logic
  };
  
  uint32_t AddBreakpoint(uint32_t address, Type type, 
                         const std::string& condition = "");
  void RemoveBreakpoint(uint32_t id);
  bool ShouldBreak(uint32_t address, Type access_type);
  std::vector<Breakpoint> ListBreakpoints();
  
private:
  std::unordered_map<uint32_t, Breakpoint> breakpoints_;
  uint32_t next_id_ = 1;
};
```

**CPU Integration**:
```cpp
// src/app/emu/cpu/cpu.cc
void CPU::RunOpcode() {
  // Check execute breakpoint BEFORE running
  if (breakpoint_mgr_->ShouldBreak(PC, BreakpointType::EXECUTE)) {
    emulator_->OnBreakpointHit(PC, BreakpointType::EXECUTE);
    return;  // Pause execution
  }
  
  // Run instruction...
  ExecuteInstruction();
  
  // Memory access breakpoints handled in Read()/Write()
}

uint8_t CPU::Read(uint32_t address) {
  if (breakpoint_mgr_->ShouldBreak(address, BreakpointType::READ)) {
    emulator_->OnBreakpointHit(address, BreakpointType::READ);
  }
  return memory_->Read(address);
}
```

**z3ed Integration**:
```bash
# CLI commands
z3ed emu breakpoint add --address 0x00FFD9 --type execute
z3ed emu breakpoint add --address 0x7E0010 --type write --condition "value > 100"
z3ed emu breakpoint list
z3ed emu breakpoint remove --id 1

# AI agent can use these
"Set a breakpoint at the Link damage handler"
→ Agent finds damage code address → z3ed emu breakpoint add
```

**Estimated Effort**: 8-12 hours

---

### 2.2 Memory Watchpoints

**Features**:
- Track specific memory regions
- Log all accesses with stack traces
- Detect buffer overflows
- Find data corruption sources

**Implementation**:
```cpp
// src/app/emu/debug/watchpoint_manager.h
class WatchpointManager {
public:
  struct Watchpoint {
    uint32_t start_address;
    uint32_t end_address;
    bool track_reads;
    bool track_writes;
    std::vector<AccessLog> history;
  };
  
  struct AccessLog {
    uint32_t pc;           // Where the access happened
    uint32_t address;      // What address was accessed
    uint8_t old_value;     // Value before write
    uint8_t new_value;     // Value after write
    bool is_write;
    uint64_t cycle_count;
  };
  
  void AddWatchpoint(uint32_t start, uint32_t end, bool reads, bool writes);
  void OnMemoryAccess(uint32_t pc, uint32_t address, bool is_write, 
                      uint8_t old_val, uint8_t new_val);
  std::vector<AccessLog> GetHistory(uint32_t address, int max_entries = 100);
};
```

**Use Cases**:
- Find where Link's HP is being modified
- Track item collection bugs
- Debug event flag corruption
- Detect unintended memory writes

**z3ed Commands**:
```bash
z3ed emu watch add --start 0x7E0000 --end 0x7E1FFF --reads --writes
z3ed emu watch history --address 0x7E0010
z3ed emu watch export --format csv
```

**Estimated Effort**: 6-8 hours

---

### 2.3 Live Disassembly Viewer

**Mesen2 Inspiration**:
- Scrollable code view with current PC highlighted
- Labels from ROM labels file
- Inline comments
- Jump target visualization
- Hot code highlighting (most-executed instructions)

**Architecture**:
```cpp
// src/app/emu/debug/disassembly_viewer.h (already exists!)
// Enhance existing viewer

class DisassemblyViewer {
public:
  struct DisassembledInstruction {
    uint32_t address;
    std::string mnemonic;
    std::string operands;
    std::string comment;
    uint32_t execution_count;  // NEW: Hotspot tracking
    bool is_breakpoint;
    bool is_current_pc;
  };
  
  void Update(CPU& cpu);
  void RenderWindow();
  void JumpToAddress(uint32_t address);
  void ToggleBreakpoint(uint32_t address);
  
  // NEW: Hotspot profiling
  void EnableProfiling(bool enable);
  std::vector<uint32_t> GetHotspots(int top_n = 10);
  
private:
  std::unordered_map<uint32_t, uint32_t> execution_counts_;
  std::shared_ptr<ResourceLabel> labels_;  // From ROM
};
```

**ImGui Integration**:
```cpp
void Emulator::RenderDisassemblyWindow() {
  if (ImGui::Begin("Disassembly", &show_disassembly_)) {
    // Scrollable list
    ImGui::BeginChild("DisasmScroll");
    
    // Show ±50 instructions around PC
    uint32_t pc = snes_.cpu().PC;
    for (int offset = -50; offset <= 50; offset++) {
      auto instr = disassembly_viewer_.GetInstruction(pc + offset);
      
      // Highlight current PC
      if (offset == 0) {
        ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,1,0,1));
      }
      
      // Show execution count for hotspots
      if (instr.execution_count > 1000) {
        ImGui::TextColored(ImVec4(1,0.5,0,1), "🔥");  // Hot code
      }
      
      ImGui::Text("%06X  %s  %s  ; %s", 
                  instr.address, instr.mnemonic.c_str(), 
                  instr.operands.c_str(), instr.comment.c_str());
      
      if (offset == 0) ImGui::PopStyleColor();
      
      // Click to toggle breakpoint
      if (ImGui::IsItemClicked()) {
        disassembly_viewer_.ToggleBreakpoint(instr.address);
      }
    }
    
    ImGui::EndChild();
  }
  ImGui::End();
}
```

**Estimated Effort**: 10-12 hours

---

### 2.4 Enhanced Memory Viewer

**Multi-Region Support**:
```cpp
enum class MemoryRegion {
  WRAM,        // 0x7E0000-0x7FFFFF (128KB)
  SRAM,        // Cartridge RAM
  VRAM,        // PPU video RAM
  CGRAM,       // PPU palette RAM
  OAM,         // PPU sprite RAM
  ARAM,        // SPC700 audio RAM
  ROM,         // Cartridge ROM
  REGISTERS    // Hardware registers
};
```

**Structured Views**:
```cpp
class MemoryViewer {
public:
  void RenderHexView(MemoryRegion region);
  void RenderStructView(uint32_t address, const std::string& struct_name);
  void RenderDiffView(uint32_t address, const uint8_t* reference);
  
  // NEW: ROM label integration
  void SetLabels(std::shared_ptr<ResourceLabel> labels);
  std::string GetLabelForAddress(uint32_t address);
  
  // NEW: Goto functionality
  void GotoAddress(uint32_t address);
  void GotoLabel(const std::string& label);
};
```

**ImGui Layout**:
```
┌────────────────────────────────────────────────┐
│ Memory Viewer                                  │
├────────────────────────────────────────────────┤
│ Region: [WRAM ▼] | Goto: [0x7E0010] [Find]   │
├────────────────────────────────────────────────┤
│ Addr    +0 +1 +2 +3 +4 +5 +6 +7  ASCII        │
│ 7E0000  00 05 3C 00 00 00 00 00  ..<.....      │ ← Link's HP
│ 7E0008  1F 00 00 00 00 00 00 00  ........      │
│ ...                                            │
├────────────────────────────────────────────────┤
│ Watchpoints: [Add] [Clear All]                │
│ • 0x7E0000-0x7E0010 (R/W) - Link stats        │
└────────────────────────────────────────────────┘
```

**Estimated Effort**: 6-8 hours

---

## 🚀 Phase 3: Performance Optimizations

### 3.1 Cycle-Accurate Timing

**Current Issue**: Emulator runs on frame timing, not cycle timing

**Mesen2 Approach**:
```cpp
class CPU {
  void RunCycle() {
    if (cycles_until_next_instruction_ == 0) {
      ExecuteInstruction();  // Sets cycles_until_next_instruction_
    } else {
      cycles_until_next_instruction_--;
    }
    
    // Other components run per-cycle
    ppu_.RunCycle();
    apu_.RunCycle();
    dma_.RunCycle();
  }
};

// Emulator loop
void Emulator::RunFrame() {
  const int cycles_per_frame = snes_.memory().pal_timing() ? 1538400 : 1789773;
  for (int i = 0; i < cycles_per_frame; i++) {
    snes_.RunCycle();  // ONE cycle at a time
  }
}
```

**Benefits**:
- Accurate mid-scanline effects
- Proper DMA timing
- Correct PPU rendering edge cases
- Deterministic emulation

**Estimated Effort**: 20-30 hours (major refactor)

---

### 3.2 Dynamic Recompilation (Dynarec)

**Why**: Cycle-accurate interpretation is slow (~30 FPS). Dynarec can hit 60 FPS.

**Strategy**:
```cpp
class Dynarec {
  // Compile frequently-executed code blocks to native ARM/x64
  void* CompileBlock(uint32_t start_pc);
  void InvalidateBlock(uint32_t address);  // When code changes
  
  // Cache compiled blocks
  std::unordered_map<uint32_t, void*> code_cache_;
};

void CPU::RunOpcode() {
  if (dynarec_enabled_) {
    // Check if block is compiled
    if (auto* block = dynarec_.GetBlock(PC)) {
      return ((BlockFunc)block)();  // Execute native code
    }
  }
  
  // Fallback to interpreter
  ExecuteInstruction();
}
```

**Complexity**: Very high - requires assembly code generation

**Alternative**: Use existing dynarec library like `bsnes-jit`

**Estimated Effort**: 40-60 hours (or use library: 10 hours)

---

### 3.3 Frame Pacing Improvements

**Current Issue**: SDL_Delay(1) is too coarse

**Better Approach**:
```cpp
void Emulator::RunFrame() {
  auto frame_start = std::chrono::high_resolution_clock::now();
  
  // Run SNES frame
  snes_.RunFrame();
  
  // Calculate how long to wait
  auto frame_end = std::chrono::high_resolution_clock::now();
  auto frame_duration = std::chrono::duration_cast<std::chrono::microseconds>(
      frame_end - frame_start);
  
  auto target_duration = std::chrono::microseconds(
      static_cast<int64_t>(wanted_frames_ * 1'000'000));
  
  if (frame_duration < target_duration) {
    auto sleep_time = target_duration - frame_duration;
    std::this_thread::sleep_for(sleep_time);  // Precise sleep
  }
}
```

**Estimated Effort**: 2-3 hours

---

## 🎮 Phase 4: SPC700 Audio CPU Debugger

### 4.1 APU Inspector Window

**Layout**:
```
┌─────────────────────────────────────────────────────────┐
│ APU Debugger                                            │
├─────────────────────────────────────────────────────────┤
│ SPC700 CPU State:                                       │
│   PC: 0x1234  A: 0x00  X: 0x05  Y: 0xFF  PSW: 0x02     │
│   SP: 0xEF    Cycles: 12,345,678                        │
├─────────────────────────────────────────────────────────┤
│ DSP Registers:  [Channel 0▼]                           │
│   VOL_L: 127    VOL_R: 127    PITCH: 2048              │
│   ADSR: 0xBE7F  GAIN: 0x7F    ENVX: 45  OUTX: 78       │
│                                                         │
│ Waveform: [████▓▓▓▓░░░░▒▒▒▒████▓▓▓▓░░░░] (live)      │
├─────────────────────────────────────────────────────────┤
│ Audio RAM (64KB):                                       │
│ 0000  BRR BRR BRR BRR ...  (sample data)               │
│ ...                                                     │
├─────────────────────────────────────────────────────────┤
│ Channel Mixer:                                          │
│ 0: ████████████░░░░ (75%)  1: ░░░░░░░░░░░░░░ (0%)     │
│ 2: ██████░░░░░░░░░░ (45%)  3: ░░░░░░░░░░░░░░ (0%)     │
│ ...                                                     │
└─────────────────────────────────────────────────────────┘
```

**Implementation**:
```cpp
// src/app/emu/debug/apu_inspector.h
class ApuInspector {
public:
  void RenderWindow(Snes& snes);
  void RenderChannelMixer();
  void RenderWaveform(int channel);
  void RenderDspRegisters();
  void RenderAudioRam();
  
  // Sample buffer visualization
  void UpdateWaveformData(const int16_t* samples, int count);
  
private:
  std::array<std::vector<float>, 8> channel_waveforms_;
  int selected_channel_ = 0;
};
```

**z3ed Commands**:
```bash
z3ed emu apu status
z3ed emu apu channel --id 0
z3ed emu apu dump-ram --output audio_ram.bin
z3ed emu apu export-samples --channel 0 --format wav
```

**Estimated Effort**: 12-15 hours

---

### 4.2 Audio Sample Export

**Feature**: Export audio samples to WAV for analysis

```cpp
class AudioExporter {
public:
  void StartRecording(int channel = -1);  // -1 = all channels
  void StopRecording();
  void ExportToWav(const std::string& filename);
  
private:
  std::vector<int16_t> recorded_samples_;
  bool recording_ = false;
};
```

**Use Cases**:
- Debug why sound effects aren't playing
- Export game music for analysis
- Compare with real SNES hardware recordings

**Estimated Effort**: 4-6 hours

---

## 🤖 Phase 5: z3ed AI Agent Integration

### 5.1 Emulator State Access

**Add to ConversationalAgentService**:
```cpp
// src/cli/service/agent/conversational_agent_service.h
class ConversationalAgentService {
public:
  // NEW: Emulator access
  void SetEmulator(emu::Emulator* emulator);
  
  // Tool: Get emulator state
  std::string HandleEmulatorState();
  std::string HandleCpuState();
  std::string HandleMemoryRead(uint32_t address, int count);
  std::string HandleMemoryWrite(uint32_t address, const std::vector<uint8_t>& data);
  
private:
  emu::Emulator* emulator_ = nullptr;
};
```

**z3ed Tool Schema**:
```json
{
  "name": "emulator-read-memory",
  "description": "Read emulator memory at a specific address",
  "parameters": {
    "address": {"type": "integer", "description": "Memory address (e.g., 0x7E0010)"},
    "count": {"type": "integer", "description": "Number of bytes to read"},
    "region": {"type": "string", "enum": ["wram", "sram", "rom", "aram"]}
  }
}
```

**Example AI Queries**:
```
User: "What is Link's current HP?"
Agent: [calls emulator-read-memory address=0x7E0000 count=1]
       → Response: "Link has 6 hearts (0x60 = 96 health points)"

User: "Set Link to full health"
Agent: [calls emulator-write-memory address=0x7E0000 data=[0xA0]]
       → Response: "Link's HP set to 160 (full health)"

User: "Where is the game stuck?"
Agent: [calls emulator-cpu-state]
       → Response: "PC=$00:8234 - Infinite loop in NMI handler"
```

---

### 5.2 Automated Test Generation

**Use Case**: AI generates emulator tests from natural language

**Example Flow**:
```bash
z3ed agent test-scenario --prompt "Test that Link takes damage from enemies"

# AI generates:
{
  "steps": [
    {"action": "load-state", "file": "link_at_full_hp.sfc"},
    {"action": "run-frames", "count": 60},
    {"action": "assert-memory", "address": "0x7E0000", "value": "0xA0"},
    {"action": "move-link", "direction": "right", "frames": 30},
    {"action": "assert-memory-decreased", "address": "0x7E0000"},
    {"action": "screenshot", "name": "link_damaged.png"}
  ]
}
```

**Implementation**:
```cpp
// src/cli/commands/agent/test_scenario_runner.h
class TestScenarioRunner {
public:
  struct TestStep {
    std::string action;
    absl::flat_hash_map<std::string, std::string> params;
  };
  
  absl::Status RunScenario(const std::vector<TestStep>& steps);
  
private:
  void ExecuteLoadState(const std::string& file);
  void ExecuteRunFrames(int count);
  void ExecuteAssertMemory(uint32_t address, uint8_t expected);
  void ExecuteMoveLink(const std::string& direction, int frames);
  void ExecuteScreenshot(const std::string& filename);
};
```

**Estimated Effort**: 8-10 hours

---

### 5.3 Memory Map Learning

**Feature**: AI learns ROM's memory layout from debugging sessions

**Architecture**:
```cpp
// Extends existing learn command
z3ed agent learn --memory-map "0x7E0000" --label "link_hp" --type "uint8"
z3ed agent learn --memory-map "0x7E0010" --label "link_x_pos" --type "uint16"

// AI can then use this knowledge
User: "What is Link's position?"
Agent: [checks learned memory map]
       [calls emulator-read-memory address=0x7E0010 count=2 type=uint16]
```

**Storage**:
```json
// ~/.yaze/agent/memory_maps/zelda3.json
{
  "rom_hash": "abc123...",
  "symbols": {
    "0x7E0000": {"name": "link_hp", "type": "uint8", "description": "Link's health"},
    "0x7E0010": {"name": "link_x_pos", "type": "uint16", "description": "Link X coordinate"},
    "0x7E0012": {"name": "link_y_pos", "type": "uint16", "description": "Link Y coordinate"}
  }
}
```

**Estimated Effort**: 6-8 hours

---

## 📊 Phase 6: Performance Profiling

### 6.1 Cycle Counter & Profiler

**Mesen2 Feature**: Shows which code is hot, helps optimize hacks

**Implementation**:
```cpp
class PerformanceProfiler {
public:
  struct FunctionProfile {
    uint32_t start_address;
    uint32_t end_address;
    std::string name;
    uint64_t total_cycles;
    uint32_t call_count;
    float percentage;
  };
  
  void StartProfiling();
  void StopProfiling();
  std::vector<FunctionProfile> GetHotFunctions(int top_n = 20);
  void ExportFlameGraph(const std::string& filename);
  
private:
  std::unordered_map<uint32_t, uint64_t> address_cycle_counts_;
};
```

**ImGui Visualization**:
```
┌────────────────────────────────────────────────┐
│ Performance Profiler                           │
├────────────────────────────────────────────────┤
│ Function           Cycles      Calls    %      │
│ NMI Handler        2,456,789   1,234   15.2%  │
│ Link Update        1,987,654   3,600   12.3%  │
│ PPU Transfer       1,234,567   890     7.6%   │
│ ...                                            │
├────────────────────────────────────────────────┤
│ [Start Profiling] [Stop] [Export Flame Graph] │
└────────────────────────────────────────────────┘
```

**z3ed Commands**:
```bash
z3ed emu profile start
# ... run game for a bit ...
z3ed emu profile stop
z3ed emu profile report --top 20
z3ed emu profile export --format flamegraph --output profile.svg
```

**Estimated Effort**: 10-12 hours

---

### 6.2 Frame Time Analysis

**Track frame timing issues**:
```cpp
class FrameTimeAnalyzer {
  struct FrameStats {
    float cpu_time_ms;
    float ppu_time_ms;
    float apu_time_ms;
    float total_time_ms;
    int dropped_frames;
  };
  
  void RecordFrame();
  FrameStats GetAverageStats(int last_n_frames = 60);
  std::vector<float> GetFrameTimeGraph(int frames = 300);  // 5 seconds
};
```

**Visualization**: Real-time graph showing frame time spikes

**Estimated Effort**: 4-6 hours

---

## 🎯 Phase 7: Event System & Timeline

### 7.1 Event Logger

**Mesen2 Feature**: Timeline view of all hardware events

**Events to Track**:
- NMI (V-Blank)
- IRQ (H-Blank, Timer)
- DMA transfers
- HDMA activations
- PPU mode changes
- Audio sample playback starts

**Implementation**:
```cpp
class EventLogger {
public:
  enum class EventType {
    NMI, IRQ, DMA, HDMA, PPU_MODE_CHANGE, APU_SAMPLE_START
  };
  
  struct Event {
    EventType type;
    uint64_t cycle;
    uint32_t pc;  // Where CPU was when event occurred
    std::string details;
  };
  
  void LogEvent(EventType type, const std::string& details);
  std::vector<Event> GetEvents(uint64_t start_cycle, uint64_t end_cycle);
  void Clear();
  
private:
  std::deque<Event> event_history_;  // Keep last 10,000 events
};
```

**Visualization**:
```
Timeline (last 5 frames):
Frame 1: [NMI]────[DMA]──[HDMA]─────────────────
Frame 2: [NMI]────[DMA]──────────[IRQ]──────────
Frame 3: [NMI]────[DMA]──[HDMA]─────────────────
         ^        ^      ^
         16.67ms  18ms   20ms (timing shown)
```

**Estimated Effort**: 8-10 hours

---

## 🧠 Phase 8: AI-Powered Debugging

### 8.1 Intelligent Crash Analysis

**Feature**: AI analyzes emulator state when game crashes/freezes

```bash
z3ed agent debug-crash --state latest_crash.state

# AI examines:
# - CPU registers and flags
# - Stack contents
# - Recent code execution
# - Memory watchpoint history
# - Event timeline

# AI response:
"The game crashed because:
1. Infinite loop detected at $00:8234
2. This is the NMI handler
3. It's waiting for PPU register 0x2137 to change
4. The value hasn't changed in 10,000 cycles
5. Likely cause: PPU is in wrong mode (Mode 0 instead of Mode 1)

Suggested fix:
- Check PPU mode initialization at game start
- Verify NMI handler only runs when PPU is ready"
```

**Estimated Effort**: 15-20 hours

---

### 8.2 Automated Bug Reproduction

**Feature**: AI creates minimal test case from bug description

```bash
z3ed agent repro --prompt "Link takes damage when he shouldn't"

# AI generates reproduction steps:
{
  "steps": [
    "load_state: link_full_hp.sfc",
    "move: right, 50 frames",
    "assert: no damage taken",
    "expected: HP stays at 0xA0",
    "actual: HP decreased to 0x90",
    "analysis: Enemy collision box too large"
  ]
}
```

**Estimated Effort**: 12-15 hours

---

## 🗺️ Implementation Roadmap

### Sprint 1: Audio Fix (Week 1)
**Priority**: CRITICAL  
**Time**: 4 hours  
**Deliverables**:
- ✅ Investigate audio buffer size mismatch
- ✅ Add audio debug logging
- ✅ Fix SDL2 audio output
- ✅ Verify audio plays correctly

### Sprint 2: Basic Debugger (Weeks 2-3)
**Priority**: HIGH  
**Time**: 20 hours  
**Deliverables**:
- ✅ Breakpoint manager with execute/read/write
- ✅ Enhanced disassembly viewer with hotspots
- ✅ Improved memory viewer with regions
- ✅ z3ed CLI commands for debugging

### Sprint 3: SPC700 Debugger (Week 4)
**Priority**: MEDIUM  
**Time**: 15 hours  
**Deliverables**:
- ✅ APU inspector window
- ✅ Channel waveform visualization
- ✅ Audio RAM viewer
- ✅ Sample export to WAV

### Sprint 4: AI Integration (Weeks 5-6)
**Priority**: MEDIUM  
**Time**: 25 hours  
**Deliverables**:
- ✅ Emulator state tools for z3ed agent
- ✅ Memory map learning system
- ✅ Automated test scenario generation
- ✅ Crash analysis AI

### Sprint 5: Performance (Weeks 7-8)
**Priority**: LOW (Future)  
**Time**: 40+ hours  
**Deliverables**:
- ✅ Cycle-accurate timing
- ✅ Dynamic recompilation
- ✅ Performance profiler
- ✅ Frame pacing improvements

---

## 🔬 Technical Deep Dives

### Audio System Architecture (SDL2)

**Current Flow**:
```
SPC700 → APU::GetSamples() → Snes::SetSamples() → audio_buffer_
         → SDL_QueueAudio() → SDL Audio Device → System Audio
```

**Debug Points**:
```cpp
// 1. Check SPC700 output
void APU::GetSamples(int16_t* buffer, int count) {
  // Are samples being generated?
  LOG_IF_ZERO_SAMPLES(buffer, count);
}

// 2. Check buffer handoff
void Snes::SetSamples(int16_t* buffer, int count) {
  apu_.GetSamples(buffer, count);
  // Are samples copied correctly?
  VERIFY_BUFFER_NOT_SILENT(buffer, count);
}

// 3. Check SDL queue
if (SDL_QueueAudio(device, buffer, size) < 0) {
  LOG_ERROR("SDL_QueueAudio failed: %s", SDL_GetError());
}

// 4. Check device status
if (SDL_GetAudioDeviceStatus(device) != SDL_AUDIO_PLAYING) {
  LOG_ERROR("Audio device not playing!");
}
```

**Common Issues**:
1. **Buffer size mismatch** - Fixed in Phase 1
2. **Format mismatch** - SPC700 outputs float, SDL wants int16
3. **Device paused** - SDL_PauseAudioDevice() called somewhere
4. **No APU timing** - SPC700 not running or too slow

---

### Memory Regions Reference

| Region | Address Range | Size | Description |
|--------|--------------|------|-------------|
| WRAM | 0x7E0000-0x7FFFFF | 128KB | Work RAM (game state) |
| SRAM | 0x700000-0x77FFFF | Variable | Save RAM (battery) |
| ROM | 0x000000-0x3FFFFF | Up to 6MB | Cartridge ROM |
| VRAM | PPU Internal | 64KB | Video RAM (tiles, maps) |
| CGRAM | PPU Internal | 512B | Palette RAM (colors) |
| OAM | PPU Internal | 544B | Sprite RAM (objects) |
| ARAM | SPC700 Internal | 64KB | Audio RAM (samples) |

**Access Patterns**:
```cpp
// CPU → WRAM (direct)
uint8_t value = cpu.Read(0x7E0010);

// CPU → VRAM (through PPU registers)
cpu.Write(0x2118, low_byte);   // VRAM write
cpu.Write(0x2119, high_byte);

// CPU → ARAM (through APU registers)
cpu.Write(0x2140, data);  // APU I/O port 0
```

---

## 🎮 Phase 9: Advanced Features (Mesen2 Parity)

### 9.1 Rewind Feature

**User Experience**: Hold button to rewind gameplay

```cpp
class RewindManager {
  void RecordFrame();  // Save state every frame
  void Rewind(int frames);
  
  // Circular buffer (last 10 seconds = 600 frames)
  std::deque<SaveState> frame_history_;
  static constexpr int kMaxFrames = 600;
};
```

**Memory Impact**: ~600 * 100KB = 60MB (acceptable)

**Estimated Effort**: 6-8 hours

---

### 9.2 TAS (Tool-Assisted Speedrun) Input Recording

**Feature**: Record and replay input sequences

```cpp
class InputRecorder {
  struct InputFrame {
    uint16_t buttons;  // SNES controller state
    uint64_t frame_number;
  };
  
  void StartRecording();
  void StopRecording();
  void SaveMovie(const std::string& filename);
  void PlayMovie(const std::string& filename);
  
  std::vector<InputFrame> recorded_inputs_;
};
```

**File Format** (JSON):
```json
{
  "rom_hash": "abc123...",
  "frames": [
    {"frame": 0, "buttons": 0x0000},
    {"frame": 60, "buttons": 0x0080},  // A button pressed
    {"frame": 61, "buttons": 0x0000}
  ]
}
```

**z3ed Integration**:
```bash
z3ed emu record start
# ... play game ...
z3ed emu record stop --output my_gameplay.json
z3ed emu replay --input my_gameplay.json --verify

# AI can generate TAS inputs!
z3ed agent tas --prompt "Beat the first dungeon as fast as possible"
```

**Estimated Effort**: 8-10 hours

---

### 9.3 Comparison Mode

**Feature**: Run two emulator instances side-by-side

**Use Case**: Compare vanilla vs hacked ROM, or before/after AI changes

```cpp
class ComparisonEmulator {
  Emulator emu_a_;
  Emulator emu_b_;
  
  void RunBothFrames();
  void RenderSideBySide();
  void HighlightDifferences();
};
```

**Visualization**:
```
┌──────────────────┬──────────────────┐
│   Vanilla ROM    │   Hacked ROM     │
├──────────────────┼──────────────────┤
│ [Game Screen A]  │ [Game Screen B]  │
│                  │                  │
│ HP: 6 ❤❤❤       │ HP: 12 ❤❤❤❤❤❤   │ ← Difference
│ Rupees: 50       │ Rupees: 50       │
└──────────────────┴──────────────────┘
Memory Diff: 147 bytes different
```

**Estimated Effort**: 12-15 hours

---

## 🛠️ Optimization Summary

### Quick Wins (< 1 week)
1. **Fix audio output** - 4 hours
2. **Add CPU breakpoints** - 6 hours
3. **Enhanced memory viewer** - 6 hours
4. **Frame pacing** - 3 hours

### Medium Term (1-2 months)
5. **Live disassembly** - 10 hours
6. **APU debugger** - 15 hours
7. **Event logger** - 8 hours
8. **AI emulator tools** - 25 hours

### Long Term (3-6 months)
9. **Cycle accuracy** - 30 hours
10. **Dynarec** - 60 hours
11. **TAS recording** - 10 hours
12. **Comparison mode** - 15 hours

---

## 🤖 z3ed Agent Emulator Tools

### New Tool Categories

**Emulator Control**:
```json
{
  "name": "emulator-control",
  "actions": ["start", "stop", "pause", "reset", "step"],
  "description": "Control emulator execution"
}
```

**Memory Tools**:
```json
{
  "name": "emulator-read-memory",
  "parameters": {
    "address": "hex string (e.g., '0x7E0010')",
    "count": "number of bytes",
    "region": "wram|sram|rom|vram|aram"
  }
},
{
  "name": "emulator-write-memory",
  "parameters": {
    "address": "hex string",
    "data": "array of bytes"
  }
}
```

**State Tools**:
```json
{
  "name": "emulator-cpu-state",
  "returns": {
    "pc": "Program Counter",
    "a": "Accumulator",
    "x": "X Register",
    "y": "Y Register",
    "sp": "Stack Pointer",
    "flags": "Processor flags"
  }
},
{
  "name": "emulator-save-state",
  "parameters": {"filename": "string"}
},
{
  "name": "emulator-load-state",
  "parameters": {"filename": "string"}
}
```

**Debug Tools**:
```json
{
  "name": "emulator-add-breakpoint",
  "parameters": {
    "address": "hex string",
    "type": "execute|read|write|access",
    "condition": "optional expression"
  }
},
{
  "name": "emulator-get-hotspots",
  "parameters": {"top_n": "integer"},
  "returns": "array of most-executed code addresses"
}
```

### Example AI Conversations

**Debugging**:
```
User: "Why is Link's HP decreasing randomly?"

Agent: Let me investigate...
       [calls emulator-read-memory address=0x7E0000 count=1]
       → Current HP: 0x60 (6 hearts)
       
       [calls emulator-add-breakpoint address=0x7E0000 type=write]
       → Breakpoint set
       
       [waits for breakpoint hit]
       → Breakpoint hit! PC=$00:8234
       
       [calls emulator-read-memory address=0x8234 count=10]
       → Disassembly shows: Enemy collision handler
       
Agent: "Link's HP is being modified by the enemy collision code at $00:8234.
       The collision box is checking at the wrong Y offset (+8 instead of +16).
       This causes damage when Link is near but not touching enemies."
```

**Testing**:
```
User: "Test that the new sword does double damage"

Agent: [calls emulator-load-state file=enemy_encounter.sfc]
       [calls emulator-read-memory address=0x7E0010 count=2]  # Link's damage
       → Current damage: 0x0004
       
       [calls emulator-write-memory address=0x7E0010 data=[0x08]]  # Set 2x
       
       [simulates sword swing - could use input recording]
       
       [calls emulator-read-memory address=0x7EF280]  # Enemy HP
       → Enemy lost 8 HP (was 4 before)
       
Agent: "Confirmed! The new sword deals 8 damage instead of 4. 
       The 2x multiplier is working correctly."
```

---

## 📁 File Structure for New Features

```
src/app/emu/
├── debug/
│   ├── breakpoint_manager.{h,cc}          # NEW
│   ├── watchpoint_manager.{h,cc}          # NEW
│   ├── disassembly_viewer.{h,cc}          # EXISTS - enhance
│   ├── memory_viewer.{h,cc}               # NEW
│   ├── event_logger.{h,cc}                # NEW
│   ├── performance_profiler.{h,cc}        # NEW
│   └── apu_inspector.{h,cc}               # NEW
├── tas/
│   ├── input_recorder.{h,cc}              # NEW
│   ├── movie_file.{h,cc}                  # NEW
│   └── rewind_manager.{h,cc}              # NEW
└── emulator.{h,cc}                        # EXISTS - integrate above

src/cli/commands/agent/
├── emulator_tools.{h,cc}                  # NEW - z3ed agent emulator commands
└── test_scenario_runner.{h,cc}            # NEW - automated testing

src/cli/service/agent/
└── tools/
    ├── emulator_control_tool.cc           # NEW
    ├── emulator_memory_tool.cc            # NEW
    └── emulator_debug_tool.cc             # NEW
```

---

## 🎨 UI Mockups

### Debugger Layout (ImGui)

```
┌────────────────────────────────────────────────────────────────┐
│ YAZE Emulator - Debugging Mode                                │
├───────────────┬────────────────────────┬───────────────────────┤
│               │                        │                       │
│ Disassembly   │   Game Display         │   Registers          │
│               │                        │                       │
│ 00:8000 LDA   │  ┌──────────────────┐  │  A: 0x00  X: 0x05    │
│ 00:8002 STA   │  │                  │  │  Y: 0xFF  SP: 0xEF   │
│►00:8004 JMP   │  │    [Zelda 3]     │  │  PC: 0x8004          │
│ 00:8007 NOP   │  │                  │  │  PB: 0x00  DB: 0x00  │
│ 00:8008 RTL   │  └──────────────────┘  │  Flags: nv--dizc     │
│               │                        │                       │
├───────────────┼────────────────────────┼───────────────────────┤
│               │                        │                       │
│ Memory        │   Event Timeline       │   Stack              │
│               │                        │                       │
│ 7E0000  00 05 │  Frame 123:            │  0x1FF: 0x00         │
│ 7E0008  3C 00 │  [NMI]──[DMA]──[IRQ]   │  0x1FE: 0x80         │
│ 7E0010  1F 00 │                        │  0x1FD: 0x04 ← SP    │
│               │                        │                       │
└───────────────┴────────────────────────┴───────────────────────┘
```

### APU Debugger Layout

```
┌────────────────────────────────────────────────────────────────┐
│ SPC700 Audio Debugger                                          │
├────────────────────┬───────────────────────────────────────────┤
│ SPC700 Disassembly │ DSP State                                │
│                    │                                           │
│ 0100 MOV A,#$00    │ Master Volume: L=127 R=127               │
│►0102 MOV (X),A     │ Echo: OFF  FIR: Standard                 │
│ 0104 INCX          │                                           │
│                    │ Channel 0: ████████░░░░ (75%)            │
├────────────────────┤   VOL: L=100 R=100  PITCH=2048           │
│ Audio RAM (64KB)   │   ADSR: Attack=15 Decay=7 Sustain=7      │
│                    │   Sample: 0x0000-0x1234 (BRR)            │
│ 0000  00 00 00 00  │                                           │
│ 0010  BRR BRR ...  │ Channel 1: ░░░░░░░░░░░░ (0%)            │
│                    │   (Inactive)                              │
│ [Export Samples]   │                                           │
└────────────────────┴───────────────────────────────────────────┘
```

---

## 🚀 Performance Targets

### Current Performance
- **Emulation Speed**: ~60 FPS (with frame skipping)
- **CPU Usage**: 40-60% (one core)
- **Memory**: 80MB (emulator only)
- **Accuracy**: ~85% (some timing issues)

### Target Performance (Post-Optimization)
- **Emulation Speed**: Solid 60 FPS (no skipping)
- **CPU Usage**: 20-30% (with dynarec)
- **Memory**: 100MB (with debug features)
- **Accuracy**: 98%+ (cycle-accurate)

### Optimization Strategy Priority
1. **Audio fix** - Enables testing with sound
2. **Frame pacing** - Eliminates jitter
3. **Hotspot profiling** - Identifies slow code
4. **Cycle accuracy** - Fixes timing bugs
5. **Dynarec** - 3x speed boost

---

## 🧪 Testing Integration

### Automated Emulator Tests (z3ed)

**Unit Tests**:
```bash
# Test CPU instructions
z3ed emu test cpu --test-suite 65816_opcodes.json

# Test PPU rendering
z3ed emu test ppu --test-rom ppu_test.sfc --frames 600

# Test APU audio
z3ed emu test apu --test-rom audio_test.sfc --export samples.wav
```

**Regression Tests**:
```bash
# Run all ROM compatibility tests
z3ed emu test regression --rom-dir test_roms/ --report report.html

# Compare with reference emulator
z3ed emu test compare --rom zelda3.sfc --reference bsnes --frames 1000
```

**AI-Generated Tests**:
```bash
z3ed agent test-scenario --prompt "Test that bombs damage enemies"

# AI generates emulator test script
{
  "setup": {
    "load_state": "link_with_bombs.sfc"
  },
  "steps": [
    {"action": "place-bomb", "x": 100, "y": 100},
    {"action": "wait-frames", "count": 60},
    {"action": "spawn-enemy", "type": "octorok", "x": 110, "y": 100},
    {"action": "wait-frames", "count": 60},
    {"action": "assert-memory", "address": "0x7EF280", "comparison": "less_than", "reference": "initial"}
  ]
}
```

---

## 🔌 z3ed Agent + Emulator Integration

### New Agent Tools

**Tool Registration** (automatic):
```cpp
// src/cli/service/agent/tool_dispatcher.cc
void ToolDispatcher::RegisterEmulatorTools(Emulator* emulator) {
  RegisterTool("emulator-start", [emulator]() { /* ... */ });
  RegisterTool("emulator-stop", [emulator]() { /* ... */ });
  RegisterTool("emulator-read-memory", [emulator](args) { /* ... */ });
  RegisterTool("emulator-cpu-state", [emulator]() { /* ... */ });
  RegisterTool("emulator-screenshot", [emulator]() { /* ... */ });
  // ... 15 more tools
}
```

**Example Conversations**:

**1. Live Debugging**:
```
User: "Why does Link keep getting stuck in walls?"

Agent: Let me debug this...
       [calls emulator-load-state file=link_stuck.sfc]
       [calls emulator-cpu-state]
       → PC=$00:9ABC (Link movement handler)
       
       [calls emulator-read-memory address=0x7E0022 count=2]
       → Link X: 0x0478, Y: 0x0234
       
       [calls emulator-read-memory address=0x7E0020 count=2]
       → Subpixel X: 0x0F, Y: 0x0F (stuck at boundary!)
       
       [calls emulator-add-breakpoint address=0x9ABC type=execute]
       [calls emulator-step]
       
Agent: "Found it! The collision detection at $00:9ABC is using
       integer division instead of proper subpixel handling.
       When Link's subpixel position is 0x0F, the boundary
       check fails and he gets stuck."
```

**2. Performance Analysis**:
```
User: "The overworld feels laggy after my changes"

Agent: [calls emulator-start]
       [calls emulator-profile-start]
       [waits 300 frames = 5 seconds]
       [calls emulator-profile-stop]
       [calls emulator-get-hotspots top_n=10]
       
       → Top hotspot: $00:8500 (45% of cycles)
       
       [calls emulator-disassemble address=0x8500 count=20]
       
Agent: "Your tile drawing code at $00:8500 is running every frame
       and taking 45% of CPU time! The original game only runs this
       when tiles change. Consider adding a dirty flag check."
```

**3. Automated ROM Testing**:
```
User: "Test my randomizer hack thoroughly"

Agent: I'll run comprehensive tests...
       [calls emulator-load-state file=randomizer_start.sfc]
       
       For each dungeon:
         [calls emulator-teleport-link dungeon=N]
         [calls emulator-run-frames count=3600]  # 60 seconds
         [calls emulator-screenshot name=dungeon_N.png]
         [calls emulator-check-crashes]
         [calls emulator-verify-items-reachable]
       
       [calls emulator-generate-report]
       
Agent: "Tested all 12 dungeons. Found issues:
       - Dungeon 3: Softlock at room 0x34 (missing key)
       - Dungeon 7: Crash at room 0x12 (invalid sprite ID)
       All other dungeons: ✅ PASS"
```

---

## 🎓 Learning from Mesen2

### What Makes Mesen2 Great

1. **Comprehensive Debugging**
   - Every hardware event is logged
   - Full state inspection at any time
   - Breakpoints on everything (CPU, PPU, APU, memory)

2. **Performance**
   - Cycle-accurate yet fast (dynarec)
   - 60 FPS even with debugging enabled
   - Efficient state save/restore

3. **User Experience**
   - Integrated debugger in same window as game
   - Real-time visualization of state changes
   - Intuitive UI for complex operations

4. **Extensibility**
   - Lua scripting for automation
   - Event system for plugins
   - Export capabilities (traces, memory dumps)

### Our Unique Advantages

**YAZE + z3ed has features Mesen2 doesn't**:

1. **AI Integration**
   - Natural language debugging
   - Automated test generation
   - Intelligent crash analysis

2. **ROM Editor Integration**
   - Edit ROM while emulator runs
   - See changes immediately
   - Debugging informs editing

3. **Collaborative Debugging**
   - Share emulator state with team
   - Remote debugging via gRPC
   - AI agent can help multiple users

4. **Cross-Platform Testing**
   - Same emulator in CLI and GUI
   - Automated test scenarios
   - CI/CD integration

---

## 📊 Resource Requirements

### Development Time Estimates

| Phase | Hours | Weeks (Part-Time) |
|-------|-------|-------------------|
| Audio Fix | 4 | 0.5 |
| Basic Debugger | 20 | 2.5 |
| SPC700 Debugger | 15 | 2 |
| AI Integration | 25 | 3 |
| Performance Opts | 40 | 5 |
| **Total** | **104** | **13** |

### Memory Requirements

| Feature | RAM Usage |
|---------|-----------|
| Base Emulator | 80 MB |
| Breakpoint Manager | +2 MB |
| Event Logger | +5 MB (10K events) |
| Rewind Buffer | +60 MB (10 seconds) |
| Performance Profiler | +10 MB |
| **Total** | **~160 MB** |

### CPU Requirements

| Configuration | CPU % (Single Core) |
|--------------|---------------------|
| Interpreter Only | 40-60% |
| + Debugging | 50-70% |
| + Profiling | 60-80% |
| + Dynarec (future) | 20-30% |

---

## 🛣️ Recommended Implementation Order

### Month 1: Foundation
**Weeks 1-2**: Audio fix + Basic breakpoints  
**Weeks 3-4**: Memory viewer + Disassembly enhancements

### Month 2: Audio & Events
**Weeks 5-6**: SPC700 debugger + APU inspector  
**Weeks 7-8**: Event logger + Timeline view

### Month 3: AI Integration
**Weeks 9-10**: z3ed emulator tools + Agent integration  
**Weeks 11-12**: Automated testing + Scenario runner

### Month 4: Performance
**Weeks 13-14**: Cycle accuracy refactor  
**Weeks 15-16**: Dynarec or JIT library integration

### Month 5: Polish
**Weeks 17-18**: UI/UX improvements  
**Weeks 19-20**: Documentation + Examples

---

## 🔮 Future Vision: AI-Powered ROM Hacking

### The Ultimate Workflow

1. **AI Explores the Game**
```
z3ed agent explore --rom zelda3.sfc --goal "Find all heart piece locations"

# Agent:
# - Loads ROM in emulator
# - Runs around overworld automatically
# - Detects heart piece spawn events via memory watchpoints
# - Screenshots each location
# - Generates report with coordinates
```

2. **AI Debugs Your Hack**
```
z3ed agent debug --rom my_hack.sfc --issue "Boss doesn't take damage"

# Agent:
# - Loads hack in emulator
# - Adds breakpoints on damage handlers
# - Simulates boss fight
# - Identifies missing damage check
# - Suggests code fix with hex addresses
```

3. **AI Generates TAS**
```
z3ed agent speedrun --rom zelda3.sfc --category "any%"

# Agent:
# - Studies game mechanics via emulator
# - Discovers optimal movement patterns
# - Generates frame-perfect input sequence
# - Exports TAS movie file
```

4. **AI Validates Randomizers**
```
z3ed agent validate --rom randomizer.sfc --seed 12345

# Agent:
# - Generates logic graph from ROM
# - Simulates playthrough via emulator
# - Verifies all items are reachable
# - Checks for softlocks
# - Rates difficulty
```

---

## 🐛 Appendix A: Audio Debugging Checklist

**Run these checks to diagnose audio issues**:

### Check 1: Device Status
```cpp
SDL_AudioStatus status = SDL_GetAudioDeviceStatus(audio_device_);
printf("Audio Status: %d (1=playing, 2=paused, 3=stopped)\n", status);
// Expected: 1 (SDL_AUDIO_PLAYING)
```

### Check 2: Queue Size
```cpp
uint32_t queued = SDL_GetQueuedAudioSize(audio_device_);
printf("Queued Audio: %u bytes\n", queued);
// Expected: 1000-8000 bytes (1-2 frames worth)
// If 0: Not queueing
// If >50000: Overflowing, audio thread stalled
```

### Check 3: Sample Validation
```cpp
int16_t* samples = audio_buffer_;
bool all_zero = true;
for (int i = 0; i < wanted_samples_ * 2; i++) {
  if (samples[i] != 0) {
    all_zero = false;
    break;
  }
}
if (all_zero) {
  printf("ERROR: All audio samples are zero! SPC700 not outputting.\n");
}
```

### Check 4: Buffer Allocation
```cpp
// In window.cc:128, verify size calculation:
// For 48000Hz, 60 FPS, stereo:
// samples_per_frame = 48000 / 60 = 800
// stereo_samples = 800 * 2 = 1600 int16_t
// Size should be: 1600, NOT 3840

printf("Audio buffer size: %zu int16_t\n", audio_buffer_.size());
// Expected: 1600-1920 (for 60-50Hz)
```

### Check 5: SPC700 Execution
```cpp
// Verify SPC700 is actually running
uint64_t apu_cycles = snes_.apu().GetCycles();
// Should increase every frame
// If stuck: SPC700 deadlock or not running
```

### Quick Fixes to Try

**Fix A: Force Unpause**
```cpp
// emulator.cc, in RunFrame():
SDL_PauseAudioDevice(audio_device_, 0);  // Force play state
```

**Fix B: Larger Queue**
```cpp
// If buffer underruns, queue more:
SDL_QueueAudio(audio_device_, audio_buffer_, wanted_samples_ * 4 * 2);  // 2 frames
```

**Fix C: Clear Stale Queue**
```cpp
// If queue is stuck:
if (SDL_GetQueuedAudioSize(audio_device_) > 50000) {
  SDL_ClearQueuedAudio(audio_device_);  // Reset
}
```

---

## 📝 Appendix B: Mesen2 Feature Reference

### Debugger Windows (Inspiration)

1. **CPU Debugger**: Disassembly, registers, breakpoints
2. **Memory Tools**: Hex viewer, search, compare
3. **PPU Viewer**: Layer toggles, VRAM, OAM, palettes
4. **Event Viewer**: Timeline of all hardware events
5. **Trace Logger**: Full execution log with filters
6. **Performance Profiler**: Hotspot analysis
7. **Script Window**: Lua scripting for automation

### Event Types Tracked

- **CPU**: NMI, IRQ, BRK instruction, RESET
- **PPU**: V-Blank, H-Blank, Mode change, Sprite overflow
- **DMA**: General DMA, HDMA, channels used
- **APU**: Sample playback, DSP writes, Timer IRQ
- **Cart**: Save RAM write, special chip events

### Trace Logger Format

```
Cycle    PC      Opcode  A  X  Y  SP  Flags  Event
0        $00FFD9 SEI     00 00 00 1FF nvmxdiZc
1        $00FFDA CLI     00 00 00 1FF nvmxdizc
2        $00FFDB JMP     00 00 00 1FF nvmxdizc
...
16749    $008234 LDA     05 00 00 1EF Nvmxdizc [NMI]
```

---

## 🎯 Success Criteria

### Phase 1 Complete When:
- ✅ Audio plays correctly from SDL2
- ✅ Can hear game music and sound effects
- ✅ No audio crackling or dropouts
- ✅ Audio buffer diagnostics implemented

### Phase 2 Complete When:
- ✅ Can set breakpoints on any address
- ✅ Disassembly view shows live execution
- ✅ Memory viewer has multi-region support
- ✅ z3ed CLI can control debugger

### Phase 3 Complete When:
- ✅ SPC700 debugger shows all APU state
- ✅ Can visualize audio channels
- ✅ Can export audio samples to WAV

### Phase 4 Complete When:
- ✅ AI agent can read emulator memory
- ✅ AI agent can control emulation
- ✅ AI can generate test scenarios
- ✅ Automated ROM testing works

### Phase 5 Complete When:
- ✅ Emulator is cycle-accurate
- ✅ 60 FPS maintained with debugging
- ✅ Dynarec provides 3x speedup
- ✅ All Mesen2 features implemented

---

## 🎓 Learning Resources

### SNES Emulation
- [SNES Development Manual](https://www.romhacking.net/documents/226/)
- [Fullsnes by nocash](https://problemkaputt.de/fullsnes.htm)
- [bsnes source code](https://github.com/bsnes-emu/bsnes) - Reference implementation
- [Mesen2 source code](https://github.com/SourMesen/Mesen2) - Feature inspiration

### Audio Debugging
- [SPC700 Reference](https://wiki.superfamicom.org/spc700-reference)
- [DSP Register Guide](https://wiki.superfamicom.org/dsp-registers)
- [BRR Audio Format](https://wiki.superfamicom.org/bit-rate-reduction-brr)

### Performance Optimization
- [Fast SNES Emulation](https://github.com/arm9/snes9x-rpi) - ARM optimization
- [Dynarec Tutorial](https://github.com/rasky/r64emu/wiki/Dynamic-Recompilation) - N64 but applicable

---

## 🙏 Credits & Acknowledgments

**Emulator Core**: Based on LakeSnes by elzo-d  
**Debugger Inspiration**: Mesen2 by SourMesen  
**AI Integration**: z3ed agent system  
**Documentation**: With love (and Puerto Rican soup! 🍲)

---

*Document Version: 1.0*  
*Last Updated: October 8, 2025*  
*Next Review: After Audio Fix*  
*Sleep Well! 😴*

