gui_debug.cpp (73678B)
1/* 2 * Gearboy - Nintendo Game Boy Emulator 3 * Copyright (C) 2012 Ignacio Sanchez 4 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see http://www.gnu.org/licenses/ 17 * 18 */ 19 20#include <math.h> 21#include "imgui/imgui.h" 22#include "imgui/imgui_memory_editor.h" 23#include "FileBrowser/ImGuiFileBrowser.h" 24#include "config.h" 25#include "emu.h" 26#include "renderer.h" 27#include "../../src/gearboy.h" 28#include "gui.h" 29#include "gui_debug_constants.h" 30 31#define GUI_DEBUG_IMPORT 32#include "gui_debug.h" 33 34struct DebugSymbol 35{ 36 int bank; 37 u16 address; 38 std::string text; 39}; 40 41struct DisassmeblerLine 42{ 43 bool is_symbol; 44 bool is_breakpoint; 45 Memory::stDisassembleRecord* record; 46 std::string symbol; 47}; 48 49static MemoryEditor mem_edit; 50static ImVec4 cyan = ImVec4(0.0f,1.0f,1.0f,1.0f); 51static ImVec4 magenta = ImVec4(1.0f,0.502f,0.957f,1.0f); 52static ImVec4 yellow = ImVec4(1.0f,1.0f,0.0f,1.0f); 53static ImVec4 red = ImVec4(1.0f,0.149f,0.447f,1.0f); 54static ImVec4 green = ImVec4(0.0f,1.0f,0.0f,1.0f); 55static ImVec4 white = ImVec4(1.0f,1.0f,1.0f,1.0f); 56static ImVec4 gray = ImVec4(0.5f,0.5f,0.5f,1.0f); 57static ImVec4 dark_gray = ImVec4(0.1f,0.1f,0.1f,1.0f); 58static std::vector<DebugSymbol> symbols; 59static Memory::stDisassembleRecord* selected_record = NULL; 60static char brk_address_cpu[8] = ""; 61static char brk_address_mem[10] = ""; 62static bool brk_new_mem_read = true; 63static bool brk_new_mem_write = true; 64static char goto_address[5] = ""; 65static bool goto_address_requested = false; 66static u16 goto_address_target = 0; 67static bool goto_back_requested = false; 68static int goto_back = 0; 69 70static void debug_window_processor(void); 71static void debug_window_io(void); 72static void debug_window_audio(void); 73static void debug_window_memory(void); 74static void debug_window_disassembler(void); 75static void debug_window_vram(void); 76static void debug_window_vram_background(void); 77static void debug_window_vram_tiles(void); 78static void debug_window_vram_oam(void); 79static void debug_window_vram_palettes(void); 80static void add_symbol(const char* line); 81static void add_breakpoint_cpu(void); 82static void add_breakpoint_mem(void); 83static void request_goto_address(u16 addr); 84static ImVec4 color_565_to_float(u16 color); 85 86void gui_debug_windows(void) 87{ 88 if (config_debug.debug) 89 { 90 if (config_debug.show_processor) 91 debug_window_processor(); 92 if (config_debug.show_memory) 93 debug_window_memory(); 94 if (config_debug.show_disassembler) 95 debug_window_disassembler(); 96 if (config_debug.show_iomap) 97 debug_window_io(); 98 if (config_debug.show_audio) 99 debug_window_audio(); 100 if (config_debug.show_video) 101 debug_window_vram(); 102 103 //ImGui::ShowDemoWindow(&config_debug.debug); 104 } 105} 106 107 108void gui_debug_reset(void) 109{ 110 gui_debug_reset_breakpoints_cpu(); 111 gui_debug_reset_breakpoints_mem(); 112 gui_debug_reset_symbols(); 113 selected_record = NULL; 114} 115 116void gui_debug_reset_symbols(void) 117{ 118 symbols.clear(); 119 120 for (int i = 0; i < gui_debug_symbols_count; i++) 121 add_symbol(gui_debug_symbols[i]); 122} 123 124void gui_debug_load_symbols_file(const char* path) 125{ 126 Log("Loading symbol file %s", path); 127 128 std::ifstream file(path); 129 130 if (file.is_open()) 131 { 132 std::string line; 133 134 while (std::getline(file, line)) 135 { 136 add_symbol(line.c_str()); 137 } 138 139 file.close(); 140 } 141} 142 143void gui_debug_toggle_breakpoint(void) 144{ 145 if (IsValidPointer(selected_record)) 146 { 147 bool found = false; 148 std::vector<Memory::stDisassembleRecord*>* breakpoints = emu_get_core()->GetMemory()->GetBreakpointsCPU(); 149 150 for (long unsigned int b = 0; b < breakpoints->size(); b++) 151 { 152 if ((*breakpoints)[b] == selected_record) 153 { 154 found = true; 155 InitPointer((*breakpoints)[b]); 156 break; 157 } 158 } 159 160 if (!found) 161 { 162 breakpoints->push_back(selected_record); 163 } 164 } 165} 166 167void gui_debug_runtocursor(void) 168{ 169 if (IsValidPointer(selected_record)) 170 { 171 emu_get_core()->GetMemory()->SetRunToBreakpoint(selected_record); 172 emu_debug_continue(); 173 } 174} 175 176void gui_debug_reset_breakpoints_cpu(void) 177{ 178 emu_get_core()->GetMemory()->GetBreakpointsCPU()->clear(); 179 brk_address_cpu[0] = 0; 180} 181 182void gui_debug_reset_breakpoints_mem(void) 183{ 184 emu_get_core()->GetMemory()->GetBreakpointsMem()->clear(); 185 brk_address_mem[0] = 0; 186} 187 188void gui_debug_go_back(void) 189{ 190 goto_back_requested = true; 191} 192 193static void debug_window_memory(void) 194{ 195 ImGui::SetNextWindowPos(ImVec2(180, 382), ImGuiCond_FirstUseEver); 196 ImGui::SetNextWindowSize(ImVec2(482, 308), ImGuiCond_FirstUseEver); 197 198 ImGui::Begin("Memory Editor", &config_debug.show_memory); 199 200 GearboyCore* core = emu_get_core(); 201 Memory* memory = core->GetMemory(); 202 203 ImGui::PushFont(gui_default_font); 204 205 ImGui::TextColored(cyan, " BANKS: ");ImGui::SameLine(); 206 207 ImGui::TextColored(magenta, "ROM1");ImGui::SameLine(); 208 ImGui::Text("$%02X", memory->GetCurrentRule()->GetCurrentRomBank1Index()); ImGui::SameLine(); 209 ImGui::TextColored(magenta, " RAM");ImGui::SameLine(); 210 ImGui::Text("$%02X", memory->GetCurrentRule()->GetCurrentRamBankIndex()); ImGui::SameLine(); 211 ImGui::TextColored(magenta, " WRAM1");ImGui::SameLine(); 212 ImGui::Text("$%02X", memory->GetCurrentCGBRAMBank()); ImGui::SameLine(); 213 ImGui::TextColored(magenta, " VRAM");ImGui::SameLine(); 214 ImGui::Text("$%02X", memory->GetCurrentLCDRAMBank()); 215 216 ImGui::PopFont(); 217 218 if (ImGui::BeginTabBar("##memory_tabs", ImGuiTabBarFlags_None)) 219 { 220 if (ImGui::BeginTabItem("ROM0")) 221 { 222 ImGui::PushFont(gui_default_font); 223 mem_edit.DrawContents(memory->GetROM0(), 0x4000, 0); 224 ImGui::PopFont(); 225 ImGui::EndTabItem(); 226 } 227 228 if (ImGui::BeginTabItem("ROM1")) 229 { 230 ImGui::PushFont(gui_default_font); 231 mem_edit.DrawContents(memory->GetROM1(), 0x4000, 0x4000); 232 ImGui::PopFont(); 233 ImGui::EndTabItem(); 234 } 235 236 if (ImGui::BeginTabItem("VRAM")) 237 { 238 ImGui::PushFont(gui_default_font); 239 mem_edit.DrawContents(memory->GetVRAM(), 0x2000, 0x8000); 240 ImGui::PopFont(); 241 ImGui::EndTabItem(); 242 } 243 244 if (ImGui::BeginTabItem("RAM")) 245 { 246 ImGui::PushFont(gui_default_font); 247 mem_edit.DrawContents(memory->GetRAM(), 0x2000, 0xA000); 248 ImGui::PopFont(); 249 ImGui::EndTabItem(); 250 } 251 252 if (emu_is_cgb()) 253 { 254 if (ImGui::BeginTabItem("WRAM0")) 255 { 256 ImGui::PushFont(gui_default_font); 257 mem_edit.DrawContents(memory->GetWRAM0(), 0x1000, 0xC000); 258 ImGui::PopFont(); 259 ImGui::EndTabItem(); 260 } 261 if (ImGui::BeginTabItem("WRAM1")) 262 { 263 ImGui::PushFont(gui_default_font); 264 mem_edit.DrawContents(memory->GetWRAM1(), 0x1000, 0xD000); 265 ImGui::PopFont(); 266 ImGui::EndTabItem(); 267 } 268 } 269 else 270 { 271 if (ImGui::BeginTabItem("WRAM")) 272 { 273 ImGui::PushFont(gui_default_font); 274 mem_edit.DrawContents(memory->GetWRAM0(), 0x2000, 0xC000); 275 ImGui::PopFont(); 276 ImGui::EndTabItem(); 277 } 278 } 279 280 if (ImGui::BeginTabItem("OAM")) 281 { 282 ImGui::PushFont(gui_default_font); 283 mem_edit.DrawContents(memory->GetMemoryMap() + 0xFE00, 0x00A0, 0xFE00); 284 ImGui::PopFont(); 285 ImGui::EndTabItem(); 286 } 287 288 if (ImGui::BeginTabItem("IO")) 289 { 290 ImGui::PushFont(gui_default_font); 291 mem_edit.DrawContents(memory->GetMemoryMap() + 0xFF00, 0x0080, 0xFF00); 292 ImGui::PopFont(); 293 ImGui::EndTabItem(); 294 } 295 296 if (ImGui::BeginTabItem("HIRAM")) 297 { 298 ImGui::PushFont(gui_default_font); 299 mem_edit.DrawContents(memory->GetMemoryMap() + 0xFF80, 0x007F, 0xFF80); 300 ImGui::PopFont(); 301 ImGui::EndTabItem(); 302 } 303 ImGui::EndTabBar(); 304 } 305 306 ImGui::End(); 307} 308 309static void debug_window_disassembler(void) 310{ 311 ImGui::SetNextWindowPos(ImVec2(180, 30), ImGuiCond_FirstUseEver); 312 ImGui::SetNextWindowSize(ImVec2(482, 344), ImGuiCond_FirstUseEver); 313 314 ImGui::Begin("Disassembler", &config_debug.show_disassembler); 315 316 GearboyCore* core = emu_get_core(); 317 Processor* processor = core->GetProcessor(); 318 Processor::ProcessorState* proc_state = processor->GetState(); 319 Memory* memory = core->GetMemory(); 320 std::vector<Memory::stDisassembleRecord*>* breakpoints_cpu = memory->GetBreakpointsCPU(); 321 std::vector<Memory::stMemoryBreakpoint>* breakpoints_mem = memory->GetBreakpointsMem(); 322 Memory::stDisassembleRecord** memory_map = memory->GetDisassembledMemoryMap(); 323 Memory::stDisassembleRecord** rom_map = memory->GetDisassembledROMMemoryMap(); 324 Memory::stDisassembleRecord** map = NULL; 325 326 int pc = proc_state->PC->GetValue(); 327 328 if (ImGui::Button("Step Over")) 329 emu_debug_step(); 330 ImGui::SameLine(); 331 if (ImGui::Button("Step Frame")) 332 emu_debug_next_frame(); 333 ImGui::SameLine(); 334 if (ImGui::Button("Continue")) 335 emu_debug_continue(); 336 ImGui::SameLine(); 337 if (ImGui::Button("Run To Cursor")) 338 gui_debug_runtocursor(); 339 340 static bool follow_pc = true; 341 static bool show_mem = true; 342 static bool show_symbols = true; 343 344 ImGui::Checkbox("Follow PC", &follow_pc); ImGui::SameLine(); 345 ImGui::Checkbox("Show Memory", &show_mem); ImGui::SameLine(); 346 ImGui::Checkbox("Show Symbols", &show_symbols); 347 348 ImGui::Separator(); 349 350 ImGui::Text("Go To Address: "); 351 ImGui::SameLine(); 352 ImGui::PushItemWidth(45); 353 if (ImGui::InputTextWithHint("##goto_address", "XXXX", goto_address, IM_ARRAYSIZE(goto_address), ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) 354 { 355 try 356 { 357 request_goto_address((u16)std::stoul(goto_address, 0, 16)); 358 follow_pc = false; 359 } 360 catch(const std::invalid_argument&) 361 { 362 } 363 goto_address[0] = 0; 364 } 365 ImGui::PopItemWidth(); 366 ImGui::SameLine(); 367 if (ImGui::Button("Go", ImVec2(30, 0))) 368 { 369 try 370 { 371 request_goto_address((u16)std::stoul(goto_address, 0, 16)); 372 follow_pc = false; 373 } 374 catch(const std::invalid_argument&) 375 { 376 } 377 goto_address[0] = 0; 378 } 379 ImGui::SameLine(); 380 if (ImGui::Button("Back", ImVec2(50, 0))) 381 { 382 goto_back_requested = true; 383 follow_pc = false; 384 } 385 386 ImGui::Separator(); 387 388 if (ImGui::CollapsingHeader("Processor Breakpoints")) 389 { 390 ImGui::Checkbox("Disable All##disable_all_cpu", &emu_debug_disable_breakpoints_cpu); 391 392 ImGui::Columns(2, "breakpoints_cpu"); 393 ImGui::SetColumnOffset(1, 85); 394 395 ImGui::Separator(); 396 397 if (IsValidPointer(selected_record)) 398 sprintf(brk_address_cpu, "%02X:%04X", selected_record->bank, selected_record->address); 399 400 ImGui::PushItemWidth(70); 401 if (ImGui::InputTextWithHint("##add_breakpoint_cpu", "XX:XXXX", brk_address_cpu, IM_ARRAYSIZE(brk_address_cpu), ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) 402 { 403 add_breakpoint_cpu(); 404 } 405 ImGui::PopItemWidth(); 406 407 if (ImGui::IsItemHovered()) 408 ImGui::SetTooltip("Use XXXX format for addresses in bank 0 or XX:XXXX for selecting bank and address"); 409 410 if (ImGui::Button("Add##add_cpu", ImVec2(70, 0))) 411 { 412 add_breakpoint_cpu(); 413 } 414 415 if (ImGui::Button("Clear All##clear_all_cpu", ImVec2(70, 0))) 416 { 417 gui_debug_reset_breakpoints_cpu(); 418 } 419 420 ImGui::NextColumn(); 421 422 ImGui::BeginChild("breakpoints_cpu", ImVec2(0, 80), false); 423 424 int remove = -1; 425 426 for (long unsigned int b = 0; b < breakpoints_cpu->size(); b++) 427 { 428 if (!IsValidPointer((*breakpoints_cpu)[b])) 429 continue; 430 431 ImGui::PushID(b); 432 if (ImGui::SmallButton("X")) 433 { 434 remove = b; 435 ImGui::PopID(); 436 continue; 437 } 438 439 ImGui::PopID(); 440 441 ImGui::PushFont(gui_default_font); 442 ImGui::SameLine(); 443 ImGui::TextColored(red, "%02X:%04X", (*breakpoints_cpu)[b]->bank, (*breakpoints_cpu)[b]->address); 444 ImGui::SameLine(); 445 ImGui::TextColored(gray, "%s", (*breakpoints_cpu)[b]->name); 446 ImGui::PopFont(); 447 } 448 449 if (remove >= 0) 450 { 451 breakpoints_cpu->erase(breakpoints_cpu->begin() + remove); 452 } 453 454 ImGui::EndChild(); 455 ImGui::Columns(1); 456 ImGui::Separator(); 457 } 458 459 if (ImGui::CollapsingHeader("Memory Breakpoints")) 460 { 461 ImGui::Checkbox("Disable All##diable_all_mem", &emu_debug_disable_breakpoints_mem); 462 463 ImGui::Columns(2, "breakpoints_mem"); 464 ImGui::SetColumnOffset(1, 100); 465 466 ImGui::Separator(); 467 468 ImGui::PushItemWidth(85); 469 if (ImGui::InputTextWithHint("##add_breakpoint_mem", "XXXX-XXXX", brk_address_mem, IM_ARRAYSIZE(brk_address_mem), ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) 470 { 471 add_breakpoint_mem(); 472 } 473 ImGui::PopItemWidth(); 474 475 if (ImGui::IsItemHovered()) 476 ImGui::SetTooltip("Use XXXX format for single addresses or XXXX-XXXX for address ranges"); 477 478 ImGui::Checkbox("Read", &brk_new_mem_read); 479 ImGui::Checkbox("Write", &brk_new_mem_write); 480 481 if (ImGui::Button("Add##add_mem", ImVec2(85, 0))) 482 { 483 add_breakpoint_mem(); 484 } 485 486 if (ImGui::Button("Clear All##clear_all_mem", ImVec2(85, 0))) 487 { 488 gui_debug_reset_breakpoints_mem(); 489 } 490 491 ImGui::NextColumn(); 492 493 ImGui::BeginChild("breakpoints_mem", ImVec2(0, 130), false); 494 495 int remove = -1; 496 497 for (long unsigned int b = 0; b < breakpoints_mem->size(); b++) 498 { 499 ImGui::PushID(10000 + b); 500 if (ImGui::SmallButton("X")) 501 { 502 remove = b; 503 ImGui::PopID(); 504 continue; 505 } 506 507 ImGui::PopID(); 508 509 ImGui::PushFont(gui_default_font); 510 ImGui::SameLine(); 511 if ((*breakpoints_mem)[b].range) 512 ImGui::TextColored(red, "%04X-%04X", (*breakpoints_mem)[b].address1, (*breakpoints_mem)[b].address2); 513 else 514 ImGui::TextColored(red, "%04X", (*breakpoints_mem)[b].address1); 515 if ((*breakpoints_mem)[b].read) 516 { 517 ImGui::SameLine(); ImGui::TextColored(gray, "R"); 518 } 519 if ((*breakpoints_mem)[b].write) 520 { 521 ImGui::SameLine(); ImGui::TextColored(gray, "W"); 522 } 523 ImGui::PopFont(); 524 } 525 526 if (remove >= 0) 527 { 528 breakpoints_mem->erase(breakpoints_mem->begin() + remove); 529 } 530 531 ImGui::EndChild(); 532 ImGui::Columns(1); 533 ImGui::Separator(); 534 } 535 536 ImGui::PushFont(gui_default_font); 537 538 bool window_visible = ImGui::BeginChild("##dis", ImVec2(ImGui::GetWindowContentRegionWidth(), 0), true, 0); 539 540 if (window_visible) 541 { 542 int dis_size = 0; 543 int pc_pos = 0; 544 int goto_address_pos = 0; 545 546 std::vector<DisassmeblerLine> vec(0x10000); 547 548 for (int i = 0; i < 0x10000; i++) 549 { 550 int offset = i; 551 int bank = 0; 552 553 if ((i & 0xC000) == 0x0000) 554 { 555 bank = memory->GetCurrentRule()->GetCurrentRomBank0Index(); 556 offset = (0x4000 * bank) + i; 557 map = rom_map; 558 } 559 else if ((i & 0xC000) == 0x4000) 560 { 561 bank = memory->GetCurrentRule()->GetCurrentRomBank1Index(); 562 offset = (0x4000 * bank) + (i & 0x3FFF); 563 map = rom_map; 564 } 565 else 566 { 567 map = memory_map; 568 } 569 570 if (IsValidPointer(map[offset]) && map[offset]->name[0] != 0) 571 { 572 for (long unsigned int s = 0; s < symbols.size(); s++) 573 { 574 if ((symbols[s].bank == bank) && (symbols[s].address == offset) && show_symbols) 575 { 576 vec[dis_size].is_symbol = true; 577 vec[dis_size].symbol = symbols[s].text; 578 dis_size ++; 579 } 580 } 581 582 vec[dis_size].is_symbol = false; 583 vec[dis_size].record = map[offset]; 584 585 if (vec[dis_size].record->address == pc) 586 pc_pos = dis_size; 587 588 if (goto_address_requested && (vec[dis_size].record->address <= goto_address_target)) 589 goto_address_pos = dis_size; 590 591 vec[dis_size].is_breakpoint = false; 592 593 for (long unsigned int b = 0; b < breakpoints_cpu->size(); b++) 594 { 595 if ((*breakpoints_cpu)[b] == vec[dis_size].record) 596 { 597 vec[dis_size].is_breakpoint = true; 598 break; 599 } 600 } 601 602 dis_size++; 603 } 604 } 605 606 if (follow_pc) 607 { 608 float window_offset = ImGui::GetWindowHeight() / 2.0f; 609 float offset = window_offset - (ImGui::GetTextLineHeightWithSpacing() - 2.0f); 610 ImGui::SetScrollY((pc_pos * ImGui::GetTextLineHeightWithSpacing()) - offset); 611 } 612 613 if (goto_address_requested) 614 { 615 goto_address_requested = false; 616 goto_back = (int)ImGui::GetScrollY(); 617 ImGui::SetScrollY((goto_address_pos * ImGui::GetTextLineHeightWithSpacing()) + 2); 618 } 619 620 if (goto_back_requested) 621 { 622 goto_back_requested = false; 623 ImGui::SetScrollY((float)goto_back); 624 } 625 626 ImGuiListClipper clipper(dis_size, ImGui::GetTextLineHeightWithSpacing()); 627 628 while (clipper.Step()) 629 { 630 for (int item = clipper.DisplayStart; item < clipper.DisplayEnd; item++) 631 { 632 if (vec[item].is_symbol) 633 { 634 ImGui::TextColored(green, "%s:", vec[item].symbol.c_str()); 635 continue; 636 } 637 638 ImGui::PushID(item); 639 640 bool is_selected = (selected_record == vec[item].record); 641 642 if (ImGui::Selectable("", is_selected, ImGuiSelectableFlags_AllowDoubleClick)) 643 { 644 if (ImGui::IsMouseDoubleClicked(0) && vec[item].record->jump) 645 { 646 follow_pc = false; 647 request_goto_address(vec[item].record->jump_address); 648 } 649 else if (is_selected) 650 { 651 InitPointer(selected_record); 652 brk_address_cpu[0] = 0; 653 } 654 else 655 selected_record = vec[item].record; 656 } 657 658 if (is_selected) 659 ImGui::SetItemDefaultFocus(); 660 661 if (vec[item].is_breakpoint) 662 { 663 ImGui::SameLine(); 664 if (vec[item].record->address == pc) 665 { 666 if (show_mem) 667 ImGui::TextColored(red, " %02X:%04X %s", vec[item].record->bank, vec[item].record->address, vec[item].record->bytes); 668 else 669 ImGui::TextColored(red, " %02X:%04X ", vec[item].record->bank, vec[item].record->address); 670 ImGui::SameLine(); 671 ImGui::TextColored(yellow, "->"); 672 ImGui::SameLine(); 673 ImGui::TextColored(red, "%s", vec[item].record->name); 674 } 675 else 676 { 677 if (show_mem) 678 ImGui::TextColored(red, " %02X:%04X %s %s", vec[item].record->bank, vec[item].record->address, vec[item].record->bytes, vec[item].record->name); 679 else 680 ImGui::TextColored(red, " %02X:%04X %s", vec[item].record->bank, vec[item].record->address, vec[item].record->name); 681 } 682 } 683 else if (vec[item].record->address == pc) 684 { 685 ImGui::SameLine(); 686 if (show_mem) 687 ImGui::TextColored(yellow, " %02X:%04X %s -> %s", vec[item].record->bank, vec[item].record->address, vec[item].record->bytes, vec[item].record->name); 688 else 689 ImGui::TextColored(yellow, " %02X:%04X -> %s", vec[item].record->bank, vec[item].record->address, vec[item].record->name); 690 } 691 else 692 { 693 ImGui::SameLine(); 694 ImGui::TextColored(cyan, " %02X:%04X ", vec[item].record->bank, vec[item].record->address); 695 ImGui::SameLine(); 696 if (show_mem) 697 ImGui::TextColored(gray, "%s ", vec[item].record->bytes); 698 else 699 ImGui::TextColored(gray, " "); 700 701 ImGui::SameLine(); 702 ImGui::TextColored(white, "%s", vec[item].record->name); 703 } 704 705 ImGui::PopID(); 706 } 707 } 708 } 709 710 ImGui::EndChild(); 711 712 ImGui::PopFont(); 713 714 ImGui::End(); 715} 716 717static void debug_window_processor(void) 718{ 719 ImGui::SetNextWindowPos(ImVec2(14, 210), ImGuiCond_FirstUseEver); 720 721 ImGui::Begin("Processor", &config_debug.show_processor, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); 722 723 ImGui::PushFont(gui_default_font); 724 725 GearboyCore* core = emu_get_core(); 726 Processor* processor = core->GetProcessor(); 727 Processor::ProcessorState* proc_state = processor->GetState(); 728 Memory* memory = core->GetMemory(); 729 730 ImGui::Separator(); 731 732 u8 flags = proc_state->AF->GetLow(); 733 734 ImGui::TextColored(magenta, " Z"); ImGui::SameLine(); 735 ImGui::Text("= %d", (bool)(flags & FLAG_ZERO)); ImGui::SameLine(); 736 737 ImGui::TextColored(magenta, " N"); ImGui::SameLine(); 738 ImGui::Text("= %d", (bool)(flags & FLAG_SUB)); 739 740 ImGui::TextColored(magenta, " H"); ImGui::SameLine(); 741 ImGui::Text("= %d", (bool)(flags & FLAG_HALF)); ImGui::SameLine(); 742 743 ImGui::TextColored(magenta, " C"); ImGui::SameLine(); 744 ImGui::Text("= %d", (bool)(flags & FLAG_CARRY)); 745 746 ImGui::Columns(2, "registers"); 747 ImGui::Separator(); 748 ImGui::TextColored(cyan, " A"); ImGui::SameLine(); 749 ImGui::Text("= $%02X", proc_state->AF->GetHigh()); 750 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->AF->GetHigh())); 751 752 ImGui::NextColumn(); 753 ImGui::TextColored(cyan, " F"); ImGui::SameLine(); 754 ImGui::Text("= $%02X", proc_state->AF->GetLow()); 755 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->AF->GetLow())); 756 757 ImGui::NextColumn(); 758 ImGui::Separator(); 759 ImGui::TextColored(cyan, " B"); ImGui::SameLine(); 760 ImGui::Text("= $%02X", proc_state->BC->GetHigh()); 761 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->BC->GetHigh())); 762 763 ImGui::NextColumn(); 764 ImGui::TextColored(cyan, " C"); ImGui::SameLine(); 765 ImGui::Text("= $%02X", proc_state->BC->GetLow()); 766 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->BC->GetLow())); 767 768 ImGui::NextColumn(); 769 ImGui::Separator(); 770 ImGui::TextColored(cyan, " D"); ImGui::SameLine(); 771 ImGui::Text("= $%02X", proc_state->DE->GetHigh()); 772 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->DE->GetHigh())); 773 774 ImGui::NextColumn(); 775 ImGui::TextColored(cyan, " E"); ImGui::SameLine(); 776 ImGui::Text("= $%02X", proc_state->DE->GetLow()); 777 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->DE->GetLow())); 778 779 ImGui::NextColumn(); 780 ImGui::Separator(); 781 ImGui::TextColored(cyan, " H"); ImGui::SameLine(); 782 ImGui::Text("= $%02X", proc_state->HL->GetHigh()); 783 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->HL->GetHigh())); 784 785 ImGui::NextColumn(); 786 ImGui::TextColored(cyan, " L"); ImGui::SameLine(); 787 ImGui::Text("= $%02X", proc_state->HL->GetLow()); 788 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->HL->GetLow())); 789 790 ImGui::NextColumn(); 791 ImGui::Columns(1); 792 ImGui::Separator(); 793 ImGui::TextColored(yellow, " SP"); ImGui::SameLine(); 794 ImGui::Text("= $%04X", proc_state->SP->GetValue()); 795 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED " " BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->SP->GetHigh()), BYTE_TO_BINARY(proc_state->SP->GetLow())); 796 797 ImGui::Separator(); 798 ImGui::TextColored(yellow, " PC"); ImGui::SameLine(); 799 ImGui::Text("= $%04X", proc_state->PC->GetValue()); 800 ImGui::Text(BYTE_TO_BINARY_PATTERN_SPACED " " BYTE_TO_BINARY_PATTERN_SPACED, BYTE_TO_BINARY(proc_state->PC->GetHigh()), BYTE_TO_BINARY(proc_state->PC->GetLow())); 801 802 803 ImGui::Columns(2); 804 ImGui::Separator(); 805 806 ImGui::TextColored(magenta, " IME"); ImGui::SameLine(); 807 ImGui::Text("= %d", *proc_state->IME); 808 809 ImGui::NextColumn(); 810 811 ImGui::TextColored(magenta, "HALT"); ImGui::SameLine(); 812 ImGui::Text("= %d", *proc_state->Halt); 813 814 ImGui::NextColumn(); 815 816 ImGui::Columns(1); 817 818 ImGui::Separator(); 819 820 ImGui::TextColored(cyan, " DOUBLE SPEED "); ImGui::SameLine(); 821 processor->CGBSpeed() ? ImGui::TextColored(green, "ON") : ImGui::TextColored(gray, "OFF"); 822 823 ImGui::Separator(); 824 825 ImGui::TextColored(cyan, " BOOTROM "); ImGui::SameLine(); 826 memory->IsBootromRegistryEnabled() ? ImGui::TextColored(green, "ON") : ImGui::TextColored(gray, "OFF"); 827 828 ImGui::PopFont(); 829 830 ImGui::End(); 831} 832 833static void debug_window_audio(void) 834{ 835 ImGui::SetNextWindowPos(ImVec2(130, 264), ImGuiCond_FirstUseEver); 836 ImGui::SetNextWindowSize(ImVec2(417, 0), ImGuiCond_FirstUseEver); 837 838 ImGui::Begin("Sound Registers", &config_debug.show_audio); 839 840 ImGui::PushFont(gui_default_font); 841 842 GearboyCore* core = emu_get_core(); 843 Audio* audio = core->GetAudio(); 844 845 gb_apu_state_t apu_state; 846 audio->GetApu()->save_state(&apu_state); 847 848 ImGui::Columns(2, "audio"); 849 850 ImGui::TextColored(yellow, "CHANNEL 1 - TONE & SWEEP:"); 851 852 u8 value = apu_state.regs[0xFF10 - 0xFF10]; 853 ImGui::TextColored(cyan, " $FF10"); ImGui::SameLine(); 854 ImGui::TextColored(magenta, "NR10"); ImGui::SameLine(); 855 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 856 857 value = apu_state.regs[0xFF11 - 0xFF10]; 858 ImGui::TextColored(cyan, " $FF11"); ImGui::SameLine(); 859 ImGui::TextColored(magenta, "NR11"); ImGui::SameLine(); 860 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 861 862 value = apu_state.regs[0xFF12 - 0xFF10]; 863 ImGui::TextColored(cyan, " $FF12"); ImGui::SameLine(); 864 ImGui::TextColored(magenta, "NR12"); ImGui::SameLine(); 865 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 866 867 value = apu_state.regs[0xFF13 - 0xFF10]; 868 ImGui::TextColored(cyan, " $FF13"); ImGui::SameLine(); 869 ImGui::TextColored(magenta, "NR13"); ImGui::SameLine(); 870 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 871 872 value = apu_state.regs[0xFF14 - 0xFF10]; 873 ImGui::TextColored(cyan, " $FF14"); ImGui::SameLine(); 874 ImGui::TextColored(magenta, "NR14"); ImGui::SameLine(); 875 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 876 877 ImGui::NextColumn(); 878 879 ImGui::TextColored(yellow, "CHANNEL 3 - WAVE:"); 880 881 value = apu_state.regs[0xFF1A - 0xFF10]; 882 ImGui::TextColored(cyan, " $FF1A"); ImGui::SameLine(); 883 ImGui::TextColored(magenta, "NR30"); ImGui::SameLine(); 884 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 885 886 value = apu_state.regs[0xFF1B - 0xFF10]; 887 ImGui::TextColored(cyan, " $FF1B"); ImGui::SameLine(); 888 ImGui::TextColored(magenta, "NR31"); ImGui::SameLine(); 889 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 890 891 value = apu_state.regs[0xFF1C - 0xFF10]; 892 ImGui::TextColored(cyan, " $FF1C"); ImGui::SameLine(); 893 ImGui::TextColored(magenta, "NR32"); ImGui::SameLine(); 894 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 895 896 value = apu_state.regs[0xFF1D - 0xFF10]; 897 ImGui::TextColored(cyan, " $FF1D"); ImGui::SameLine(); 898 ImGui::TextColored(magenta, "NR33"); ImGui::SameLine(); 899 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 900 901 value = apu_state.regs[0xFF1E - 0xFF10]; 902 ImGui::TextColored(cyan, " $FF1E"); ImGui::SameLine(); 903 ImGui::TextColored(magenta, "NR34"); ImGui::SameLine(); 904 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 905 906 ImGui::NextColumn(); 907 ImGui::Separator(); 908 909 ImGui::TextColored(yellow, "CHANNEL 2 - TONE:"); 910 911 value = apu_state.regs[0xFF16 - 0xFF10]; 912 ImGui::TextColored(cyan, " $FF16"); ImGui::SameLine(); 913 ImGui::TextColored(magenta, "NR21"); ImGui::SameLine(); 914 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 915 916 value = apu_state.regs[0xFF17 - 0xFF10]; 917 ImGui::TextColored(cyan, " $FF17"); ImGui::SameLine(); 918 ImGui::TextColored(magenta, "NR22"); ImGui::SameLine(); 919 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 920 921 value = apu_state.regs[0xFF18 - 0xFF10]; 922 ImGui::TextColored(cyan, " $FF18"); ImGui::SameLine(); 923 ImGui::TextColored(magenta, "NR23"); ImGui::SameLine(); 924 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 925 926 value = apu_state.regs[0xFF19 - 0xFF10]; 927 ImGui::TextColored(cyan, " $FF19"); ImGui::SameLine(); 928 ImGui::TextColored(magenta, "NR24"); ImGui::SameLine(); 929 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 930 931 ImGui::NextColumn(); 932 933 ImGui::TextColored(yellow, "CHANNEL 4 - NOISE:"); 934 935 value = apu_state.regs[0xFF20 - 0xFF10]; 936 ImGui::TextColored(cyan, " $FF20"); ImGui::SameLine(); 937 ImGui::TextColored(magenta, "NR41"); ImGui::SameLine(); 938 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 939 940 value = apu_state.regs[0xFF21 - 0xFF10]; 941 ImGui::TextColored(cyan, " $FF21"); ImGui::SameLine(); 942 ImGui::TextColored(magenta, "NR42"); ImGui::SameLine(); 943 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 944 945 value = apu_state.regs[0xFF22 - 0xFF10]; 946 ImGui::TextColored(cyan, " $FF22"); ImGui::SameLine(); 947 ImGui::TextColored(magenta, "NR43"); ImGui::SameLine(); 948 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 949 950 value = apu_state.regs[0xFF23 - 0xFF10]; 951 ImGui::TextColored(cyan, " $FF23"); ImGui::SameLine(); 952 ImGui::TextColored(magenta, "NR44"); ImGui::SameLine(); 953 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 954 955 ImGui::NextColumn(); 956 ImGui::Separator(); 957 958 ImGui::TextColored(yellow, "CONTROL:"); 959 960 value = apu_state.regs[0xFF24 - 0xFF10]; 961 ImGui::TextColored(cyan, " $FF24"); ImGui::SameLine(); 962 ImGui::TextColored(magenta, "NR50"); ImGui::SameLine(); 963 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 964 965 value = apu_state.regs[0xFF25 - 0xFF10]; 966 ImGui::TextColored(cyan, " $FF25"); ImGui::SameLine(); 967 ImGui::TextColored(magenta, "NR51"); ImGui::SameLine(); 968 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 969 970 value = apu_state.regs[0xFF26 - 0xFF10]; 971 ImGui::TextColored(cyan, " $FF26"); ImGui::SameLine(); 972 ImGui::TextColored(magenta, "NR52"); ImGui::SameLine(); 973 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", value, BYTE_TO_BINARY(value)); 974 975 ImGui::NextColumn(); 976 977 ImGui::TextColored(yellow, "WAVE ($FF30 - $FF37):" ); 978 979 ImGui::Text(" %02X%02X %02X%02X %02X%02X %02X%02X", apu_state.regs[0x20], apu_state.regs[0x21], apu_state.regs[0x22], apu_state.regs[0x23], apu_state.regs[0x24], apu_state.regs[0x25], apu_state.regs[0x26], apu_state.regs[0x27]); 980 981 ImGui::TextColored(yellow, "WAVE ($FF38 - $FF3F):" ); 982 983 ImGui::Text(" %02X%02X %02X%02X %02X%02X %02X%02X", apu_state.regs[0x28], apu_state.regs[0x29], apu_state.regs[0x2A], apu_state.regs[0x2B], apu_state.regs[0x2C], apu_state.regs[0x2D], apu_state.regs[0x2E], apu_state.regs[0x2F]); 984 985 ImGui::NextColumn(); 986 987 ImGui::Columns(1); 988 989 ImGui::PopFont(); 990 991 ImGui::End(); 992} 993 994static void debug_window_io(void) 995{ 996 ImGui::SetNextWindowPos(ImVec2(121, 164), ImGuiCond_FirstUseEver); 997 ImGui::SetNextWindowSize(ImVec2(420, 0), ImGuiCond_FirstUseEver); 998 999 ImGui::Begin("IO Map", &config_debug.show_iomap); 1000 1001 ImGui::PushFont(gui_default_font); 1002 1003 GearboyCore* core = emu_get_core(); 1004 Memory* memory = core->GetMemory(); 1005 1006 ImGui::Columns(2, "iomap"); 1007 1008 ImGui::TextColored(yellow, "INTERRUPTS:"); 1009 1010 ImGui::TextColored(cyan, " $FFFF"); ImGui::SameLine(); 1011 ImGui::TextColored(magenta, "IE "); ImGui::SameLine(); 1012 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFFFF), BYTE_TO_BINARY(memory->Retrieve(0xFFFF))); 1013 1014 ImGui::TextColored(cyan, " $FF0F"); ImGui::SameLine(); 1015 ImGui::TextColored(magenta, "IF "); ImGui::SameLine(); 1016 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF0F), BYTE_TO_BINARY(memory->Retrieve(0xFF0F))); 1017 1018 ImGui::TextColored(cyan, " VBLNK "); ImGui::SameLine(); 1019 IsSetBit(memory->Retrieve(0xFF0F), 0) && IsSetBit(memory->Retrieve(0xFFFF), 0) ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF "); ImGui::SameLine(); 1020 ImGui::TextColored(magenta, "IF:"); ImGui::SameLine(); 1021 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFF0F), 0)); ImGui::SameLine(); 1022 ImGui::TextColored(magenta, " IE:"); ImGui::SameLine(); 1023 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFFFF), 0)); 1024 1025 ImGui::TextColored(cyan, " STAT "); ImGui::SameLine(); 1026 IsSetBit(memory->Retrieve(0xFF0F), 1) && IsSetBit(memory->Retrieve(0xFFFF), 1) ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF "); ImGui::SameLine(); 1027 ImGui::TextColored(magenta, "IF:"); ImGui::SameLine(); 1028 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFF0F), 1)); ImGui::SameLine(); 1029 ImGui::TextColored(magenta, " IE:"); ImGui::SameLine(); 1030 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFFFF), 1)); 1031 1032 ImGui::TextColored(cyan, " TIMER "); ImGui::SameLine(); 1033 IsSetBit(memory->Retrieve(0xFF0F), 2) && IsSetBit(memory->Retrieve(0xFFFF), 2) ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF "); ImGui::SameLine(); 1034 ImGui::TextColored(magenta, "IF:"); ImGui::SameLine(); 1035 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFF0F), 2)); ImGui::SameLine(); 1036 ImGui::TextColored(magenta, " IE:"); ImGui::SameLine(); 1037 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFFFF), 2)); 1038 1039 ImGui::TextColored(cyan, " SERIAL "); ImGui::SameLine(); 1040 IsSetBit(memory->Retrieve(0xFF0F), 3) && IsSetBit(memory->Retrieve(0xFFFF), 3) ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF "); ImGui::SameLine(); 1041 ImGui::TextColored(magenta, "IF:"); ImGui::SameLine(); 1042 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFF0F), 3)); ImGui::SameLine(); 1043 ImGui::TextColored(magenta, " IE:"); ImGui::SameLine(); 1044 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFFFF), 3)); 1045 1046 ImGui::TextColored(cyan, " JOYPAD "); ImGui::SameLine(); 1047 IsSetBit(memory->Retrieve(0xFF0F), 4) && IsSetBit(memory->Retrieve(0xFFFF), 4) ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF "); ImGui::SameLine(); 1048 ImGui::TextColored(magenta, "IF:"); ImGui::SameLine(); 1049 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFF0F), 4)); ImGui::SameLine(); 1050 ImGui::TextColored(magenta, " IE:"); ImGui::SameLine(); 1051 ImGui::Text("%d", IsSetBit(memory->Retrieve(0xFFFF), 4)); 1052 1053 ImGui::TextColored(yellow, "GBC:"); 1054 1055 ImGui::TextColored(cyan, " $FF4D"); ImGui::SameLine(); 1056 ImGui::TextColored(magenta, "KEY1"); ImGui::SameLine(); 1057 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF4D), BYTE_TO_BINARY(memory->Retrieve(0xFF4D))); 1058 1059 ImGui::TextColored(cyan, " $FF70"); ImGui::SameLine(); 1060 ImGui::TextColored(magenta, "SVBK"); ImGui::SameLine(); 1061 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF70), BYTE_TO_BINARY(memory->Retrieve(0xFF70))); 1062 1063 ImGui::TextColored(yellow, "GBC LCD:"); 1064 1065 ImGui::TextColored(cyan, " $FF68"); ImGui::SameLine(); 1066 ImGui::TextColored(magenta, "BCPS"); ImGui::SameLine(); 1067 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF68), BYTE_TO_BINARY(memory->Retrieve(0xFF68))); 1068 1069 ImGui::TextColored(cyan, " $FF69"); ImGui::SameLine(); 1070 ImGui::TextColored(magenta, "BCPD"); ImGui::SameLine(); 1071 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF69), BYTE_TO_BINARY(memory->Retrieve(0xFF69))); 1072 1073 ImGui::TextColored(cyan, " $FF6A"); ImGui::SameLine(); 1074 ImGui::TextColored(magenta, "OCPS"); ImGui::SameLine(); 1075 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF6A), BYTE_TO_BINARY(memory->Retrieve(0xFF6A))); 1076 1077 ImGui::TextColored(cyan, " $FF6B"); ImGui::SameLine(); 1078 ImGui::TextColored(magenta, "OCPD"); ImGui::SameLine(); 1079 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF6B), BYTE_TO_BINARY(memory->Retrieve(0xFF6B))); 1080 1081 ImGui::TextColored(cyan, " $FF4F"); ImGui::SameLine(); 1082 ImGui::TextColored(magenta, "VBK "); ImGui::SameLine(); 1083 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF4F), BYTE_TO_BINARY(memory->Retrieve(0xFF4F))); 1084 1085 ImGui::TextColored(yellow, "GBC HDMA:"); 1086 1087 ImGui::TextColored(cyan, " $FF51:$FF52"); ImGui::SameLine(); 1088 ImGui::TextColored(magenta, "SOURCE "); ImGui::SameLine(); 1089 ImGui::Text("$%04X", (memory->Retrieve(0xFF51) << 8) | memory->Retrieve(0xFF52)); 1090 1091 ImGui::TextColored(cyan, " $FF53:$FF54"); ImGui::SameLine(); 1092 ImGui::TextColored(magenta, "DEST "); ImGui::SameLine(); 1093 ImGui::Text("$%04X", (memory->Retrieve(0xFF53) << 8) | memory->Retrieve(0xFF54)); 1094 1095 ImGui::TextColored(cyan, " $FF55"); ImGui::SameLine(); 1096 ImGui::TextColored(magenta, "LEN "); ImGui::SameLine(); 1097 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF55), BYTE_TO_BINARY(memory->Retrieve(0xFF55))); 1098 1099 ImGui::TextColored(yellow, "GBC INFRARED:"); 1100 1101 ImGui::TextColored(cyan, " $FF56"); ImGui::SameLine(); 1102 ImGui::TextColored(magenta, "RP "); ImGui::SameLine(); 1103 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF56), BYTE_TO_BINARY(memory->Retrieve(0xFF56))); 1104 1105 ImGui::NextColumn(); 1106 1107 ImGui::TextColored(yellow, "LCD:"); 1108 1109 ImGui::TextColored(cyan, " $FF40"); ImGui::SameLine(); 1110 ImGui::TextColored(magenta, "LCDC"); ImGui::SameLine(); 1111 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF40), BYTE_TO_BINARY(memory->Retrieve(0xFF40))); 1112 1113 ImGui::TextColored(cyan, " $FF41"); ImGui::SameLine(); 1114 ImGui::TextColored(magenta, "STAT"); ImGui::SameLine(); 1115 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF41), BYTE_TO_BINARY(memory->Retrieve(0xFF41))); 1116 1117 ImGui::TextColored(cyan, " $FF42"); ImGui::SameLine(); 1118 ImGui::TextColored(magenta, "SCY "); ImGui::SameLine(); 1119 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF42), BYTE_TO_BINARY(memory->Retrieve(0xFF42))); 1120 1121 ImGui::TextColored(cyan, " $FF43"); ImGui::SameLine(); 1122 ImGui::TextColored(magenta, "SCX "); ImGui::SameLine(); 1123 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF43), BYTE_TO_BINARY(memory->Retrieve(0xFF43))); 1124 1125 ImGui::TextColored(cyan, " $FF44"); ImGui::SameLine(); 1126 ImGui::TextColored(magenta, "LY "); ImGui::SameLine(); 1127 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF44), BYTE_TO_BINARY(memory->Retrieve(0xFF44))); 1128 1129 ImGui::TextColored(cyan, " $FF45"); ImGui::SameLine(); 1130 ImGui::TextColored(magenta, "LYC "); ImGui::SameLine(); 1131 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF45), BYTE_TO_BINARY(memory->Retrieve(0xFF45))); 1132 1133 ImGui::TextColored(cyan, " $FF46"); ImGui::SameLine(); 1134 ImGui::TextColored(magenta, "DMA "); ImGui::SameLine(); 1135 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF46), BYTE_TO_BINARY(memory->Retrieve(0xFF46))); 1136 1137 ImGui::TextColored(cyan, " $FF47"); ImGui::SameLine(); 1138 ImGui::TextColored(magenta, "BGP "); ImGui::SameLine(); 1139 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF47), BYTE_TO_BINARY(memory->Retrieve(0xFF47))); 1140 1141 ImGui::TextColored(cyan, " $FF48"); ImGui::SameLine(); 1142 ImGui::TextColored(magenta, "OBP0"); ImGui::SameLine(); 1143 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF48), BYTE_TO_BINARY(memory->Retrieve(0xFF48))); 1144 1145 ImGui::TextColored(cyan, " $FF49"); ImGui::SameLine(); 1146 ImGui::TextColored(magenta, "OBP1"); ImGui::SameLine(); 1147 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF49), BYTE_TO_BINARY(memory->Retrieve(0xFF49))); 1148 1149 ImGui::TextColored(cyan, " $FF4A"); ImGui::SameLine(); 1150 ImGui::TextColored(magenta, "WY "); ImGui::SameLine(); 1151 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF4A), BYTE_TO_BINARY(memory->Retrieve(0xFF4A))); 1152 1153 ImGui::TextColored(cyan, " $FF4B"); ImGui::SameLine(); 1154 ImGui::TextColored(magenta, "WX "); ImGui::SameLine(); 1155 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF4B), BYTE_TO_BINARY(memory->Retrieve(0xFF4B))); 1156 1157 ImGui::TextColored(yellow, "TIMER:"); 1158 1159 ImGui::TextColored(cyan, " $FF04"); ImGui::SameLine(); 1160 ImGui::TextColored(magenta, "DIV "); ImGui::SameLine(); 1161 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF04), BYTE_TO_BINARY(memory->Retrieve(0xFF04))); 1162 1163 ImGui::TextColored(cyan, " $FF05"); ImGui::SameLine(); 1164 ImGui::TextColored(magenta, "TIMA"); ImGui::SameLine(); 1165 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF05), BYTE_TO_BINARY(memory->Retrieve(0xFF05))); 1166 1167 ImGui::TextColored(cyan, " $FF06"); ImGui::SameLine(); 1168 ImGui::TextColored(magenta, "TMA "); ImGui::SameLine(); 1169 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF06), BYTE_TO_BINARY(memory->Retrieve(0xFF06))); 1170 1171 ImGui::TextColored(cyan, " $FF07"); ImGui::SameLine(); 1172 ImGui::TextColored(magenta, "TAC "); ImGui::SameLine(); 1173 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF07), BYTE_TO_BINARY(memory->Retrieve(0xFF07))); 1174 1175 ImGui::TextColored(yellow, "INPUT:"); 1176 1177 ImGui::TextColored(cyan, " $FF00"); ImGui::SameLine(); 1178 ImGui::TextColored(magenta, "JOYP"); ImGui::SameLine(); 1179 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF00), BYTE_TO_BINARY(memory->Retrieve(0xFF00))); 1180 1181 ImGui::TextColored(yellow, "SERIAL:"); 1182 1183 ImGui::TextColored(cyan, " $FF01"); ImGui::SameLine(); 1184 ImGui::TextColored(magenta, "SB "); ImGui::SameLine(); 1185 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF01), BYTE_TO_BINARY(memory->Retrieve(0xFF01))); 1186 1187 ImGui::TextColored(cyan, " $FF02"); ImGui::SameLine(); 1188 ImGui::TextColored(magenta, "SC "); ImGui::SameLine(); 1189 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ")", memory->Retrieve(0xFF02), BYTE_TO_BINARY(memory->Retrieve(0xFF02))); 1190 1191 ImGui::Columns(1); 1192 1193 ImGui::PopFont(); 1194 1195 ImGui::End(); 1196} 1197 1198static void debug_window_vram(void) 1199{ 1200 ImGui::SetNextWindowPos(ImVec2(60, 60), ImGuiCond_FirstUseEver); 1201 ImGui::SetNextWindowSize(ImVec2(544, 534), ImGuiCond_FirstUseEver); 1202 1203 ImGui::Begin("VRAM Viewer", &config_debug.show_video); 1204 1205 if (ImGui::BeginTabBar("##vram_tabs", ImGuiTabBarFlags_None)) 1206 { 1207 if (ImGui::BeginTabItem("Background")) 1208 { 1209 debug_window_vram_background(); 1210 ImGui::EndTabItem(); 1211 } 1212 1213 if (ImGui::BeginTabItem("Tiles")) 1214 { 1215 debug_window_vram_tiles(); 1216 ImGui::EndTabItem(); 1217 } 1218 1219 if (ImGui::BeginTabItem("OAM")) 1220 { 1221 debug_window_vram_oam(); 1222 ImGui::EndTabItem(); 1223 } 1224 1225 if (ImGui::BeginTabItem("Palettes")) 1226 { 1227 debug_window_vram_palettes(); 1228 ImGui::EndTabItem(); 1229 } 1230 1231 ImGui::EndTabBar(); 1232 } 1233 1234 ImGui::End(); 1235} 1236 1237static void debug_window_vram_background(void) 1238{ 1239 Memory* memory = emu_get_core()->GetMemory(); 1240 1241 static bool show_grid = true; 1242 static bool show_screen = true; 1243 static int tile_address_radio = 0; 1244 static int map_address_radio = 0; 1245 float scale = 1.5f; 1246 float size = 256.0f * scale; 1247 float spacing = 8.0f * scale; 1248 1249 ImGui::Checkbox("Show Grid##grid_bg", &show_grid); ImGui::SameLine(); 1250 ImGui::Checkbox("Show Screen Rect", &show_screen); 1251 1252 ImGui::PushFont(gui_default_font); 1253 1254 ImGui::Columns(2, "bg", false); 1255 ImGui::SetColumnOffset(1, size + 10.0f); 1256 1257 ImVec2 p = ImGui::GetCursorScreenPos(); 1258 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 1259 ImGuiIO& io = ImGui::GetIO(); 1260 1261 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_background, ImVec2(size, size)); 1262 1263 if (show_grid) 1264 { 1265 float x = p.x; 1266 for (int n = 0; n <= 32; n++) 1267 { 1268 draw_list->AddLine(ImVec2(x, p.y), ImVec2(x, p.y + size), ImColor(dark_gray), 1.0f); 1269 x += spacing; 1270 } 1271 1272 float y = p.y; 1273 for (int n = 0; n <= 32; n++) 1274 { 1275 draw_list->AddLine(ImVec2(p.x, y), ImVec2(p.x + size, y), ImColor(dark_gray), 1.0f); 1276 y += spacing; 1277 } 1278 } 1279 1280 if (show_screen) 1281 { 1282 u8 scroll_x = memory->Retrieve(0xFF43); 1283 u8 scroll_y = memory->Retrieve(0xFF42); 1284 1285 float grid_x_max = p.x + size; 1286 float grid_y_max = p.y + size; 1287 1288 float rect_x_min = p.x + (scroll_x * scale); 1289 float rect_y_min = p.y + (scroll_y * scale); 1290 float rect_x_max = p.x + ((scroll_x + GAMEBOY_WIDTH) * scale); 1291 float rect_y_max = p.y + ((scroll_y + GAMEBOY_HEIGHT) * scale); 1292 1293 float x_overflow = 0.0f; 1294 float y_overflow = 0.0f; 1295 1296 if (rect_x_max > grid_x_max) 1297 x_overflow = rect_x_max - grid_x_max; 1298 if (rect_y_max > grid_y_max) 1299 y_overflow = rect_y_max - grid_y_max; 1300 1301 draw_list->AddLine(ImVec2(rect_x_min, rect_y_min), ImVec2(fminf(rect_x_max, grid_x_max), rect_y_min), ImColor(green), 2.0f); 1302 if (x_overflow > 0.0f) 1303 draw_list->AddLine(ImVec2(p.x, rect_y_min), ImVec2(p.x + x_overflow, rect_y_min), ImColor(green), 2.0f); 1304 1305 draw_list->AddLine(ImVec2(rect_x_min, rect_y_min), ImVec2(rect_x_min, fminf(rect_y_max, grid_y_max)), ImColor(green), 2.0f); 1306 if (y_overflow > 0.0f) 1307 draw_list->AddLine(ImVec2(rect_x_min, p.y), ImVec2(rect_x_min, p.y + y_overflow), ImColor(green), 2.0f); 1308 1309 draw_list->AddLine(ImVec2(rect_x_min, (y_overflow > 0.0f) ? p.y + y_overflow : rect_y_max), ImVec2(fminf(rect_x_max, grid_x_max), (y_overflow > 0.0f) ? p.y + y_overflow : rect_y_max), ImColor(green), 2.0f); 1310 if (x_overflow > 0.0f) 1311 draw_list->AddLine(ImVec2(p.x, (y_overflow > 0.0f) ? p.y + y_overflow : rect_y_max), ImVec2(p.x + x_overflow, (y_overflow > 0.0f) ? p.y + y_overflow : rect_y_max), ImColor(green), 2.0f); 1312 1313 draw_list->AddLine(ImVec2((x_overflow > 0.0f) ? p.x + x_overflow : rect_x_max, rect_y_min), ImVec2((x_overflow > 0.0f) ? p.x + x_overflow : rect_x_max, fminf(rect_y_max, grid_y_max)), ImColor(green), 2.0f); 1314 if (y_overflow > 0.0f) 1315 draw_list->AddLine(ImVec2((x_overflow > 0.0f) ? p.x + x_overflow : rect_x_max, p.y), ImVec2((x_overflow > 0.0f) ? p.x + x_overflow : rect_x_max, p.y + y_overflow), ImColor(green), 2.0f); 1316 } 1317 1318 float mouse_x = io.MousePos.x - p.x; 1319 float mouse_y = io.MousePos.y - p.y; 1320 1321 int tile_x = -1; 1322 int tile_y = -1; 1323 if ((mouse_x >= 0.0f) && (mouse_x < size) && (mouse_y >= 0.0f) && (mouse_y < size)) 1324 { 1325 tile_x = (int)(mouse_x / spacing); 1326 tile_y = (int)(mouse_y / spacing); 1327 1328 draw_list->AddRect(ImVec2(p.x + (tile_x * spacing), p.y + (tile_y * spacing)), ImVec2(p.x + ((tile_x + 1) * spacing), p.y + ((tile_y + 1) * spacing)), ImColor(cyan), 2.0f, 15, 2.0f); 1329 1330 ImGui::NextColumn(); 1331 1332 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_background, ImVec2(128.0f, 128.0f), ImVec2((1.0f / 32.0f) * tile_x, (1.0f / 32.0f) * tile_y), ImVec2((1.0f / 32.0f) * (tile_x + 1), (1.0f / 32.0f) * (tile_y + 1))); 1333 1334 ImGui::TextColored(yellow, "DMG:"); 1335 1336 ImGui::TextColored(cyan, " X:"); ImGui::SameLine(); 1337 ImGui::Text("$%02X", tile_x); ImGui::SameLine(); 1338 ImGui::TextColored(cyan, " Y:"); ImGui::SameLine(); 1339 ImGui::Text("$%02X", tile_y); 1340 1341 u8 lcdc = memory->Retrieve(0xFF40); 1342 1343 int tile_start_addr = emu_debug_background_tile_address >= 0 ? emu_debug_background_tile_address : IsSetBit(lcdc, 4) ? 0x8000 : 0x8800; 1344 int map_start_addr = emu_debug_background_map_address >= 0 ? emu_debug_background_map_address : IsSetBit(lcdc, 3) ? 0x9C00 : 0x9800; 1345 1346 u16 map_addr = map_start_addr + (32 * tile_y) + tile_x; 1347 1348 ImGui::TextColored(cyan, " Map Addr: "); ImGui::SameLine(); 1349 ImGui::Text("$%04X", map_addr); 1350 1351 int map_tile = 0; 1352 1353 if (tile_start_addr == 0x8800) 1354 { 1355 map_tile = static_cast<s8> (memory->Retrieve(map_addr)); 1356 map_tile += 128; 1357 } 1358 else 1359 { 1360 map_tile = memory->Retrieve(map_addr); 1361 } 1362 1363 ImGui::TextColored(cyan, " Tile Addr:"); ImGui::SameLine(); 1364 ImGui::Text("$%04X", tile_start_addr + (map_tile << 4)); 1365 ImGui::TextColored(cyan, " Tile Number:"); ImGui::SameLine(); 1366 ImGui::Text("$%02X", memory->Retrieve(map_addr)); 1367 1368 if (emu_is_cgb()) 1369 { 1370 ImGui::TextColored(yellow, "GBC:"); 1371 1372 u8 cgb_tile_attr = memory->ReadCGBLCDRAM(map_addr, true); 1373 int cgb_tile_pal = cgb_tile_attr & 0x07; 1374 int cgb_tile_bank = IsSetBit(cgb_tile_attr, 3) ? 1 : 0; 1375 bool cgb_tile_xflip = IsSetBit(cgb_tile_attr, 5); 1376 bool cgb_tile_yflip = IsSetBit(cgb_tile_attr, 6); 1377 1378 ImGui::TextColored(cyan, " Attributes:"); ImGui::SameLine(); 1379 ImGui::Text("$%02X", cgb_tile_attr); 1380 ImGui::TextColored(cyan, " Palette:"); ImGui::SameLine(); 1381 ImGui::Text("%d", cgb_tile_pal); 1382 ImGui::TextColored(cyan, " Bank:"); ImGui::SameLine(); 1383 ImGui::Text("%d", cgb_tile_bank); 1384 1385 ImGui::TextColored(cyan, " X-Flip:"); ImGui::SameLine(); 1386 cgb_tile_xflip ? ImGui::TextColored(green, "ON") : ImGui::TextColored(gray, "OFF"); 1387 1388 ImGui::TextColored(cyan, " Y-Flip:"); ImGui::SameLine(); 1389 cgb_tile_yflip ? ImGui::TextColored(green, "ON") : ImGui::TextColored(gray, "OFF"); 1390 } 1391 } 1392 1393 ImGui::Columns(1); 1394 1395 ImGui::PopFont(); 1396 1397 ImGui::Text("Tile address:"); ImGui::SameLine(); 1398 ImGui::RadioButton("Auto##tile", &tile_address_radio, 0); ImGui::SameLine(); 1399 ImGui::RadioButton("0x8000", &tile_address_radio, 1); ImGui::SameLine(); 1400 ImGui::RadioButton("0x8800", &tile_address_radio, 2); 1401 1402 switch (tile_address_radio) 1403 { 1404 case 0: 1405 emu_debug_background_tile_address = -1; 1406 break; 1407 case 1: 1408 emu_debug_background_tile_address = 0x8000; 1409 break; 1410 case 2: 1411 emu_debug_background_tile_address = 0x8800; 1412 break; 1413 default: 1414 emu_debug_background_tile_address = -1; 1415 break; 1416 } 1417 1418 ImGui::Text("Map address:"); ImGui::SameLine(); 1419 ImGui::RadioButton("Auto##map", &map_address_radio, 0); ImGui::SameLine(); 1420 ImGui::RadioButton("0x9C00", &map_address_radio, 1); ImGui::SameLine(); 1421 ImGui::RadioButton("0x9800", &map_address_radio, 2); 1422 1423 switch (map_address_radio) 1424 { 1425 case 0: 1426 emu_debug_background_map_address = -1; 1427 break; 1428 case 1: 1429 emu_debug_background_map_address = 0x9C00; 1430 break; 1431 case 2: 1432 emu_debug_background_map_address = 0x9800; 1433 break; 1434 default: 1435 emu_debug_background_map_address = -1; 1436 break; 1437 } 1438} 1439 1440static void debug_window_vram_tiles(void) 1441{ 1442 static bool show_grid = true; 1443 float scale = 1.5f; 1444 float width = 8.0f * 16.0f * scale; 1445 float height = 8.0f * 24.0f * scale; 1446 float spacing = 8.0f * scale; 1447 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 1448 ImGuiIO& io = ImGui::GetIO(); 1449 ImVec2 p[2]; 1450 1451 ImGui::Checkbox("Show Grid##grid_tiles", &show_grid); 1452 ImGui::SameLine(150.0f); 1453 1454 ImGui::PushItemWidth(80.0f); 1455 1456 if (!emu_is_cgb()) 1457 { 1458 ImGui::Combo("Palette##dmg_tile_palette", &emu_debug_tile_dmg_palette, "BGP\0OBP0\0OBP1\0\0"); 1459 } 1460 else 1461 { 1462 ImGui::Combo("Palette##cgb_tile_palette", &emu_debug_tile_color_palette, "BCP0\0BCP1\0BCP2\0BCP3\0BCP4\0BCP5\0BCP6\0BCP7\0OCP0\0OCP1\0OCP2\0OCP3\0OCP4\0OCP5\0OCP6\0OCP7\0\0"); 1463 } 1464 1465 ImGui::PopItemWidth(); 1466 1467 ImGui::Columns(2, "bg", false); 1468 ImGui::SetColumnOffset(1, (width * 2.0f) + 16.0f); 1469 1470 p[0] = ImGui::GetCursorScreenPos(); 1471 1472 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_tiles[0], ImVec2(width, height)); 1473 1474 ImGui::SameLine(); 1475 1476 p[1] = ImGui::GetCursorScreenPos(); 1477 1478 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_tiles[1], ImVec2(width, height)); 1479 1480 for (int i = 0; i < 2; i++) 1481 { 1482 if (show_grid) 1483 { 1484 float x = p[i].x; 1485 for (int n = 0; n <= 16; n++) 1486 { 1487 draw_list->AddLine(ImVec2(x, p[i].y), ImVec2(x, p[i].y + height), ImColor(dark_gray), 1.0f); 1488 x += spacing; 1489 } 1490 1491 float y = p[i].y; 1492 for (int n = 0; n <= 24; n++) 1493 { 1494 draw_list->AddLine(ImVec2(p[i].x, y), ImVec2(p[i].x + width, y), ImColor(dark_gray), ((n == 8) || (n == 16)) ? 3.0f : 1.0f); 1495 y += spacing; 1496 } 1497 } 1498 } 1499 1500 for (int i = 0; i < 2; i++) 1501 { 1502 float mouse_x = io.MousePos.x - p[i].x; 1503 float mouse_y = io.MousePos.y - p[i].y; 1504 1505 int tile_x = -1; 1506 int tile_y = -1; 1507 1508 if ((mouse_x >= 0.0f) && (mouse_x < width) && (mouse_y >= 0.0f) && (mouse_y < height)) 1509 { 1510 tile_x = (int)(mouse_x / spacing); 1511 tile_y = (int)(mouse_y / spacing); 1512 1513 draw_list->AddRect(ImVec2(p[i].x + (tile_x * spacing), p[i].y + (tile_y * spacing)), ImVec2(p[i].x + ((tile_x + 1) * spacing), p[i].y + ((tile_y + 1) * spacing)), ImColor(cyan), 2.0f, 15, 2.0f); 1514 1515 ImGui::NextColumn(); 1516 1517 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_tiles[i], ImVec2(128.0f, 128.0f), ImVec2((1.0f / 16.0f) * tile_x, (1.0f / 24.0f) * tile_y), ImVec2((1.0f / 16.0f) * (tile_x + 1), (1.0f / 24.0f) * (tile_y + 1))); 1518 1519 ImGui::PushFont(gui_default_font); 1520 1521 ImGui::TextColored(yellow, "DETAILS:"); 1522 1523 int tile_full = (tile_y << 4) + tile_x; 1524 int tile = tile_full & 0xFF; 1525 1526 ImGui::TextColored(cyan, " Tile Number:"); ImGui::SameLine(); 1527 ImGui::Text("$%02X", tile); 1528 ImGui::TextColored(cyan, " Tile Addr:"); ImGui::SameLine(); 1529 ImGui::Text("$%04X", 0x8000 + (tile_full << 4)); 1530 1531 ImGui::PopFont(); 1532 } 1533 } 1534 1535 ImGui::Columns(1); 1536} 1537 1538static void debug_window_vram_oam(void) 1539{ 1540 float scale = 5.0f; 1541 float width = 8.0f * scale; 1542 float height_8 = 8.0f * scale; 1543 float height_16 = 16.0f * scale; 1544 1545 GearboyCore* core = emu_get_core(); 1546 Memory* memory = core->GetMemory(); 1547 1548 ImVec2 p[40]; 1549 1550 ImGuiIO& io = ImGui::GetIO(); 1551 1552 u8 lcdc = memory->Retrieve(0xFF40); 1553 bool sprites_16 = IsSetBit(lcdc, 2); 1554 1555 ImGui::PushFont(gui_default_font); 1556 1557 ImGui::Columns(2, "oam", false); 1558 ImGui::SetColumnOffset(1, 280.0f); 1559 1560 ImGui::BeginChild("sprites", ImVec2(0, 0), true); 1561 1562 for (int s = 0; s < 40; s++) 1563 { 1564 p[s] = ImGui::GetCursorScreenPos(); 1565 1566 ImGui::Image((void*)(intptr_t)renderer_emu_debug_vram_oam[s], ImVec2(width, sprites_16 ? height_16 : height_8), ImVec2(0.0f, 0.0f), ImVec2(1.0f, sprites_16 ? 1.0f : 0.5f)); 1567 1568 float mouse_x = io.MousePos.x - p[s].x; 1569 float mouse_y = io.MousePos.y - p[s].y; 1570 1571 if ((mouse_x >= 0.0f) && (mouse_x < width) && (mouse_y >= 0.0f) && (mouse_y < (sprites_16 ? height_16 : height_8))) 1572 { 1573 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 1574 draw_list->AddRect(ImVec2(p[s].x, p[s].y), ImVec2(p[s].x + width, p[s].y + (sprites_16 ? height_16 : height_8)), ImColor(cyan), 2.0f, 15, 3.0f); 1575 } 1576 1577 if (s % 5 < 4) 1578 ImGui::SameLine(); 1579 } 1580 1581 ImGui::EndChild(); 1582 1583 ImGui::NextColumn(); 1584 1585 ImVec2 p_screen = ImGui::GetCursorScreenPos(); 1586 1587 float screen_scale = 1.5f; 1588 1589 ImGui::Image((void*)(intptr_t)renderer_emu_texture, ImVec2(GAMEBOY_WIDTH * screen_scale, GAMEBOY_HEIGHT * screen_scale)); 1590 1591 for (int s = 0; s < 40; s++) 1592 { 1593 if ((p[s].x == 0) && (p[s].y == 0)) 1594 continue; 1595 1596 float mouse_x = io.MousePos.x - p[s].x; 1597 float mouse_y = io.MousePos.y - p[s].y; 1598 1599 if ((mouse_x >= 0.0f) && (mouse_x < width) && (mouse_y >= 0.0f) && (mouse_y < (sprites_16 ? height_16 : height_8))) 1600 { 1601 u16 address = 0xFE00 + (4 * s); 1602 1603 u8 y = memory->Retrieve(address); 1604 u8 x = memory->Retrieve(address + 1); 1605 u8 tile = memory->Retrieve(address + 2); 1606 u8 flags = memory->Retrieve(address + 3); 1607 int palette = IsSetBit(flags, 4) ? 1 : 0; 1608 bool xflip = IsSetBit(flags, 5); 1609 bool yflip = IsSetBit(flags, 6); 1610 bool priority = !IsSetBit(flags, 7); 1611 bool cgb_bank = IsSetBit(flags, 3); 1612 int cgb_pal = flags & 0x07; 1613 1614 float real_x = x - 8.0f; 1615 float real_y = y - 16.0f; 1616 float rectx_min = p_screen.x + (real_x * screen_scale); 1617 float rectx_max = p_screen.x + ((real_x + 8.0f) * screen_scale); 1618 float recty_min = p_screen.y + (real_y * screen_scale); 1619 float recty_max = p_screen.y + ((real_y + (sprites_16 ? 16.0f : 8.0f)) * screen_scale); 1620 1621 rectx_min = fminf(fmaxf(rectx_min, p_screen.x), p_screen.x + (GAMEBOY_WIDTH * screen_scale)); 1622 rectx_max = fminf(fmaxf(rectx_max, p_screen.x), p_screen.x + (GAMEBOY_WIDTH * screen_scale)); 1623 recty_min = fminf(fmaxf(recty_min, p_screen.y), p_screen.y + (GAMEBOY_HEIGHT * screen_scale)); 1624 recty_max = fminf(fmaxf(recty_max, p_screen.y), p_screen.y + (GAMEBOY_HEIGHT * screen_scale)); 1625 1626 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 1627 draw_list->AddRect(ImVec2(rectx_min, recty_min), ImVec2(rectx_max, recty_max), ImColor(cyan), 2.0f, 15, 2.0f); 1628 1629 ImGui::TextColored(yellow, "DETAILS:"); 1630 ImGui::TextColored(cyan, " X:"); ImGui::SameLine(); 1631 ImGui::Text("$%02X", x); ImGui::SameLine(); 1632 ImGui::TextColored(cyan, " Y:"); ImGui::SameLine(); 1633 ImGui::Text("$%02X", y); ImGui::SameLine(); 1634 1635 ImGui::TextColored(cyan, " Tile:"); ImGui::SameLine(); 1636 ImGui::Text("$%02X", tile); 1637 1638 ImGui::TextColored(cyan, " Tile Addr:"); ImGui::SameLine(); 1639 ImGui::Text("$%04X", 0x8000 + (tile * 16)); ImGui::SameLine(); 1640 1641 ImGui::TextColored(cyan, " Bank:"); ImGui::SameLine(); 1642 ImGui::Text("%d", cgb_bank); 1643 1644 ImGui::TextColored(cyan, " OAM Addr:"); ImGui::SameLine(); 1645 ImGui::Text("$%04X", address); ImGui::SameLine(); 1646 1647 1648 ImGui::TextColored(cyan, " Flags:"); ImGui::SameLine(); 1649 ImGui::Text("$%02X", flags); 1650 1651 ImGui::TextColored(cyan, " Priority:"); ImGui::SameLine(); 1652 priority ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF"); ImGui::SameLine(); 1653 1654 ImGui::TextColored(cyan, " Palette:"); ImGui::SameLine(); 1655 ImGui::Text("%d", emu_is_cgb() ? cgb_pal : palette); 1656 1657 ImGui::TextColored(cyan, " X-Flip:"); ImGui::SameLine(); 1658 xflip ? ImGui::TextColored(green, "ON ") : ImGui::TextColored(gray, "OFF"); ImGui::SameLine(); 1659 1660 ImGui::TextColored(cyan, " Y-Flip:"); ImGui::SameLine(); 1661 yflip ? ImGui::TextColored(green, "ON") : ImGui::TextColored(gray, "OFF"); 1662 } 1663 } 1664 1665 ImGui::Columns(1); 1666 1667 ImGui::PopFont(); 1668} 1669 1670static void debug_window_vram_palettes(void) 1671{ 1672 GearboyCore* core = emu_get_core(); 1673 Video* video = core->GetVideo(); 1674 Memory* memory = core->GetMemory(); 1675 u16* palette = core->GetDMGInternalPalette(); 1676 1677 ImGui::PushFont(gui_default_font); 1678 1679 ImGui::TextColored(yellow, "DMG:"); ImGui::SameLine(); 1680 ImGui::TextColored(cyan, " 0 1 2 3"); 1681 1682 u8 bgp = memory->Retrieve(0xFF47); 1683 u8 obp0 = memory->Retrieve(0xFF48); 1684 u8 obp1 = memory->Retrieve(0xFF49); 1685 1686 ImGui::TextColored(cyan, " $FF47"); ImGui::SameLine(); 1687 ImGui::TextColored(magenta, "BGP "); ImGui::SameLine(); 1688 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ") ", bgp, BYTE_TO_BINARY(bgp)); ImGui::SameLine(); 1689 1690 for (int i = 0; i < 4; i++) 1691 { 1692 int index = (bgp >> (i * 2)) & 0x03; 1693 int color = palette[index]; 1694 ImVec4 float_color = color_565_to_float(color); 1695 char id[16]; 1696 sprintf(id, "##dmg_bg_%d", i); 1697 ImGui::ColorEdit3(id, (float*)&float_color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker); ImGui::SameLine(); 1698 ImGui::Text("%d ", index); 1699 if (i < 3) 1700 ImGui::SameLine(); 1701 } 1702 1703 ImGui::TextColored(cyan, " $FF48"); ImGui::SameLine(); 1704 ImGui::TextColored(magenta, "OBP0"); ImGui::SameLine(); 1705 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ") ", obp0, BYTE_TO_BINARY(obp0)); ImGui::SameLine(); 1706 1707 for (int i = 0; i < 4; i++) 1708 { 1709 int index = (obp0 >> (i * 2)) & 0x03; 1710 int color = palette[index]; 1711 ImVec4 float_color = color_565_to_float(color); 1712 char id[16]; 1713 sprintf(id, "##dmg_bg_%d", i); 1714 ImGui::ColorEdit3(id, (float*)&float_color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker); ImGui::SameLine(); 1715 ImGui::Text("%d ", index); 1716 if (i < 3) 1717 ImGui::SameLine(); 1718 } 1719 1720 ImGui::TextColored(cyan, " $FF49"); ImGui::SameLine(); 1721 ImGui::TextColored(magenta, "OBP1"); ImGui::SameLine(); 1722 ImGui::Text("$%02X (" BYTE_TO_BINARY_PATTERN_SPACED ") ", obp1, BYTE_TO_BINARY(obp1)); ImGui::SameLine(); 1723 1724 for (int i = 0; i < 4; i++) 1725 { 1726 int index = (obp1 >> (i * 2)) & 0x03; 1727 int color = palette[index]; 1728 ImVec4 float_color = color_565_to_float(color); 1729 char id[16]; 1730 sprintf(id, "##dmg_bg_%d", i); 1731 ImGui::ColorEdit3(id, (float*)&float_color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker); ImGui::SameLine(); 1732 ImGui::Text("%d ", index); 1733 if (i < 3) 1734 ImGui::SameLine(); 1735 } 1736 1737 ImGui::Text(" "); 1738 1739 PaletteMatrix bg_palettes = video->GetCGBBackgroundPalettes(); 1740 PaletteMatrix sprite_palettes = video->GetCGBSpritePalettes(); 1741 1742 ImGui::Columns(2, "palettes"); 1743 1744 ImGui::TextColored(yellow, "GBC BACKGROUND:"); 1745 1746 ImGui::NextColumn(); 1747 1748 ImGui::TextColored(yellow, "GBC SPRITES:"); 1749 1750 ImGui::NextColumn(); 1751 1752 ImGui::Separator(); 1753 1754 for (int p = 0; p < 8; p++) 1755 { 1756 ImGui::TextColored(cyan, " %d ", p); ImGui::SameLine(); 1757 1758 for (int c = 0; c < 4; c++) 1759 { 1760 u16 color = (*bg_palettes)[p][c][1]; 1761 ImVec4 float_color = color_565_to_float(color); 1762 char id[16]; 1763 sprintf(id, "##cgb_bg_%d_%d", p, c); 1764 ImGui::ColorEdit3(id, (float*)&float_color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker); 1765 if (c < 3) 1766 { 1767 ImGui::SameLine(); ImGui::Dummy(ImVec2(8.0f, 0.0f)); 1768 ImGui::SameLine(); 1769 } 1770 } 1771 1772 ImGui::Text(" "); ImGui::SameLine(); 1773 1774 for (int c = 0; c < 4; c++) 1775 { 1776 u16 color = (*bg_palettes)[p][c][1]; 1777 ImGui::Text("%04X ", color); 1778 if (c < 3) 1779 ImGui::SameLine(); 1780 } 1781 } 1782 1783 ImGui::NextColumn(); 1784 1785 for (int p = 0; p < 8; p++) 1786 { 1787 ImGui::TextColored(cyan, " %d ", p); ImGui::SameLine(); 1788 1789 for (int c = 0; c < 4; c++) 1790 { 1791 u16 color = (*sprite_palettes)[p][c][1]; 1792 ImVec4 float_color = color_565_to_float(color); 1793 char id[16]; 1794 sprintf(id, "##cgb_bg_%d_%d", p, c); 1795 ImGui::ColorEdit3(id, (float*)&float_color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoPicker); 1796 if (c < 3) 1797 { 1798 ImGui::SameLine(); ImGui::Dummy(ImVec2(8.0f, 0.0f)); 1799 ImGui::SameLine(); 1800 } 1801 } 1802 1803 ImGui::Text(" "); ImGui::SameLine(); 1804 1805 for (int c = 0; c < 4; c++) 1806 { 1807 u16 color = (*sprite_palettes)[p][c][1]; 1808 ImGui::Text("%04X ", color); 1809 if (c < 3) 1810 ImGui::SameLine(); 1811 } 1812 } 1813 1814 ImGui::Columns(1); 1815 1816 ImGui::PopFont(); 1817} 1818 1819static void add_symbol(const char* line) 1820{ 1821 Log("Loading symbol %s", line); 1822 1823 DebugSymbol s; 1824 1825 std::string str(line); 1826 1827 str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); 1828 str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); 1829 1830 size_t first = str.find_first_not_of(' '); 1831 if (std::string::npos == first) 1832 { 1833 str = ""; 1834 } 1835 else 1836 { 1837 size_t last = str.find_last_not_of(' '); 1838 str = str.substr(first, (last - first + 1)); 1839 } 1840 1841 std::size_t comment = str.find(";"); 1842 1843 if (comment != std::string::npos) 1844 str = str.substr(0 , comment); 1845 1846 std::size_t space = str.find(" "); 1847 1848 if (space != std::string::npos) 1849 { 1850 s.text = str.substr(space + 1 , std::string::npos); 1851 str = str.substr(0, space); 1852 1853 std::size_t separator = str.find(":"); 1854 1855 try 1856 { 1857 if (separator != std::string::npos) 1858 { 1859 s.address = (u16)std::stoul(str.substr(separator + 1 , std::string::npos), 0, 16); 1860 s.bank = std::stoul(str.substr(0, separator), 0 , 16); 1861 } 1862 else 1863 { 1864 s.address = (u16)std::stoul(str, 0, 16); 1865 s.bank = 0; 1866 } 1867 1868 symbols.push_back(s); 1869 } 1870 catch(const std::invalid_argument&) 1871 { 1872 } 1873 } 1874} 1875 1876static void add_breakpoint_cpu(void) 1877{ 1878 int input_len = (int)strlen(brk_address_cpu); 1879 u16 target_address = 0; 1880 int target_bank = 0; 1881 int target_offset = 0; 1882 1883 try 1884 { 1885 if ((input_len == 7) && (brk_address_cpu[2] == ':')) 1886 { 1887 std::string str(brk_address_cpu); 1888 std::size_t separator = str.find(":"); 1889 1890 if (separator != std::string::npos) 1891 { 1892 target_address = (u16)std::stoul(str.substr(separator + 1 , std::string::npos), 0, 16); 1893 1894 target_bank = std::stoul(str.substr(0, separator), 0 , 16); 1895 target_bank &= 0xFF; 1896 } 1897 } 1898 else if (input_len == 4) 1899 { 1900 target_bank = 0; 1901 target_address = (u16)std::stoul(brk_address_cpu, 0, 16); 1902 } 1903 else 1904 { 1905 return; 1906 } 1907 } 1908 catch(const std::invalid_argument&) 1909 { 1910 return; 1911 } 1912 1913 Memory::stDisassembleRecord** memoryMap = emu_get_core()->GetMemory()->GetDisassembledMemoryMap(); 1914 Memory::stDisassembleRecord** romMap = emu_get_core()->GetMemory()->GetDisassembledROMMemoryMap(); 1915 Memory::stDisassembleRecord** map = NULL; 1916 1917 bool rom = true; 1918 1919 if ((target_address & 0xC000) == 0x0000) 1920 { 1921 target_offset = (0x4000 * target_bank) + target_address; 1922 map = romMap; 1923 } 1924 else if ((target_address & 0xC000) == 0x4000) 1925 { 1926 target_offset = (0x4000 * target_bank) + (target_address & 0x3FFF); 1927 map = romMap; 1928 } 1929 else 1930 { 1931 target_offset = target_address; 1932 map = memoryMap; 1933 rom = false; 1934 } 1935 1936 brk_address_cpu[0] = 0; 1937 1938 bool found = false; 1939 std::vector<Memory::stDisassembleRecord*>* breakpoints = emu_get_core()->GetMemory()->GetBreakpointsCPU(); 1940 1941 if (IsValidPointer(map[target_offset])) 1942 { 1943 for (long unsigned int b = 0; b < breakpoints->size(); b++) 1944 { 1945 if ((*breakpoints)[b] == map[target_offset]) 1946 { 1947 found = true; 1948 break; 1949 } 1950 } 1951 } 1952 1953 if (!found) 1954 { 1955 if (!IsValidPointer(map[target_offset])) 1956 { 1957 map[target_offset] = new Memory::stDisassembleRecord; 1958 1959 if (rom) 1960 { 1961 map[target_offset]->address = target_offset & 0x3FFF; 1962 map[target_offset]->bank = target_offset >> 14; 1963 } 1964 else 1965 { 1966 map[target_offset]->address = 0; 1967 map[target_offset]->bank = 0; 1968 } 1969 1970 map[target_offset]->name[0] = 0; 1971 map[target_offset]->bytes[0] = 0; 1972 map[target_offset]->size = 0; 1973 map[target_offset]->jump = false; 1974 map[target_offset]->jump_address = 0; 1975 for (int i = 0; i < 4; i++) 1976 map[target_offset]->opcodes[i] = 0; 1977 } 1978 1979 breakpoints->push_back(map[target_offset]); 1980 } 1981} 1982 1983static void add_breakpoint_mem(void) 1984{ 1985 int input_len = (int)strlen(brk_address_mem); 1986 u16 address1 = 0; 1987 u16 address2 = 0; 1988 bool range = false; 1989 1990 try 1991 { 1992 if ((input_len == 9) && (brk_address_mem[4] == '-')) 1993 { 1994 std::string str(brk_address_mem); 1995 std::size_t separator = str.find("-"); 1996 1997 if (separator != std::string::npos) 1998 { 1999 address1 = (u16)std::stoul(str.substr(0, separator), 0 , 16); 2000 address2 = (u16)std::stoul(str.substr(separator + 1 , std::string::npos), 0, 16); 2001 range = true; 2002 } 2003 } 2004 else if (input_len == 4) 2005 { 2006 address1 = (u16)std::stoul(brk_address_mem, 0, 16); 2007 } 2008 else 2009 { 2010 return; 2011 } 2012 } 2013 catch(const std::invalid_argument&) 2014 { 2015 return; 2016 } 2017 2018 bool found = false; 2019 std::vector<Memory::stMemoryBreakpoint>* breakpoints = emu_get_core()->GetMemory()->GetBreakpointsMem(); 2020 2021 for (long unsigned int b = 0; b < breakpoints->size(); b++) 2022 { 2023 Memory::stMemoryBreakpoint temp = (*breakpoints)[b]; 2024 if ((temp.address1 == address1) && (temp.address2 == address2) && (temp.range == range)) 2025 { 2026 found = true; 2027 break; 2028 } 2029 } 2030 2031 if (!found) 2032 { 2033 Memory::stMemoryBreakpoint new_breakpoint; 2034 new_breakpoint.address1 = address1; 2035 new_breakpoint.address2 = address2; 2036 new_breakpoint.range = range; 2037 new_breakpoint.read = brk_new_mem_read; 2038 new_breakpoint.write = brk_new_mem_write; 2039 2040 breakpoints->push_back(new_breakpoint); 2041 } 2042 2043 brk_address_mem[0] = 0; 2044} 2045 2046static void request_goto_address(u16 address) 2047{ 2048 goto_address_requested = true; 2049 goto_address_target = address; 2050} 2051 2052static ImVec4 color_565_to_float(u16 color) 2053{ 2054 ImVec4 ret; 2055 ret.w = 0; 2056 ret.x = (1.0f / 31.0f) * ((color >> 11) & 0x1F); 2057 ret.y = (1.0f / 63.0f) * ((color >> 5) & 0x3F); 2058 ret.z = (1.0f / 31.0f) * (color & 0x1F); 2059 return ret; 2060}