cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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}