diff --git a/docs/E1-emulator-enhancement-roadmap.md b/docs/E1-emulator-enhancement-roadmap.md new file mode 100644 index 00000000..79931e0d --- /dev/null +++ b/docs/E1-emulator-enhancement-roadmap.md @@ -0,0 +1,1939 @@ +# 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(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(audio_frequency / 50 * 2); // Stereo +``` + +### Quick Win Actions +**File**: `window.cc` +**Line**: 128 +**Change**: +```cpp +// Before: +window.audio_buffer_ = std::make_shared(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((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 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 ListBreakpoints(); + +private: + std::unordered_map 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 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 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 GetHotspots(int top_n = 10); + +private: + std::unordered_map execution_counts_; + std::shared_ptr 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 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 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( + frame_end - frame_start); + + auto target_duration = std::chrono::microseconds( + static_cast(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, 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 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& 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 params; + }; + + absl::Status RunScenario(const std::vector& 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 GetHotFunctions(int top_n = 20); + void ExportFlameGraph(const std::string& filename); + +private: + std::unordered_map 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 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 GetEvents(uint64_t start_cycle, uint64_t end_cycle); + void Clear(); + +private: + std::deque 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 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 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! ๐Ÿ˜ด* +