yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emulator.cc
Go to the documentation of this file.
1#include "app/emu/emulator.h"
2
3#include <cstdint>
4#include <fstream>
5#include <vector>
6
7#include "app/core/window.h"
8#include "util/log.h"
9
10namespace yaze::core {
11 extern bool g_window_is_resizing;
12}
13
18#include "app/gui/color.h"
20#include "app/gui/icons.h"
22#include "imgui/imgui.h"
23
24namespace yaze {
25namespace emu {
26
28 // Don't call Cleanup() in destructor - renderer is already destroyed
29 // Just stop emulation
30 running_ = false;
31}
32
34 // Stop emulation
35 running_ = false;
36
37 // Don't try to destroy PPU texture during shutdown
38 // The renderer is destroyed before the emulator, so attempting to
39 // call renderer_->DestroyTexture() will crash
40 // The texture will be cleaned up automatically when SDL quits
41 ppu_texture_ = nullptr;
42
43 // Reset state
44 snes_initialized_ = false;
45}
46
47void Emulator::Initialize(gfx::IRenderer* renderer, const std::vector<uint8_t>& rom_data) {
48 // This method is now optional - emulator can be initialized lazily in Run()
50 rom_data_ = rom_data;
51
52 // Register emulator cards with EditorCardManager
53 auto& card_manager = gui::EditorCardManager::Get();
54
55 card_manager.RegisterCard({
56 .card_id = "emulator.cpu_debugger",
57 .display_name = "CPU Debugger",
58 .icon = ICON_MD_BUG_REPORT,
59 .category = "Emulator",
60 .visibility_flag = &show_cpu_debugger_,
61 .priority = 10
62 });
63
64 card_manager.RegisterCard({
65 .card_id = "emulator.memory_viewer",
66 .display_name = "Memory Viewer",
67 .icon = ICON_MD_MEMORY,
68 .category = "Emulator",
69 .visibility_flag = &show_memory_viewer_,
70 .priority = 20
71 });
72
73 card_manager.RegisterCard({
74 .card_id = "emulator.ppu_viewer",
75 .display_name = "PPU Viewer",
76 .icon = ICON_MD_GRID_VIEW,
77 .category = "Emulator",
78 .visibility_flag = &show_ppu_viewer_,
79 .priority = 30
80 });
81
82 card_manager.RegisterCard({
83 .card_id = "emulator.audio_mixer",
84 .display_name = "Audio Mixer",
85 .icon = ICON_MD_AUDIO_FILE,
86 .category = "Emulator",
87 .visibility_flag = &show_audio_mixer_,
88 .priority = 40
89 });
90
91 printf("[Emulator] Registered 4 cards with EditorCardManager\n");
92
93 // Reset state for new ROM
94 running_ = false;
95 snes_initialized_ = false;
96
97 // Initialize audio backend if not already done
98 if (!audio_backend_) {
101
102 audio::AudioConfig config;
103 config.sample_rate = 48000;
104 config.channels = 2;
105 // Use moderate buffer size - 1024 samples = ~21ms latency
106 // This is a good balance between latency and stability
107 config.buffer_frames = 1024;
109
110 if (!audio_backend_->Initialize(config)) {
111 LOG_ERROR("Emulator", "Failed to initialize audio backend");
112 } else {
113 LOG_INFO("Emulator", "Audio backend initialized: %s",
114 audio_backend_->GetBackendName().c_str());
115 }
116 }
117
118 // Set up CPU breakpoint callback
119 snes_.cpu().on_breakpoint_hit_ = [this](uint32_t pc) -> bool {
121 };
122
123 // Set up instruction recording callback for DisassemblyViewer
124 snes_.cpu().on_instruction_executed_ = [this](uint32_t address, uint8_t opcode,
125 const std::vector<uint8_t>& operands,
126 const std::string& mnemonic,
127 const std::string& operand_str) {
128 disassembly_viewer_.RecordInstruction(address, opcode, operands, mnemonic, operand_str);
129 };
130
131 initialized_ = true;
132}
133
134void Emulator::Run(Rom* rom) {
135 // Lazy initialization: set renderer from Controller if not set yet
136 if (!renderer_) {
137 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
138 "Emulator renderer not initialized");
139 return;
140 }
141
142 // Initialize audio backend if not already done (lazy initialization)
143 if (!audio_backend_) {
146
147 audio::AudioConfig config;
148 config.sample_rate = 48000;
149 config.channels = 2;
150 // Use moderate buffer size - 1024 samples = ~21ms latency
151 // This is a good balance between latency and stability
152 config.buffer_frames = 1024;
154
155 if (!audio_backend_->Initialize(config)) {
156 LOG_ERROR("Emulator", "Failed to initialize audio backend");
157 } else {
158 LOG_INFO("Emulator", "Audio backend initialized (lazy): %s",
159 audio_backend_->GetBackendName().c_str());
160 }
161 }
162
163 // Initialize input manager if not already done
166 LOG_ERROR("Emulator", "Failed to initialize input manager");
167 } else {
168 LOG_INFO("Emulator", "Input manager initialized: %s",
170 }
171 }
172
173 // Initialize SNES and create PPU texture on first run
174 // This happens lazily when user opens the emulator window
175 if (!snes_initialized_ && rom->is_loaded()) {
176 // Create PPU texture with correct format for SNES emulator
177 // ARGB8888 matches the XBGR format used by the SNES PPU (pixel format 1)
178 if (!ppu_texture_) {
180 512, 480, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING);
181 if (ppu_texture_ == NULL) {
182 printf("Failed to create PPU texture: %s\n", SDL_GetError());
183 return;
184 }
185 }
186
187 // Initialize SNES with ROM data (either from Initialize() or from rom parameter)
188 if (rom_data_.empty()) {
189 rom_data_ = rom->vector();
190 }
192
193 // Note: DisassemblyViewer recording is always enabled via callback
194 // No explicit setup needed - callback is set in Initialize()
195
196 // Note: PPU pixel format set to 1 (XBGR) in Init() which matches ARGB8888 texture
197
198 wanted_frames_ = 1.0 / (snes_.memory().pal_timing() ? 50.0 : 60.0);
199 wanted_samples_ = 48000 / (snes_.memory().pal_timing() ? 50 : 60);
200 snes_initialized_ = true;
201
202 count_frequency = SDL_GetPerformanceFrequency();
203 last_count = SDL_GetPerformanceCounter();
204 time_adder = 0.0;
205 frame_count_ = 0;
206 fps_timer_ = 0.0;
207 current_fps_ = 0.0;
208
209 // Start emulator in running state by default
210 // User can press Space to pause if needed
211 running_ = true;
212 }
213
214 RenderNavBar();
215
216 // Auto-pause emulator during window resize to prevent crashes
217 // MODERN APPROACH: Only pause on actual window resize, not focus loss
218 static bool was_running_before_resize = false;
219
220 // Check if window is being resized (set in HandleEvents)
222 was_running_before_resize = true;
223 running_ = false;
224 } else if (!yaze::core::g_window_is_resizing && !running_ && was_running_before_resize) {
225 // Auto-resume after resize completes
226 running_ = true;
227 was_running_before_resize = false;
228 }
229
230 // REMOVED: Aggressive focus-based pausing
231 // Modern emulators (RetroArch, bsnes, etc.) continue running in background
232 // Users can manually pause with Space if they want to save CPU/battery
233
234 if (running_) {
235 // Poll input and update SNES controller state
236 input_manager_.Poll(&snes_, 1); // Player 1
237
238 uint64_t current_count = SDL_GetPerformanceCounter();
239 uint64_t delta = current_count - last_count;
240 last_count = current_count;
241 double seconds = delta / (double)count_frequency;
242 time_adder += seconds;
243
244 // Cap time accumulation to prevent spiral of death and improve stability
245 if (time_adder > wanted_frames_ * 3.0) {
247 }
248
249 // Track frames to skip for performance
250 int frames_to_process = 0;
251 while (time_adder >= wanted_frames_ - 0.002) {
253 frames_to_process++;
254 }
255
256 // Limit maximum frames to process (prevent spiral of death)
257 if (frames_to_process > 4) {
258 frames_to_process = 4;
259 }
260
261 if (snes_initialized_ && frames_to_process > 0) {
262 // Process frames (skip rendering for all but last frame if falling behind)
263 for (int i = 0; i < frames_to_process; i++) {
264 bool should_render = (i == frames_to_process - 1);
265
266 // Run frame
267 if (turbo_mode_) {
268 snes_.RunFrame();
269 }
270 snes_.RunFrame();
271
272 // Track FPS
273 frame_count_++;
275 if (fps_timer_ >= 1.0) {
277 frame_count_ = 0;
278 fps_timer_ = 0.0;
279 }
280
281 // Only render and handle audio on the last frame
282 if (should_render) {
283 // SMOOTH AUDIO BUFFERING
284 // Strategy: Always queue samples, never drop. Use dynamic rate control
285 // to keep buffer at target level. This prevents pops and glitches.
286
287 if (audio_backend_) {
288 auto audio_status = audio_backend_->GetStatus();
289 uint32_t queued_frames = audio_status.queued_frames;
290
291 // Synchronize DSP frame boundary for proper resampling
292 snes_.apu().dsp().NewFrame();
293
294 // Target buffer: 2.0 frames for low latency with safety margin
295 // This is similar to how bsnes/Mesen handle audio buffering
296 const uint32_t target_buffer = wanted_samples_ * 2;
297 const uint32_t min_buffer = wanted_samples_;
298 const uint32_t max_buffer = wanted_samples_ * 4;
299
300 // Generate samples from SNES APU/DSP
302
303 // CRITICAL: Always queue all generated samples - never drop
304 // Dropping samples causes audible pops and glitches
305 int num_samples = wanted_samples_ * 2; // Stereo (L+R channels)
306
307 // Only skip queueing if buffer is dangerously full (>4 frames)
308 // This prevents unbounded buffer growth but is rare in practice
309 if (queued_frames < max_buffer) {
310 if (!audio_backend_->QueueSamples(audio_buffer_, num_samples)) {
311 static int error_count = 0;
312 if (++error_count % 300 == 0) {
313 LOG_WARN("Emulator", "Failed to queue audio (count: %d)", error_count);
314 }
315 }
316 } else {
317 // Buffer overflow - skip this frame's audio
318 // This should rarely happen with proper timing
319 static int overflow_count = 0;
320 if (++overflow_count % 60 == 0) {
321 LOG_WARN("Emulator", "Audio buffer overflow (count: %d, queued: %u)",
322 overflow_count, queued_frames);
323 }
324 }
325 }
326
327 // Update PPU texture only on rendered frames
328 void* ppu_pixels_;
329 int ppu_pitch_;
330 if (renderer_->LockTexture(ppu_texture_, NULL, &ppu_pixels_, &ppu_pitch_)) {
331 snes_.SetPixels(static_cast<uint8_t*>(ppu_pixels_));
333
334 // WORKAROUND: Tiny delay after texture unlock to prevent macOS Metal crash
335 // macOS CoreAnimation/Metal driver bug in layer_presented() callback
336 // Without this, rapid texture updates corrupt Metal's frame tracking
337 SDL_Delay(1);
338 }
339 }
340 }
341 }
342 }
343
345}
346
348 // Apply modern theming with safety checks
349 try {
350 auto& theme_manager = gui::ThemeManager::Get();
351 const auto& theme = theme_manager.GetCurrentTheme();
352
353 // Modern EditorCard-based layout - modular and flexible
354 static bool show_cpu_debugger_ = true;
355 static bool show_ppu_display_ = true;
356 static bool show_memory_viewer_ = false;
357 static bool show_breakpoints_ = false;
358 static bool show_performance_ = true;
359 static bool show_ai_agent_ = false;
360 static bool show_save_states_ = false;
361 static bool show_keyboard_config_ = false;
362 static bool show_apu_debugger_ = true;
363
364 // Create session-aware cards
365 static gui::EditorCard cpu_card(ICON_MD_MEMORY " CPU Debugger", ICON_MD_MEMORY);
366 static gui::EditorCard ppu_card(ICON_MD_VIDEOGAME_ASSET " PPU Display",
368 static gui::EditorCard memory_card(ICON_MD_DATA_ARRAY " Memory Viewer",
370 static gui::EditorCard breakpoints_card(ICON_MD_BUG_REPORT " Breakpoints",
372 static gui::EditorCard performance_card(ICON_MD_SPEED " Performance",
374 static gui::EditorCard ai_card(ICON_MD_SMART_TOY " AI Agent", ICON_MD_SMART_TOY);
375 static gui::EditorCard save_states_card(ICON_MD_SAVE " Save States", ICON_MD_SAVE);
376 static gui::EditorCard keyboard_card(ICON_MD_KEYBOARD " Keyboard Config",
378 static gui::EditorCard apu_debug_card(ICON_MD_MUSIC_NOTE " APU Debugger",
380
381 // Configure default positions
382 static bool cards_configured = false;
383 if (!cards_configured) {
384 cpu_card.SetDefaultSize(400, 500);
386
387 ppu_card.SetDefaultSize(550, 520);
389
390 memory_card.SetDefaultSize(800, 600);
392
393 breakpoints_card.SetDefaultSize(400, 350);
395
396 performance_card.SetDefaultSize(350, 300);
398
399 ai_card.SetDefaultSize(500, 450);
401
402 save_states_card.SetDefaultSize(400, 300);
404
405 keyboard_card.SetDefaultSize(450, 400);
407
408 apu_debug_card.SetDefaultSize(500, 400);
410
411 cards_configured = true;
412 }
413
414 // CPU Debugger Card
415 if (show_cpu_debugger_) {
416 if (cpu_card.Begin(&show_cpu_debugger_)) {
418 }
419 cpu_card.End();
420 }
421
422 // PPU Display Card
423 if (show_ppu_display_) {
424 if (ppu_card.Begin(&show_ppu_display_)) {
426 }
427 ppu_card.End();
428 }
429
430 // Memory Viewer Card
432 if (memory_card.Begin(&show_memory_viewer_)) {
434 }
435 memory_card.End();
436 }
437
438 // Breakpoints Card
439 if (show_breakpoints_) {
440 if (breakpoints_card.Begin(&show_breakpoints_)) {
442 }
443 breakpoints_card.End();
444 }
445
446 // Performance Monitor Card
447 if (show_performance_) {
448 if (performance_card.Begin(&show_performance_)) {
450 }
451 performance_card.End();
452 }
453
454 // AI Agent Card
455 if (show_ai_agent_) {
456 if (ai_card.Begin(&show_ai_agent_)) {
458 }
459 ai_card.End();
460 }
461
462 // Save States Card
463 if (show_save_states_) {
464 if (save_states_card.Begin(&show_save_states_)) {
466 }
467 save_states_card.End();
468 }
469
470 // Keyboard Configuration Card
471 if (show_keyboard_config_) {
472 if (keyboard_card.Begin(&show_keyboard_config_)) {
474 }
475 keyboard_card.End();
476 }
477
478 // APU Debugger Card
479 if (show_apu_debugger_) {
480 if (apu_debug_card.Begin(&show_apu_debugger_)) {
482 }
483 apu_debug_card.End();
484 }
485
486 } catch (const std::exception& e) {
487 // Fallback to basic UI if theming fails
488 ImGui::Text("Error loading emulator UI: %s", e.what());
489 if (ImGui::Button("Retry")) {
490 // Force theme manager reinitialization
491 auto& theme_manager = gui::ThemeManager::Get();
492 theme_manager.InitializeBuiltInThemes();
493 }
494 }
495}
496
498 // Delegate to UI layer
499 ui::RenderSnesPpu(this);
500}
501
503 // Delegate to UI layer
504 ui::RenderNavBar(this);
505}
506
507// REMOVED: HandleEvents() - replaced by ui::InputHandler::Poll()
508// The old ImGui::IsKeyPressed/Released approach was event-based and didn't work properly
509// for continuous game input. Now using SDL_GetKeyboardState() for proper polling.
510
512 // Delegate to UI layer
514}
515
517 // Delegate to UI layer
519}
520
522 try {
523 auto& theme_manager = gui::ThemeManager::Get();
524 const auto& theme = theme_manager.GetCurrentTheme();
525
526 // Debugger controls toolbar
527 if (ImGui::Button(ICON_MD_PLAY_ARROW)) { running_ = true; }
528 ImGui::SameLine();
529 if (ImGui::Button(ICON_MD_PAUSE)) { running_ = false; }
530 ImGui::SameLine();
531 if (ImGui::Button(ICON_MD_SKIP_NEXT " Step")) {
532 if (!running_) snes_.cpu().RunOpcode();
533 }
534 ImGui::SameLine();
535 if (ImGui::Button(ICON_MD_REFRESH)) { snes_.Reset(true); }
536
537 ImGui::Separator();
538
539 // Breakpoint controls
540 static char bp_addr[16] = "00FFD9";
541 ImGui::Text(ICON_MD_BUG_REPORT " Breakpoints:");
542 ImGui::PushItemWidth(100);
543 ImGui::InputText("##BPAddr", bp_addr, IM_ARRAYSIZE(bp_addr),
544 ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
545 ImGui::PopItemWidth();
546 ImGui::SameLine();
547 if (ImGui::Button(ICON_MD_ADD " Add")) {
548 uint32_t addr = std::strtoul(bp_addr, nullptr, 16);
551 "", absl::StrFormat("BP at $%06X", addr));
552 }
553
554 // List breakpoints
555 ImGui::BeginChild("##BPList", ImVec2(0, 100), true);
556 for (const auto& bp : breakpoint_manager_.GetAllBreakpoints()) {
558 bool enabled = bp.enabled;
559 if (ImGui::Checkbox(absl::StrFormat("##en%d", bp.id).c_str(), &enabled)) {
560 breakpoint_manager_.SetEnabled(bp.id, enabled);
561 }
562 ImGui::SameLine();
563 ImGui::Text("$%06X", bp.address);
564 ImGui::SameLine();
565 ImGui::TextDisabled("(hits: %d)", bp.hit_count);
566 ImGui::SameLine();
567 if (ImGui::SmallButton(absl::StrFormat(ICON_MD_DELETE "##%d", bp.id).c_str())) {
569 }
570 }
571 }
572 ImGui::EndChild();
573
574 ImGui::Separator();
575
576 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "CPU Status");
577 ImGui::PushStyleColor(ImGuiCol_ChildBg,
578 ConvertColorToImVec4(theme.child_bg));
579 ImGui::BeginChild("##CpuStatus", ImVec2(0, 180), true);
580
581 // Compact register display in a table
582 if (ImGui::BeginTable(
583 "Registers", 4,
584 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
585 ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 60);
586 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 80);
587 ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 60);
588 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 80);
589 ImGui::TableHeadersRow();
590
591 ImGui::TableNextRow();
592 ImGui::TableNextColumn();
593 ImGui::Text("A");
594 ImGui::TableNextColumn();
595 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%04X",
596 snes_.cpu().A);
597 ImGui::TableNextColumn();
598 ImGui::Text("D");
599 ImGui::TableNextColumn();
600 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%04X",
601 snes_.cpu().D);
602
603 ImGui::TableNextRow();
604 ImGui::TableNextColumn();
605 ImGui::Text("X");
606 ImGui::TableNextColumn();
607 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%04X",
608 snes_.cpu().X);
609 ImGui::TableNextColumn();
610 ImGui::Text("DB");
611 ImGui::TableNextColumn();
612 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
613 snes_.cpu().DB);
614
615 ImGui::TableNextRow();
616 ImGui::TableNextColumn();
617 ImGui::Text("Y");
618 ImGui::TableNextColumn();
619 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%04X",
620 snes_.cpu().Y);
621 ImGui::TableNextColumn();
622 ImGui::Text("PB");
623 ImGui::TableNextColumn();
624 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
625 snes_.cpu().PB);
626
627 ImGui::TableNextRow();
628 ImGui::TableNextColumn();
629 ImGui::Text("PC");
630 ImGui::TableNextColumn();
631 ImGui::TextColored(ConvertColorToImVec4(theme.success), "0x%04X",
632 snes_.cpu().PC);
633 ImGui::TableNextColumn();
634 ImGui::Text("SP");
635 ImGui::TableNextColumn();
636 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
637 snes_.memory().mutable_sp());
638
639 ImGui::TableNextRow();
640 ImGui::TableNextColumn();
641 ImGui::Text("PS");
642 ImGui::TableNextColumn();
643 ImGui::TextColored(ConvertColorToImVec4(theme.warning), "0x%02X",
644 snes_.cpu().status);
645 ImGui::TableNextColumn();
646 ImGui::Text("Cycle");
647 ImGui::TableNextColumn();
648 ImGui::TextColored(ConvertColorToImVec4(theme.info), "%llu",
650
651 ImGui::EndTable();
652 }
653
654 ImGui::EndChild();
655 ImGui::PopStyleColor();
656
657 // SPC700 Status Panel
658 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "SPC700 Status");
659 ImGui::PushStyleColor(ImGuiCol_ChildBg,
660 ConvertColorToImVec4(theme.child_bg));
661 ImGui::BeginChild("##SpcStatus", ImVec2(0, 150), true);
662
663 if (ImGui::BeginTable(
664 "SPCRegisters", 4,
665 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
666 ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 50);
667 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 60);
668 ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 50);
669 ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 60);
670 ImGui::TableHeadersRow();
671
672 ImGui::TableNextRow();
673 ImGui::TableNextColumn();
674 ImGui::Text("A");
675 ImGui::TableNextColumn();
676 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
677 snes_.apu().spc700().A);
678 ImGui::TableNextColumn();
679 ImGui::Text("PC");
680 ImGui::TableNextColumn();
681 ImGui::TextColored(ConvertColorToImVec4(theme.success), "0x%04X",
682 snes_.apu().spc700().PC);
683
684 ImGui::TableNextRow();
685 ImGui::TableNextColumn();
686 ImGui::Text("X");
687 ImGui::TableNextColumn();
688 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
689 snes_.apu().spc700().X);
690 ImGui::TableNextColumn();
691 ImGui::Text("SP");
692 ImGui::TableNextColumn();
693 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
694 snes_.apu().spc700().SP);
695
696 ImGui::TableNextRow();
697 ImGui::TableNextColumn();
698 ImGui::Text("Y");
699 ImGui::TableNextColumn();
700 ImGui::TextColored(ConvertColorToImVec4(theme.accent), "0x%02X",
701 snes_.apu().spc700().Y);
702 ImGui::TableNextColumn();
703 ImGui::Text("PSW");
704 ImGui::TableNextColumn();
705 ImGui::TextColored(
706 ConvertColorToImVec4(theme.warning), "0x%02X",
707 snes_.apu().spc700().FlagsToByte(snes_.apu().spc700().PSW));
708
709 ImGui::EndTable();
710 }
711
712 ImGui::EndChild();
713 ImGui::PopStyleColor();
714
715 // New Disassembly Viewer
716 if (ImGui::CollapsingHeader("Disassembly Viewer",
717 ImGuiTreeNodeFlags_DefaultOpen)) {
718 uint32_t current_pc = (static_cast<uint32_t>(snes_.cpu().PB) << 16) | snes_.cpu().PC;
719 auto& disasm = snes_.cpu().disassembly_viewer();
720 if (disasm.IsAvailable()) {
721 disasm.Render(current_pc, snes_.cpu().breakpoints_);
722 } else {
723 ImGui::TextColored(ConvertColorToImVec4(theme.error), "Disassembly viewer unavailable.");
724 }
725 }
726 } catch (const std::exception& e) {
727 // Ensure any pushed styles are popped on error
728 try {
729 ImGui::PopStyleColor();
730 } catch (...) {
731 // Ignore PopStyleColor errors
732 }
733 ImGui::Text("CPU Debugger Error: %s", e.what());
734 }
735}
736
738 // Delegate to UI layer
740}
741
743 // Delegate to UI layer
745}
746
748 const std::vector<InstructionEntry>& instruction_log) {
749 // Delegate to UI layer (legacy log deprecated)
750 ui::RenderCpuInstructionLog(this, instruction_log.size());
751}
752
754 // TODO: Create ui::RenderSaveStates() when save state system is implemented
755 auto& theme_manager = gui::ThemeManager::Get();
756 const auto& theme = theme_manager.GetCurrentTheme();
757
758 ImGui::TextColored(ConvertColorToImVec4(theme.warning),
759 ICON_MD_SAVE " Save States - Coming Soon");
760 ImGui::TextWrapped("Save state functionality will be implemented here.");
761}
762
764 // Delegate to the input manager UI
766}
767
769 // Delegate to UI layer
771}
772
773} // namespace emu
774} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
auto vector() const
Definition rom.h:207
bool is_loaded() const
Definition rom.h:197
bool ShouldBreakOnExecute(uint32_t pc, CpuType cpu)
Check if execution should break at this address.
void RemoveBreakpoint(uint32_t id)
Remove a breakpoint by ID.
void SetEnabled(uint32_t id, bool enabled)
Enable or disable a breakpoint.
std::vector< Breakpoint > GetAllBreakpoints() const
Get all breakpoints.
uint32_t AddBreakpoint(uint32_t address, Type type, CpuType cpu, const std::string &condition="", const std::string &description="")
Add a new breakpoint.
gfx::IRenderer * renderer()
Definition emulator.h:61
void Initialize(gfx::IRenderer *renderer, const std::vector< uint8_t > &rom_data)
Definition emulator.cc:47
void RenderModernCpuDebugger()
Definition emulator.cc:521
std::unique_ptr< audio::IAudioBackend > audio_backend_
Definition emulator.h:157
void RenderMemoryViewer()
Definition emulator.cc:516
uint64_t count_frequency
Definition emulator.h:144
void RenderKeyboardConfig()
Definition emulator.cc:763
debug::DisassemblyViewer disassembly_viewer_
Definition emulator.h:174
std::vector< uint8_t > rom_data_
Definition emulator.h:176
void RenderPerformanceMonitor()
Definition emulator.cc:737
void RenderAIAgentPanel()
Definition emulator.cc:742
void RenderBreakpointList()
Definition emulator.cc:511
BreakpointManager breakpoint_manager_
Definition emulator.h:173
uint64_t last_count
Definition emulator.h:145
input::InputManager input_manager_
Definition emulator.h:179
void RenderCpuInstructionLog(const std::vector< InstructionEntry > &instructionLog)
Definition emulator.cc:747
void Run(Rom *rom)
Definition emulator.cc:134
void RenderEmulatorInterface()
Definition emulator.cc:347
int16_t * audio_buffer_
Definition emulator.h:153
gfx::IRenderer * renderer_
Definition emulator.h:163
auto mutable_cycles() -> uint64_t &
Definition snes.h:76
void SetSamples(int16_t *sample_data, int wanted_samples)
Definition snes.cc:692
void Reset(bool hard=false)
Definition snes.cc:54
void RunFrame()
Definition snes.cc:98
auto apu() -> Apu &
Definition snes.h:73
auto cpu() -> Cpu &
Definition snes.h:71
void Init(std::vector< uint8_t > &rom_data)
Definition snes.cc:36
auto memory() -> MemoryImpl &
Definition snes.h:74
void SetPixels(uint8_t *pixel_data)
Definition snes.cc:696
static std::unique_ptr< IAudioBackend > Create(BackendType type)
void RecordInstruction(uint32_t address, uint8_t opcode, const std::vector< uint8_t > &operands, const std::string &mnemonic, const std::string &operand_str)
Record an instruction execution.
virtual std::string GetBackendName() const =0
Get backend name for debugging.
void Poll(Snes *snes, int player=1)
bool Initialize(InputBackendFactory::BackendType type=InputBackendFactory::BackendType::SDL2)
Defines an abstract interface for all rendering operations.
Definition irenderer.h:35
virtual void UnlockTexture(TextureHandle texture)=0
virtual bool LockTexture(TextureHandle texture, SDL_Rect *rect, void **pixels, int *pitch)=0
virtual TextureHandle CreateTextureWithFormat(int width, int height, uint32_t format, int access)=0
Creates a new texture with a specific pixel format.
static EditorCardManager & Get()
Draggable, dockable card for editor sub-windows.
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
void SetPosition(Position pos)
static ThemeManager & Get()
#define ICON_MD_GRID_VIEW
Definition icons.h:895
#define ICON_MD_PAUSE
Definition icons.h:1387
#define ICON_MD_MEMORY
Definition icons.h:1193
#define ICON_MD_DATA_ARRAY
Definition icons.h:517
#define ICON_MD_PLAY_ARROW
Definition icons.h:1477
#define ICON_MD_REFRESH
Definition icons.h:1570
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2074
#define ICON_MD_BUG_REPORT
Definition icons.h:325
#define ICON_MD_SPEED
Definition icons.h:1815
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1262
#define ICON_MD_ADD
Definition icons.h:84
#define ICON_MD_KEYBOARD
Definition icons.h:1026
#define ICON_MD_SKIP_NEXT
Definition icons.h:1771
#define ICON_MD_SAVE
Definition icons.h:1642
#define ICON_MD_DELETE
Definition icons.h:528
#define ICON_MD_AUDIO_FILE
Definition icons.h:210
#define ICON_MD_SMART_TOY
Definition icons.h:1779
#define LOG_ERROR(category, format,...)
Definition log.h:110
#define LOG_WARN(category, format,...)
Definition log.h:108
#define LOG_INFO(category, format,...)
Definition log.h:106
bool g_window_is_resizing
Definition window.cc:55
void RenderKeyboardConfig(input::InputManager *manager)
Render keyboard configuration UI.
void RenderPerformanceMonitor(Emulator *emu)
Performance metrics (FPS, frame time, audio status)
void RenderAIAgentPanel(Emulator *emu)
AI Agent panel for automated testing/gameplay.
void RenderSnesPpu(Emulator *emu)
SNES PPU output display.
void RenderNavBar(Emulator *emu)
Navigation bar with play/pause, step, reset controls.
void RenderBreakpointList(Emulator *emu)
Breakpoint list and management.
void RenderApuDebugger(Emulator *emu)
APU/Audio debugger with handshake tracker.
void RenderMemoryViewer(Emulator *emu)
Memory viewer/editor.
void RenderCpuInstructionLog(Emulator *emu, uint32_t log_size)
CPU instruction log (legacy, prefer DisassemblyViewer)
Main namespace for the application.