summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/debugger/debugimgui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/debugger/debugimgui.cpp')
-rw-r--r--src/osd/modules/debugger/debugimgui.cpp1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/src/osd/modules/debugger/debugimgui.cpp b/src/osd/modules/debugger/debugimgui.cpp
new file mode 100644
index 00000000000..060791a3196
--- /dev/null
+++ b/src/osd/modules/debugger/debugimgui.cpp
@@ -0,0 +1,1081 @@
+// Initial test to attempt an imgui based debugger
+
+#include "emu.h"
+#include "imgui/imgui.h"
+#include "uiinput.h"
+
+#include "debug/debugvw.h"
+#include "debug/dvdisasm.h"
+#include "debug/dvmemory.h"
+#include "debug/dvbpoints.h"
+#include "debug/dvwpoints.h"
+#include "debug/debugcon.h"
+#include "debug/debugcpu.h"
+
+#include "config.h"
+#include "debugger.h"
+#include "modules/lib/osdobj_common.h"
+#include "debug_module.h"
+#include "modules/osdmodule.h"
+
+enum
+{
+ VIEW_STATE_BUTTON = 0x01,
+ VIEW_STATE_MOVING = 0x02,
+ VIEW_STATE_SIZING = 0x04,
+ VIEW_STATE_NEEDS_UPDATE = 0x08,
+ VIEW_STATE_FOLLOW_CPU = 0x10,
+ VIEW_STATE_VISIBLE = 0x20
+};
+
+class DView
+{
+ DISABLE_COPYING(DView);
+
+public:
+ DView(running_machine &machine, debug_view_type type, int flags)
+ : next(nullptr),
+ type(0),
+ state(0),
+ ofs_x(0),
+ ofs_y(0),
+ exec_cmd(false)
+ {
+ this->view = machine.debug_view().alloc_view(type, nullptr, this);
+ this->type = type;
+ this->m_machine = &machine;
+ this->state = flags | VIEW_STATE_NEEDS_UPDATE | VIEW_STATE_VISIBLE;
+ this->width = 300;
+ this->height = 300;
+
+ /* specials */
+ switch (type)
+ {
+ case DVT_DISASSEMBLY:
+ /* set up disasm view */
+ downcast<debug_view_disasm *>(this->view)->set_expression("curpc");
+ break;
+ default:
+ break;
+ }
+ }
+ ~DView()
+ {
+ //this->target->debug_free(*this->container);
+ machine().debug_view().free_view(*this->view);
+ }
+
+ running_machine &machine() const { assert(m_machine != nullptr); return *m_machine; }
+
+ DView * next;
+
+ int type;
+ debug_view * view;
+ running_machine * m_machine;
+ int state;
+ // drawing
+ int ofs_x;
+ int ofs_y;
+ int width;
+ int height; // width and height of the view area, passed to ImGui::BeginChild
+ std::string title;
+ int last_x;
+ int last_y;
+ bool exec_cmd; // console only
+ int src_sel;
+ char console_input[512];
+};
+
+class debug_imgui : public osd_module, public debug_module
+{
+public:
+ debug_imgui()
+ : osd_module(OSD_DEBUG_PROVIDER, "imgui"), debug_module(),
+ m_machine(nullptr),
+ m_hide(false),
+ m_win_count(0)
+ {
+ }
+
+ virtual ~debug_imgui() { }
+
+ virtual int init(const osd_options &options) override { return 0; }
+ virtual void exit() override {};
+
+ virtual void init_debugger(running_machine &machine) override;
+ virtual void wait_for_debugger(device_t &device, bool firststop) override;
+ virtual void debugger_update() override;
+
+private:
+ void handle_mouse();
+ void handle_keys();
+ void handle_console(running_machine* machine);
+ void update();
+ void draw_console();
+ void add_disasm(int id);
+ void add_memory(int id);
+ void add_bpoints(int id);
+ void add_wpoints(int id);
+ void draw_disasm(DView* view_ptr, bool* opened);
+ void draw_memory(DView* view_ptr, bool* opened);
+ void draw_bpoints(DView* view_ptr, bool* opened);
+ void update_cpu_view(device_t* device);
+
+ running_machine* m_machine;
+ INT32 m_mouse_x;
+ INT32 m_mouse_y;
+ bool m_mouse_button;
+ bool m_running;
+ const char* font_name;
+ float font_size;
+ ImguiFontHandle m_font;
+ UINT8 m_key_char;
+ bool m_hide;
+ unsigned char* font_data;
+ int m_win_count; // number of active windows, does not decrease, used to ID individual windows
+};
+
+// globals
+static std::vector<DView*> view_list;
+static DView* view_main_console = nullptr;
+static DView* view_main_disasm = nullptr;
+static DView* view_main_regs = nullptr;
+
+static void view_list_add(DView* item)
+{
+ view_list.push_back(item);
+}
+
+static void view_list_remove(DView* item)
+{
+ std::vector<DView*>::iterator it;
+ if(view_list.empty())
+ return;
+ it = std::find(view_list.begin(),view_list.end(),item);
+ view_list.erase(it);
+
+}
+
+static DView *dview_alloc(running_machine &machine, debug_view_type type, int flags)
+{
+ DView *dv;
+
+ dv = global_alloc(DView(machine, type, flags));
+
+ return dv;
+}
+
+static inline void map_attr_to_fg_bg(unsigned char attr, rgb_t *fg, rgb_t *bg)
+{
+ *bg = rgb_t(0xe6,0xff,0xff,0xff);
+ *fg = rgb_t(0xff,0x00,0x00,0x00);
+
+ if(attr & DCA_ANCILLARY)
+ *bg = rgb_t(0xe6,0xd0,0xd0,0xd0);
+ if(attr & DCA_SELECTED) {
+ *bg = rgb_t(0xe6,0xff,0x80,0x80);
+ }
+ if(attr & DCA_CURRENT) {
+ *bg = rgb_t(0xe6,0xff,0xff,0x00);
+ }
+ if(attr & DCA_CHANGED) {
+ *fg = rgb_t(0xff,0xff,0x00,0x00);
+ }
+ if(attr & DCA_INVALID) {
+ *fg = rgb_t(0xff,0x00,0x00,0xff);
+ }
+ if(attr & DCA_DISABLED) {
+ *fg = rgb_t(fg->a(), (fg->r() + bg->r()) >> 1, (fg->g() + bg->g()) >> 1, (fg->b() + bg->b()) >> 1);
+ }
+ if(attr & DCA_COMMENT) {
+ *fg = rgb_t(0xff,0x00,0x80,0x00);
+ }
+}
+
+void debug_imgui::handle_mouse()
+{
+ m_machine->ui_input().find_mouse(&m_mouse_x, &m_mouse_y, &m_mouse_button);
+}
+
+void debug_imgui::handle_keys()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ui_event event;
+
+ // global keys
+ if(m_machine->input().code_pressed_once(KEYCODE_F3))
+ {
+ if(m_machine->input().code_pressed(KEYCODE_LSHIFT))
+ m_machine->schedule_hard_reset();
+ else
+ {
+ m_machine->schedule_soft_reset();
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
+ }
+ }
+
+ if(m_machine->input().code_pressed_once(KEYCODE_F5))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
+ m_running = true;
+ }
+ if(m_machine->input().code_pressed_once(KEYCODE_F6))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device();
+ m_running = true;
+ }
+ if(m_machine->input().code_pressed_once(KEYCODE_F7))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt();
+ m_running = true;
+ }
+ if(m_machine->input().code_pressed_once(KEYCODE_F8))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank();
+ if(m_machine->input().code_pressed_once(KEYCODE_F9))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out();
+ if(m_machine->input().code_pressed_once(KEYCODE_F10))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over();
+ if(m_machine->input().code_pressed_once(KEYCODE_F11))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step();
+ if(m_machine->input().code_pressed_once(KEYCODE_F12))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
+ m_hide = true;
+ }
+
+/* if(m_machine->input().code_pressed_once(KEYCODE_UP))
+ io.KeysDown[ImGuiKey_UpArrow] = true;
+ if(m_machine->input().code_pressed_once(KEYCODE_DOWN))
+ io.KeysDown[ImGuiKey_DownArrow] = true;
+ if(m_machine->input().code_pressed_once(KEYCODE_LEFT))
+ io.KeysDown[ImGuiKey_LeftArrow] = true;
+ if(m_machine->input().code_pressed_once(KEYCODE_RIGHT))
+ io.KeysDown[ImGuiKey_RightArrow] = true;
+
+ if(m_machine->input().code_pressed(KEYCODE_TAB))
+ io.KeysDown[ImGuiKey_Tab] = true;
+
+ if(m_machine->input().code_pressed_once(KEYCODE_PGUP))
+ {
+ io.KeysDown[ImGuiKey_PageUp] = true;
+ }
+ if(m_machine->input().code_pressed_once(KEYCODE_PGDN))
+ {
+ io.KeysDown[ImGuiKey_PageDown] = true;
+ }
+
+ if(m_machine->input().code_pressed_once(KEYCODE_HOME))
+ {
+ io.KeysDown[ImGuiKey_Home] = true;
+ }
+ if(m_machine->input().code_pressed_once(KEYCODE_END))
+ {
+ io.KeysDown[ImGuiKey_End] = true;
+ }*/
+ if(m_machine->input().code_pressed(KEYCODE_LCONTROL))
+ io.KeyCtrl = true;
+ else
+ io.KeyCtrl = false;
+ if(m_machine->input().code_pressed(KEYCODE_LSHIFT))
+ io.KeyShift = true;
+ else
+ io.KeyShift = false;
+ if(m_machine->input().code_pressed(KEYCODE_LALT))
+ io.KeyAlt = true;
+ else
+ io.KeyAlt = false;
+
+ for(input_item_id id = ITEM_ID_A; id <= ITEM_ID_CANCEL; id++)
+ {
+ if(m_machine->input().code_pressed(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
+ io.KeysDown[id] = true;
+ else
+ io.KeysDown[id] = false;
+ }
+
+ m_key_char = 0;
+ while (m_machine->ui_input().pop_event(&event))
+ {
+ switch (event.event_type)
+ {
+ case UI_EVENT_CHAR:
+ m_key_char = event.ch;
+ return;
+ default:
+ break;
+ }
+ }
+
+ if(ImGui::IsKeyPressed(ITEM_ID_D) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ add_disasm(++m_win_count);
+ if(ImGui::IsKeyPressed(ITEM_ID_M) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ add_memory(++m_win_count);
+ if(ImGui::IsKeyPressed(ITEM_ID_B) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ add_bpoints(++m_win_count);
+ if(ImGui::IsKeyPressed(ITEM_ID_W) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ add_wpoints(++m_win_count);
+
+ m_machine->ui_input().reset(); // clear remaining inputs, so they don't fall through to the UI
+}
+
+void debug_imgui::handle_console(running_machine* machine)
+{
+ if(view_main_console->exec_cmd && view_main_console->type == DVT_CONSOLE)
+ {
+ if(strlen(view_main_console->console_input) > 0)
+ debug_console_execute_command(*m_machine, view_main_console->console_input, 1);
+ // check for commands that start execution (so that input fields can be disabled)
+ if(strcmp(view_main_console->console_input,"g") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"g ",2) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"go") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"go ",3) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"gi") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"gi ",3) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"gint") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"gint ",5) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"gt") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"gt ",3) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"gtime") == 0)
+ m_running = true;
+ if(strncmp(view_main_console->console_input,"gtime ",6) == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"n") == 0)
+ m_running = true;
+ if(strcmp(view_main_console->console_input,"next") == 0)
+ m_running = true;
+ strcpy(view_main_console->console_input,"");
+ view_main_console->exec_cmd = false;
+ }
+}
+
+void debug_imgui::update_cpu_view(device_t* device)
+{
+ const debug_view_source *source;
+ source = view_main_disasm->view->source_for_device(device);
+ view_main_disasm->view->set_source(*source);
+ source = view_main_regs->view->source_for_device(device);
+ view_main_regs->view->set_source(*source);
+}
+
+void debug_imgui::draw_bpoints(DView* view_ptr, bool* opened)
+{
+ ImGui::SetNextWindowSize(ImVec2(view_ptr->width,view_ptr->height + ImGui::GetTextLineHeight()),ImGuiSetCond_Once);
+ if(ImGui::Begin(view_ptr->title.c_str(),opened))
+ {
+ rgb_t bg, fg;
+ rgb_t base(0xe6, 0xff, 0xff, 0xff);
+ const debug_view_char *viewdata;
+ debug_view_xy vsize,totalsize;
+ unsigned char v;
+ int x,y;
+
+ viewdata = view_ptr->view->viewdata();
+ totalsize = view_ptr->view->total_size();
+ view_ptr->view->set_visible_size(totalsize);
+ vsize = view_ptr->view->visible_size();
+
+ ImGui::BeginChild("##break_output", ImVec2(ImGui::GetWindowWidth() - 16,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight() - ImGui::GetCursorPosY())); // account for title bar and widgets already drawn
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ ImVec2 xy1,xy2;
+ char str[2];
+ map_attr_to_fg_bg(viewdata->attrib,&fg,&bg);
+ str[0] = v = viewdata->byte;
+ str[1] = '\0';
+ if(bg != base)
+ {
+ ImU32 bg_col = ImGui::ColorConvertFloat4ToU32(ImVec4(bg.r()/255.0f,bg.g()/255.0f,bg.b()/255.0f,bg.a()/255.0f));
+ xy1.x = ImGui::GetCursorScreenPos().x + 1;
+ xy1.y = ImGui::GetCursorScreenPos().y;
+ xy2 = ImGui::CalcTextSize(str);
+ xy2.x += ImGui::GetCursorScreenPos().x + 1;
+ xy2.y += ImGui::GetCursorScreenPos().y;
+ ImGui::GetWindowDrawList()->AddRectFilled(xy1,xy2,bg_col);
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(fg.r()/255.0f,fg.g()/255.0f,fg.b()/255.0f,fg.a()/255.0f));
+ ImGui::Text("%c",v);
+ ImGui::PopStyleColor();
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+
+ ImGui::End();
+ }
+}
+
+void debug_imgui::add_bpoints(int id)
+{
+ std::stringstream str;
+ DView* new_view;
+ new_view = dview_alloc(*m_machine, DVT_BREAK_POINTS, 0);
+ str << id;
+ str << ": Breakpoints";
+ new_view->title = str.str();
+ new_view->width = 500;
+ new_view->height = 300;
+ new_view->ofs_x = 0;
+ new_view->ofs_y = 0;
+ view_list_add(new_view);
+}
+
+void debug_imgui::add_wpoints(int id)
+{
+ std::stringstream str;
+ DView* new_view;
+ new_view = dview_alloc(*m_machine, DVT_WATCH_POINTS, 0);
+ str << id;
+ str << ": Watchpoints";
+ new_view->title = str.str();
+ new_view->width = 500;
+ new_view->height = 300;
+ new_view->ofs_x = 0;
+ new_view->ofs_y = 0;
+ view_list_add(new_view);
+}
+
+void debug_imgui::draw_disasm(DView* view_ptr, bool* opened)
+{
+ std::string cpu_list = "";
+ const debug_view_source* src = view_ptr->view->first_source();
+
+ // build source CPU list
+ while(src != nullptr)
+ {
+ cpu_list += src->name();
+ cpu_list += '\0';
+ src = src->next();
+ }
+ cpu_list += '\0'; // end of list
+
+ ImGui::SetNextWindowSize(ImVec2(view_ptr->width,view_ptr->height + ImGui::GetTextLineHeight()),ImGuiSetCond_Once);
+ if(ImGui::Begin(view_ptr->title.c_str(),opened,ImGuiWindowFlags_MenuBar))
+ {
+ rgb_t bg, fg;
+ rgb_t base(0xe6, 0xff, 0xff, 0xff);
+ const debug_view_char *viewdata;
+ debug_view_xy vsize,totalsize;
+ unsigned char v;
+ int x,y,idx;
+ bool done = false;
+
+ if(ImGui::BeginMenuBar())
+ {
+ if(ImGui::BeginMenu("Options"))
+ {
+ debug_view_disasm* disasm = downcast<debug_view_disasm*>(view_ptr->view);
+ int rightcol = disasm->right_column();
+
+ if(ImGui::MenuItem("Raw opcodes",NULL,(rightcol == DASM_RIGHTCOL_RAW) ? true : false))
+ disasm->set_right_column(DASM_RIGHTCOL_RAW);
+ if(ImGui::MenuItem("Encrypted opcodes",NULL,(rightcol == DASM_RIGHTCOL_ENCRYPTED) ? true : false))
+ disasm->set_right_column(DASM_RIGHTCOL_ENCRYPTED);
+ if(ImGui::MenuItem("No opcodes",NULL,(rightcol == DASM_RIGHTCOL_NONE) ? true : false))
+ disasm->set_right_column(DASM_RIGHTCOL_NONE);
+ if(ImGui::MenuItem("Comments",NULL,(rightcol == DASM_RIGHTCOL_COMMENTS) ? true : false))
+ disasm->set_right_column(DASM_RIGHTCOL_COMMENTS);
+
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+
+ ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
+ if(m_running)
+ flags |= ImGuiInputTextFlags_ReadOnly;
+ ImGui::Combo("##cpu",&view_ptr->src_sel,cpu_list.c_str());
+ ImGui::SameLine();
+ ImGui::PushItemWidth(-1.0f);
+ if(ImGui::InputText("##addr",view_ptr->console_input,512,flags))
+ downcast<debug_view_disasm *>(view_ptr->view)->set_expression(view_ptr->console_input);
+ ImGui::PopItemWidth();
+ ImGui::Separator();
+
+ // disassembly portion
+ viewdata = view_ptr->view->viewdata();
+ totalsize = view_ptr->view->total_size();
+ totalsize.y = 50;
+ view_ptr->view->set_visible_size(totalsize);
+ vsize = view_ptr->view->visible_size();
+
+ ImGui::BeginChild("##disasm_output", ImVec2(ImGui::GetWindowWidth() - 16,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight() - ImGui::GetCursorPosY())); // account for title bar and widgets already drawn
+ src = view_ptr->view->first_source();
+ idx = 0;
+ while (!done)
+ {
+ if(view_ptr->src_sel == idx)
+ view_ptr->view->set_source(*src);
+ idx++;
+ src = src->next();
+ if(src == nullptr)
+ done = true;
+ }
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ ImVec2 xy1,xy2;
+ char str[2];
+ map_attr_to_fg_bg(viewdata->attrib,&fg,&bg);
+ str[0] = v = viewdata->byte;
+ str[1] = '\0';
+ if(bg != base)
+ {
+ ImU32 bg_col = ImGui::ColorConvertFloat4ToU32(ImVec4(bg.r()/255.0f,bg.g()/255.0f,bg.b()/255.0f,bg.a()/255.0f));
+ xy1.x = ImGui::GetCursorScreenPos().x + 1;
+ xy1.y = ImGui::GetCursorScreenPos().y;
+ xy2 = ImGui::CalcTextSize(str);
+ xy2.x += ImGui::GetCursorScreenPos().x + 1;
+ xy2.y += ImGui::GetCursorScreenPos().y;
+ ImGui::GetWindowDrawList()->AddRectFilled(xy1,xy2,bg_col);
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(fg.r()/255.0f,fg.g()/255.0f,fg.b()/255.0f,fg.a()/255.0f));
+ ImGui::Text("%c",v);
+ ImGui::PopStyleColor();
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+
+ ImGui::End();
+ }
+}
+
+void debug_imgui::add_disasm(int id)
+{
+ std::stringstream str;
+ DView* new_view;
+ new_view = dview_alloc(*m_machine, DVT_DISASSEMBLY, 0);
+ str << id;
+ str << ": Disassembly";
+ new_view->title = str.str();
+ new_view->width = 500;
+ new_view->height = 300;
+ new_view->ofs_x = 0;
+ new_view->ofs_y = 0;
+ new_view->src_sel = 0;
+ strcpy(new_view->console_input,"curpc");
+ view_list_add(new_view);
+}
+
+void debug_imgui::draw_memory(DView* view_ptr, bool* opened)
+{
+ std::string region_list = "";
+ const debug_view_source* src = view_ptr->view->first_source();
+
+ ImGui::SetNextWindowSize(ImVec2(view_ptr->width,view_ptr->height + ImGui::GetTextLineHeight()),ImGuiSetCond_Once);
+ if(ImGui::Begin(view_ptr->title.c_str(),opened,ImGuiWindowFlags_MenuBar))
+ {
+ rgb_t bg, fg;
+ rgb_t base(0xe6, 0xff, 0xff, 0xff);
+ const debug_view_char *viewdata;
+ debug_view_xy vsize,totalsize;
+ unsigned char v;
+ int x,y,idx;
+ bool done = false;
+
+ if(ImGui::BeginMenuBar())
+ {
+ if(ImGui::BeginMenu("Options"))
+ {
+ debug_view_memory* mem = downcast<debug_view_memory*>(view_ptr->view);
+ bool physical = mem->physical();
+ bool rev = mem->reverse();
+ int format = mem->get_data_format();
+ UINT32 chunks = mem->chunks_per_row();
+
+ if(ImGui::MenuItem("1-byte chunks",NULL,(format == 1) ? true : false))
+ mem->set_data_format(1);
+ if(ImGui::MenuItem("2-byte chunks",NULL,(format == 2) ? true : false))
+ mem->set_data_format(2);
+ if(ImGui::MenuItem("4-byte chunks",NULL,(format == 4) ? true : false))
+ mem->set_data_format(4);
+ if(ImGui::MenuItem("8-byte chunks",NULL,(format == 8) ? true : false))
+ mem->set_data_format(8);
+ if(ImGui::MenuItem("32-bit floating point",NULL,(format == 9) ? true : false))
+ mem->set_data_format(9);
+ if(ImGui::MenuItem("64-bit floating point",NULL,(format == 10) ? true : false))
+ mem->set_data_format(10);
+ if(ImGui::MenuItem("80-bit floating point",NULL,(format == 11) ? true : false))
+ mem->set_data_format(11);
+ ImGui::Separator();
+ if(ImGui::MenuItem("Logical addresses",NULL,!physical))
+ mem->set_physical(false);
+ if(ImGui::MenuItem("Physical addresses",NULL,physical))
+ mem->set_physical(true);
+ ImGui::Separator();
+ if(ImGui::MenuItem("Reverse view",NULL,rev))
+ mem->set_reverse(!rev);
+ ImGui::Separator();
+ if(ImGui::MenuItem("Increase bytes per line"))
+ mem->set_chunks_per_row(chunks+1);
+ if(ImGui::MenuItem("Decrease bytes per line"))
+ mem->set_chunks_per_row(chunks-1);
+
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+
+ ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
+ ImGui::PushItemWidth(100.0f);
+ if(m_running)
+ flags |= ImGuiInputTextFlags_ReadOnly;
+ // build source CPU list
+ while(src != nullptr)
+ {
+ region_list += src->name();
+ region_list += '\0';
+ src = src->next();
+ }
+ region_list += '\0'; // end of list
+ if(ImGui::InputText("##addr",view_ptr->console_input,512,flags))
+ downcast<debug_view_memory *>(view_ptr->view)->set_expression(view_ptr->console_input);
+ ImGui::PopItemWidth();
+ ImGui::SameLine();
+ ImGui::PushItemWidth(-1.0f);
+ ImGui::Combo("##region",&view_ptr->src_sel,region_list.c_str());
+ ImGui::PopItemWidth();
+ ImGui::Separator();
+
+ // memory editor portion
+ viewdata = view_ptr->view->viewdata();
+ totalsize = view_ptr->view->total_size();
+ if(totalsize.y > 256)
+ totalsize.y = 256;
+ view_ptr->view->set_visible_size(totalsize);
+ vsize = view_ptr->view->visible_size();
+
+ ImGui::BeginChild("##memory_output", ImVec2(ImGui::GetWindowWidth() - 16,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight() - ImGui::GetCursorPosY())); // account for title bar and widgets already drawn
+ src = view_ptr->view->first_source();
+ idx = 0;
+ while (!done)
+ {
+ if(view_ptr->src_sel == idx)
+ view_ptr->view->set_source(*src);
+ idx++;
+ src = src->next();
+ if(src == nullptr)
+ done = true;
+ }
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ ImVec2 xy1,xy2;
+ char str[2];
+ map_attr_to_fg_bg(viewdata->attrib,&fg,&bg);
+ str[0] = v = viewdata->byte;
+ str[1] = '\0';
+ if(bg != base)
+ {
+ ImU32 bg_col = ImGui::ColorConvertFloat4ToU32(ImVec4(bg.r()/255.0f,bg.g()/255.0f,bg.b()/255.0f,bg.a()/255.0f));
+ xy1.x = ImGui::GetCursorScreenPos().x + 1;
+ xy1.y = ImGui::GetCursorScreenPos().y;
+ xy2 = ImGui::CalcTextSize(str);
+ xy2.x += ImGui::GetCursorScreenPos().x + 1;
+ xy2.y += ImGui::GetCursorScreenPos().y;
+ ImGui::GetWindowDrawList()->AddRectFilled(xy1,xy2,bg_col);
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(fg.r()/255.0f,fg.g()/255.0f,fg.b()/255.0f,fg.a()/255.0f));
+ ImGui::Text("%c",v);
+ ImGui::PopStyleColor();
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+
+ ImGui::End();
+ }
+}
+
+void debug_imgui::add_memory(int id)
+{
+ std::stringstream str;
+ DView* new_view;
+ new_view = dview_alloc(*m_machine, DVT_MEMORY, 0);
+ str << id;
+ str << ": Memory";
+ new_view->title = str.str();
+ new_view->width = 500;
+ new_view->height = 300;
+ new_view->ofs_x = 0;
+ new_view->ofs_y = 0;
+ new_view->src_sel = 0;
+ strcpy(new_view->console_input,"0");
+ view_list_add(new_view);
+}
+
+void debug_imgui::draw_console()
+{
+ rgb_t bg, fg;
+ rgb_t base(0xe6, 0xff, 0xff, 0xff);
+ ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
+
+ ImGui::SetNextWindowSize(ImVec2(view_main_regs->width + view_main_disasm->width,view_main_disasm->height + view_main_console->height + ImGui::GetTextLineHeight()*3),ImGuiSetCond_Once);
+ if(ImGui::Begin(view_main_console->title.c_str(),NULL,flags))
+ {
+ const debug_view_char *viewdata;
+ debug_view_xy vsize,totalsize;
+ unsigned char v;
+ int x,y;
+
+ if(ImGui::BeginMenuBar())
+ {
+ if(ImGui::BeginMenu("Debug"))
+ {
+ if(ImGui::MenuItem("New disassembly window", "Ctrl+D"))
+ add_disasm(++m_win_count);
+ if(ImGui::MenuItem("New memory window", "Ctrl+M"))
+ add_memory(++m_win_count);
+ if(ImGui::MenuItem("New breakpoints window", "Ctrl+B"))
+ add_bpoints(++m_win_count);
+ if(ImGui::MenuItem("New watchpoints window", "Ctrl+W"))
+ add_wpoints(++m_win_count);
+ ImGui::Separator();
+ if(ImGui::MenuItem("Run", "F5"))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
+ m_running = true;
+ }
+ if(ImGui::MenuItem("Go to next CPU", "F6"))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device();
+ m_running = true;
+ }
+ if(ImGui::MenuItem("Run until next interrupt", "F7"))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt();
+ m_running = true;
+ }
+ if(ImGui::MenuItem("Run until VBLANK", "F8"))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank();
+ if(ImGui::MenuItem("Run and hide debugger", "F12"))
+ {
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
+ m_hide = true;
+ }
+ ImGui::Separator();
+ if(ImGui::MenuItem("Single step", "F11"))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step();
+ if(ImGui::MenuItem("Step over", "F10"))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over();
+ if(ImGui::MenuItem("Step out", "F9"))
+ debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out();
+
+ ImGui::EndMenu();
+ }
+ if(ImGui::BeginMenu("Window"))
+ {
+ if(ImGui::MenuItem("Show all"))
+ {
+ for(std::vector<DView*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ ImGui::SetWindowCollapsed((*view_ptr)->title.c_str(),false);
+ }
+ ImGui::Separator();
+ // list all extra windows, so we can un-collapse the windows if necessary
+ //DView* view_ptr;
+ for(std::vector<DView*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ {
+ bool collapsed;
+ if(ImGui::Begin((*view_ptr)->title.c_str()))
+ {
+ collapsed = false;
+ ImGui::End();
+ }
+ else
+ {
+ collapsed = true;
+ ImGui::End();
+ }
+ if(ImGui::MenuItem((*view_ptr)->title.c_str(),NULL,!collapsed))
+ ImGui::SetWindowCollapsed((*view_ptr)->title.c_str(),false);
+ }
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+
+ // CPU state portion
+ viewdata = view_main_regs->view->viewdata();
+ totalsize = view_main_regs->view->total_size();
+ view_main_regs->view->set_visible_size(totalsize);
+ vsize = view_main_regs->view->visible_size();
+
+ ImGui::BeginChild("##state_output", ImVec2(180,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight()*2)); // account for title bar and menu
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ map_attr_to_fg_bg(viewdata->attrib,&fg,&bg);
+ v = viewdata->byte;
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(fg.r()/255.0f,fg.g()/255.0f,fg.b()/255.0f,fg.a()/255.0f));
+ ImGui::Text("%c",v);
+ ImGui::PopStyleColor();
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+
+ ImGui::BeginChild("##right_side", ImVec2(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - 8,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight()*2));
+ // disassembly portion
+ viewdata = view_main_disasm->view->viewdata();
+ totalsize = view_main_disasm->view->total_size();
+ totalsize.y = 20;
+ view_main_disasm->view->set_visible_size(totalsize);
+// height = ImGui::GetTextLineHeight();
+ vsize = view_main_disasm->view->visible_size();
+
+ ImGui::BeginChild("##disasm_output", ImVec2(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - 8,(ImGui::GetWindowHeight() - ImGui::GetTextLineHeight()*4)/2));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ ImVec2 xy1,xy2;
+ char str[2];
+ map_attr_to_fg_bg(viewdata->attrib,&fg,&bg);
+ str[0] = v = viewdata->byte;
+ str[1] = '\0';
+ if(bg != base)
+ {
+ ImU32 bg_col = ImGui::ColorConvertFloat4ToU32(ImVec4(bg.r()/255.0f,bg.g()/255.0f,bg.b()/255.0f,bg.a()/255.0f));
+ xy1.x = ImGui::GetCursorScreenPos().x + 1;
+ xy1.y = ImGui::GetCursorScreenPos().y;
+ xy2 = ImGui::CalcTextSize(str);
+ xy2.x += ImGui::GetCursorScreenPos().x + 1;
+ xy2.y += ImGui::GetCursorScreenPos().y;
+ ImGui::GetWindowDrawList()->AddRectFilled(xy1,xy2,bg_col);
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(fg.r()/255.0f,fg.g()/255.0f,fg.b()/255.0f,fg.a()/255.0f));
+ ImGui::Text("%c",v);
+ ImGui::PopStyleColor();
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+
+ ImGui::Separator();
+
+ // console portion
+ viewdata = view_main_console->view->viewdata();
+ totalsize = view_main_console->view->total_size();
+ view_main_console->view->set_visible_size(totalsize);
+// height = ImGui::GetTextLineHeight();
+ vsize = view_main_console->view->visible_size();
+
+ ImGui::BeginChild("##console_output", ImVec2(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - 8,(ImGui::GetWindowHeight() - ImGui::GetTextLineHeight()*4)/2 - ImGui::GetTextLineHeight()));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
+ for(y=0;y<vsize.y;y++)
+ {
+ for(x=0;x<vsize.x;x++)
+ {
+ v = viewdata->byte;
+ ImGui::Text("%c",v);
+ if(x<vsize.x - 1)
+ ImGui::SameLine();
+ viewdata++;
+ }
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::EndChild();
+ ImGui::Separator();
+ //if(ImGui::IsWindowFocused())
+ // ImGui::SetKeyboardFocusHere();
+ ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
+ if(m_running)
+ flags |= ImGuiInputTextFlags_ReadOnly;
+ ImGui::PushItemWidth(-1.0f);
+ if(ImGui::InputText("##console_input",view_main_console->console_input,512,flags))
+ view_main_console->exec_cmd = true;
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
+ ImGui::End();
+ }
+}
+
+void debug_imgui::update()
+{
+ DView* to_delete = nullptr;
+ //DView* view_ptr = view_list;
+ std::vector<DView*>::iterator view_ptr;
+ bool opened;
+ int count = 0;
+ ImGui::PushStyleColor(ImGuiCol_WindowBg,ImVec4(1.0f,1.0f,1.0f,0.9f));
+ ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(0.0f,0.0f,0.0f,1.0f));
+ ImGui::PushStyleColor(ImGuiCol_TextDisabled,ImVec4(0.0f,0.0f,1.0f,1.0f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBg,ImVec4(0.5f,0.5f,0.5f,0.9f));
+ ImGui::PushStyleColor(ImGuiCol_PopupBg,ImVec4(0.8f,0.8f,0.8f,0.9f));
+ ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab,ImVec4(0.6f,0.6f,0.6f,0.9f));
+ ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered,ImVec4(0.7f,0.7f,0.7f,0.9f));
+ ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive,ImVec4(0.9f,0.9f,0.9f,0.9f));
+
+ draw_console(); // We'll always have a console window
+
+ view_ptr = view_list.begin();
+ while(view_ptr != view_list.end())
+ {
+ opened = true;
+ switch((*view_ptr)->type)
+ {
+ case DVT_DISASSEMBLY:
+ draw_disasm((*view_ptr),&opened);
+ if(opened == false)
+ to_delete = (*view_ptr);
+ break;
+ case DVT_MEMORY:
+ draw_memory((*view_ptr),&opened);
+ if(opened == false)
+ to_delete = (*view_ptr);
+ break;
+ case DVT_BREAK_POINTS:
+ case DVT_WATCH_POINTS: // watchpoints window uses same drawing code as breakpoints window
+ draw_bpoints((*view_ptr),&opened);
+ if(opened == false)
+ to_delete = (*view_ptr);
+ break;
+ }
+ view_ptr++;
+ count++;
+ }
+ // check for a closed window
+ if(to_delete != nullptr)
+ {
+ view_list_remove(to_delete);
+ global_free(to_delete);
+ }
+ ImGui::PopStyleColor(8);
+}
+
+void debug_imgui::init_debugger(running_machine &machine)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ m_machine = &machine;
+ if(strcmp(downcast<osd_options &>(m_machine->options()).video(),"bgfx") != 0)
+ fatalerror("Error: ImGui debugger requires the BGFX renderer.\n");
+
+ io.KeyMap[ImGuiKey_A] = ITEM_ID_A;
+ io.KeyMap[ImGuiKey_C] = ITEM_ID_C;
+ io.KeyMap[ImGuiKey_V] = ITEM_ID_V;
+ io.KeyMap[ImGuiKey_X] = ITEM_ID_X;
+ io.KeyMap[ImGuiKey_C] = ITEM_ID_C;
+ io.KeyMap[ImGuiKey_Y] = ITEM_ID_Y;
+ io.KeyMap[ImGuiKey_Z] = ITEM_ID_Z;
+ io.KeyMap[ImGuiKey_Backspace] = ITEM_ID_BACKSPACE;
+ io.KeyMap[ImGuiKey_Delete] = ITEM_ID_DEL;
+ io.KeyMap[ImGuiKey_Tab] = ITEM_ID_TAB;
+ io.KeyMap[ImGuiKey_PageUp] = ITEM_ID_PGUP;
+ io.KeyMap[ImGuiKey_PageDown] = ITEM_ID_PGDN;
+ io.KeyMap[ImGuiKey_Home] = ITEM_ID_HOME;
+ io.KeyMap[ImGuiKey_End] = ITEM_ID_END;
+ io.KeyMap[ImGuiKey_Escape] = ITEM_ID_ESC;
+ io.KeyMap[ImGuiKey_Enter] = ITEM_ID_ENTER;
+
+ font_name = (downcast<osd_options &>(m_machine->options()).debugger_font());
+ font_size = (downcast<osd_options &>(m_machine->options()).debugger_font_size());
+
+ if(font_size == 0)
+ font_size = 12;
+
+ io.Fonts->Clear();
+ if(!strcmp(font_name, OSDOPTVAL_AUTO))
+ io.Fonts->AddFontDefault();
+ else
+ io.Fonts->AddFontFromFileTTF(font_name,font_size); // for now, font name must be a path to a TTF file
+ m_font = imguiCreate();
+ imguiSetFont(m_font);
+}
+
+void debug_imgui::wait_for_debugger(device_t &device, bool firststop)
+{
+ UINT32 width = m_machine->render().ui_target().width();
+ UINT32 height = m_machine->render().ui_target().height();
+ if(firststop && view_list.empty())
+ {
+ view_main_console = dview_alloc(device.machine(), DVT_CONSOLE, VIEW_STATE_FOLLOW_CPU);
+ view_main_console->title = "MAME Debugger";
+ view_main_console->width = 500;
+ view_main_console->height = 200;
+ view_main_console->ofs_x = 0;
+ view_main_console->ofs_y = 0;
+ view_main_disasm = dview_alloc(device.machine(), DVT_DISASSEMBLY, VIEW_STATE_FOLLOW_CPU);
+ view_main_disasm->width = 500;
+ view_main_disasm->height = 200;
+ view_main_regs = dview_alloc(device.machine(), DVT_STATE, VIEW_STATE_FOLLOW_CPU);
+ view_main_regs->width = 180;
+ view_main_regs->height = 440;
+ strcpy(view_main_console->console_input,""); // clear console input
+ }
+ if(firststop)
+ {
+// debug_show_all();
+ device.machine().ui_input().reset();
+ m_running = false;
+ }
+ m_hide = false;
+// m_machine->ui_input().frame_update();
+ handle_mouse();
+ handle_keys();
+ handle_console(m_machine);
+ update_cpu_view(&device);
+ imguiBeginFrame(m_mouse_x,m_mouse_y,m_mouse_button ? IMGUI_MBUT_LEFT : 0, 0, width, height,m_key_char);
+ update();
+ imguiEndFrame();
+ device.machine().osd().update(false);
+}
+
+
+void debug_imgui::debugger_update()
+{
+ if ((m_machine != nullptr) && (!debug_cpu_is_stopped(*m_machine)) && (m_machine->phase() == MACHINE_PHASE_RUNNING) && !m_hide)
+ {
+ UINT32 width = m_machine->render().ui_target().width();
+ UINT32 height = m_machine->render().ui_target().height();
+ handle_mouse();
+ handle_keys();
+ imguiBeginFrame(m_mouse_x,m_mouse_y,m_mouse_button ? IMGUI_MBUT_LEFT : 0, 0, width, height, m_key_char);
+ update();
+ imguiEndFrame();
+ }
+}
+
+MODULE_DEFINITION(DEBUG_IMGUI, debug_imgui)