/********************************************************************* debugint.c Internal debugger frontend using render interface. Copyright Nicola Salmoria and the MAME Team. Visit http://mamedev.org for licensing and usage restrictions. *********************************************************************/ #include "emu.h" #include "ui.h" #include "rendfont.h" #include "uiinput.h" #include "osdepend.h" #include "debug/debugvw.h" #include "debug/dvdisasm.h" #include "debug/dvmemory.h" #include "debug/dvstate.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" /*************************************************************************** CONSTANTS ***************************************************************************/ #define BORDER_YTHICKNESS 1 #define BORDER_XTHICKNESS 1 #define HSB_HEIGHT 20 #define VSB_WIDTH 20 #define TITLE_HEIGHT 20 enum { RECT_DVIEW, RECT_DVIEW_CLIENT, RECT_DVIEW_TITLE, RECT_DVIEW_HSB, RECT_DVIEW_VSB, RECT_DVIEW_SIZE, }; enum { VIEW_STATE_BUTTON = 0x01, VIEW_STATE_MOVING = 0x02, VIEW_STATE_SIZING = 0x04, VIEW_STATE_NEEDS_UPDATE = 0x08, VIEW_STATE_FOLLOW_CPU = 0x10, }; /*************************************************************************** MACROS ***************************************************************************/ //#define NX(_dv, _x) ((float) (_x)/(float)(_dv)->bounds.width()) //#define NY(_dv, _y) ((float) (_y)/(float)(_dv)->bounds.height()) #define NX(_dv, _x) ((float) (_x)/(float) (dv)->rt_width) #define NY(_dv, _y) ((float) (_y)/(float) (dv)->rt_height) #define LIST_ADD_FRONT(_list, _elem, _type) \ do { \ (_elem)->next = _list; \ _list = _elem; \ } while (0) #define LIST_GET_PREVIOUS(_list, _elem, _prev) \ do { \ _prev = NULL; \ if (_list != _elem) \ for (_prev = _list; _prev != NULL; _prev = _prev->next) \ if ((_prev)->next == _elem) \ break; \ } while (0) #define LIST_GET_LAST(_list, _last) \ do { \ for (_last = _list; _last != NULL; _last = _last->next) \ if ((_last)->next == NULL) \ break; \ } while (0) #define LIST_REMOVE(_list, _elem, _type) \ do { \ _type *_hlp; \ LIST_GET_PREVIOUS(_list, _elem, _hlp); \ if (_hlp != NULL) \ (_hlp)->next = (_elem)->next; \ else \ _list = (_elem)->next; \ } while (0) #define LIST_ADD_BACK(_list, _elem, _type) \ do { \ _type *_hlp; \ LIST_GET_LAST(_list, _hlp); \ if (_hlp != NULL) \ (_hlp)->next = _elem; \ else \ _list = _elem; \ } while (0) /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ typedef struct _adjustment adjustment; struct _adjustment { int visible; int lower; int upper; int value; int step_increment; int page_increment; int page_size; }; class DView; class DView_edit { DISABLE_COPYING(DView_edit); public: DView_edit() { } ~DView_edit() { } int active; render_container * container; astring str; }; /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ static void dview_update(debug_view &dw, void *osdprivate); static int map_point(DView *dv, INT32 target_x, INT32 target_y, INT32 *mapped_x, INT32 *mapped_y); class DView { DISABLE_COPYING(DView); public: DView(render_target *target, running_machine &machine, debug_view_type type, int flags) : next(NULL), type(0), state(0), ofs_x(0), ofs_y(0) { this->target = target; //dv->container = render_target_get_component_container(target, name, &pos); this->container = target->debug_alloc(); this->view = machine.debug_view().alloc_view(type, dview_update, this); this->type = type; this->m_machine = &machine; this->state = flags | VIEW_STATE_NEEDS_UPDATE; // initial size this->bounds.set(0, 300, 0, 300); /* specials */ switch (type) { case DVT_DISASSEMBLY: /* set up disasm view */ downcast(this->view)->set_expression("curpc"); //debug_view_ property_UINT32(dv->view, DVP_DASM_TRACK_LIVE, 1); break; default: break; } } ~DView() { this->target->debug_free(*this->container); machine().debug_view().free_view(*this->view); } running_machine &machine() const { assert(m_machine != NULL); return *m_machine; } DView * next; int type; debug_view * view; render_container * container; render_target * target; running_machine * m_machine; int state; // drawing rectangle bounds; int ofs_x; int ofs_y; astring title; int last_x; int last_y; // Scrollbars adjustment hsb; adjustment vsb; // render target tracking INT32 rt_width; INT32 rt_height; //optional DView_edit editor; }; /*************************************************************************** INLINE FUNCTIONS ***************************************************************************/ INLINE int dview_is_state(DView *dv, int state) { return ((dv->state & state) ? TRUE : FALSE); } INLINE int dview_is_state_all(DView *dv, int state) { return ((dv->state & state) == state ? TRUE : FALSE); } INLINE void dview_set_state(DView *dv, int state, int onoff) { if (onoff) dv->state |= state; else dv->state &= ~state; } /*************************************************************************** LOCAL VARIABLES ***************************************************************************/ static render_font * debug_font; static int debug_font_width; static int debug_font_height; static float debug_font_aspect; static DView * list; static DView * focus_view; static ui_menu * menu; static DView_edit * cur_editor; static void set_focus_view(DView *dv) { if (focus_view != NULL) dview_set_state(focus_view, VIEW_STATE_NEEDS_UPDATE, TRUE); if (dv != NULL) dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); if (focus_view != dv) { focus_view = dv; LIST_REMOVE(list, dv, DView); LIST_ADD_FRONT(list, dv, DView); dv->target->debug_top(*dv->container); } } static DView *dview_alloc(render_target *target, running_machine &machine, debug_view_type type, int flags) { DView *dv; dv = auto_alloc(machine, DView(target, machine, type, flags)); /* add to list */ LIST_ADD_BACK(list, dv, DView); return dv; } static void dview_free(DView *dv) { LIST_REMOVE(list, dv, DView); auto_free(dv->machine(), dv); } static void dview_get_rect(DView *dv, int type, rectangle &rect) { rect = dv->bounds; switch (type) { case RECT_DVIEW: break; case RECT_DVIEW_CLIENT: rect.min_x += BORDER_XTHICKNESS; rect.max_x -= (BORDER_XTHICKNESS + dv->vsb.visible * VSB_WIDTH); rect.min_y += 2 * BORDER_YTHICKNESS + TITLE_HEIGHT; rect.max_y -= (BORDER_YTHICKNESS + dv->hsb.visible * HSB_HEIGHT); break; case RECT_DVIEW_HSB: rect.min_x += 0; rect.max_x -= /* dv->vsb.visible * */ VSB_WIDTH; rect.min_y = dv->bounds.max_y - HSB_HEIGHT; rect.max_y -= 0; break; case RECT_DVIEW_VSB: rect.min_x = dv->bounds.max_x - VSB_WIDTH; rect.max_x -= 0; rect.min_y += TITLE_HEIGHT; rect.max_y -= /* dv->hsb.visible * */ HSB_HEIGHT; break; case RECT_DVIEW_SIZE: rect.min_x = dv->bounds.max_x - VSB_WIDTH; rect.max_x -= 0; rect.min_y = dv->bounds.max_y - HSB_HEIGHT; rect.max_y -= 0; break; case RECT_DVIEW_TITLE: rect.min_x += 0; rect.max_x -= 0; rect.min_y += 0; rect.max_y = rect.min_y + TITLE_HEIGHT - 1; break; default: assert_always(FALSE, "unknown rectangle type"); } } static void dview_clear(DView *dv) { dv->container->empty(); } static void dview_draw_outlined_box(DView *dv, int rtype, int x, int y, int w, int h, rgb_t bg) { rectangle r; dview_get_rect(dv, rtype, r); ui_draw_outlined_box(dv->container, NX(dv, x + r.min_x), NY(dv, y + r.min_y), NX(dv, x + r.min_x + w), NY(dv, y + r.min_y + h), bg); } static void dview_draw_box(DView *dv, int rtype, int x, int y, int w, int h, rgb_t col) { rectangle r; dview_get_rect(dv, rtype, r); dv->container->add_rect(NX(dv, x + r.min_x), NY(dv, y + r.min_y), NX(dv, x + r.min_x + w), NY(dv, y + r.min_y + h), col, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); } static void dview_draw_char(DView *dv, int rtype, int x, int y, int h, rgb_t col, UINT16 ch) { rectangle r; dview_get_rect(dv, rtype, r); dv->container->add_char( NX(dv, x + r.min_x), NY(dv, y + r.min_y), NY(dv, h), debug_font_aspect, //(float) dv->bounds.height() / (float) dv->bounds->width(), //render_get_ui_aspect(), col, *debug_font, ch); } static int dview_xy_in_rect(DView *dv, int type, int x, int y) { rectangle r; dview_get_rect(dv, type, r); if (r.contains(x, y)) return TRUE; return FALSE; } static void dview_draw_hsb(DView *dv) { int vt; int ts; //int sz = SLIDER_SIZE; int sz; rectangle r; adjustment *sb = &dv->hsb; dview_get_rect(dv, RECT_DVIEW_HSB, r); dview_draw_outlined_box(dv, RECT_DVIEW_HSB, 0, 0, VSB_WIDTH,HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); dview_draw_outlined_box(dv, RECT_DVIEW_HSB, r.width() - VSB_WIDTH, 0, VSB_WIDTH, HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); ts = (r.width()) - 2 * VSB_WIDTH; sz = (ts * (sb->page_size)) / (sb->upper - sb->lower); ts = ts - sz; vt = (ts * (sb->value - sb->lower)) / (sb->upper - sb->lower - sb->page_size) + sz / 2 + r.min_x + VSB_WIDTH; dview_draw_outlined_box(dv, RECT_DVIEW_HSB, vt - sz / 2, 0, sz, HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); } static void dview_draw_vsb(DView *dv) { int vt; int ts; //int sz = SLIDER_SIZE; int sz; rectangle r; adjustment *sb = &dv->vsb; dview_get_rect(dv, RECT_DVIEW_VSB, r); dview_draw_outlined_box(dv, RECT_DVIEW_VSB, 0, r.height() - HSB_HEIGHT, VSB_WIDTH, HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); dview_draw_outlined_box(dv, RECT_DVIEW_VSB, 0, 0, VSB_WIDTH, HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); ts = r.height() - 2 * HSB_HEIGHT; sz = (ts * (sb->page_size)) / (sb->upper - sb->lower); ts = ts - sz; vt = (ts * (sb->value - sb->lower)) / (sb->upper - sb->lower - sb->page_size) + sz / 2 + HSB_HEIGHT; dview_draw_outlined_box(dv, RECT_DVIEW_VSB, 0, vt - sz / 2, VSB_WIDTH, sz, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); } static void dview_draw_size(DView *dv) { rectangle r; dview_get_rect(dv, RECT_DVIEW_SIZE, r); dview_draw_outlined_box(dv, RECT_DVIEW_SIZE, 0, 0, r.width(),r.height(), MAKE_ARGB(0xff, 0xff, 0xff, 0x00)); } static void dview_set_title(DView *dv, astring title) { if (dv->title.cmp(title) != 0) { dv->title = title; dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); } } static void dview_draw_title(DView *dv) { int i; rgb_t col = MAKE_ARGB(0xff,0x00,0x00,0xff); rectangle r; dview_get_rect(dv, RECT_DVIEW_TITLE, r); if (dv == focus_view) col = MAKE_ARGB(0xff,0x00,0x7f,0x00); dview_draw_outlined_box(dv, RECT_DVIEW_TITLE, 0, 0, dv->bounds.width(), TITLE_HEIGHT, col); if (!dv->title) return; for (i=0; ititle); i++) { dview_draw_char(dv, RECT_DVIEW_TITLE, i * debug_font_width + BORDER_XTHICKNESS, BORDER_YTHICKNESS, debug_font_height, //r.max_y - 2 * BORDER_YTHICKNESS, MAKE_ARGB(0xff,0xff,0xff,0xff), (UINT16) dv->title[i] ); } } static int dview_on_mouse(DView *dv, int mx, int my, int button) { int clicked = (button && !dview_is_state(dv, VIEW_STATE_BUTTON)); int handled = TRUE; int x,y; if (button && dview_is_state_all(dv, VIEW_STATE_BUTTON | VIEW_STATE_MOVING)) { int dx = mx - dv->last_x; int dy = my - dv->last_y; dv->ofs_x += dx; dv->ofs_y += dy; dv->last_x = mx; dv->last_y = my; dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); return TRUE; } else if (button && dview_is_state_all(dv, VIEW_STATE_BUTTON | VIEW_STATE_SIZING)) { int dx = mx - dv->last_x; int dy = my - dv->last_y; dv->bounds.max_x += dx; dv->bounds.max_y += dy; dv->last_x = mx; dv->last_y = my; dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); return TRUE; } else dview_set_state(dv, VIEW_STATE_MOVING | VIEW_STATE_SIZING, FALSE); if (!map_point(dv, mx, my, &x, &y)) return FALSE; if (dview_xy_in_rect(dv, RECT_DVIEW_TITLE, x, y)) { /* on title, do nothing */ if (clicked) { dv->last_x = mx; dv->last_y = my; set_focus_view(dv); dview_set_state(dv, VIEW_STATE_MOVING, TRUE); } } else if (dview_xy_in_rect(dv, RECT_DVIEW_HSB, x, y)) { /* on horizontal scrollbar */ debug_view_xy pos; adjustment *sb = &dv->hsb; if (clicked) { rectangle r; int xt; dview_get_rect(dv, RECT_DVIEW_HSB, r); x -= r.min_x; xt = (x - VSB_WIDTH) * (sb->upper - sb->lower) / (r.width() - 2 * dv->vsb.visible * VSB_WIDTH) + sb->lower; if (x < VSB_WIDTH) sb->value -= sb->step_increment; else if (x > r.width() - VSB_WIDTH) sb->value += sb->step_increment; else if (xt < sb->value) sb->value -= sb->page_increment; else if (xt > sb->value) sb->value += sb->page_increment; if (sb->value < sb->lower) sb->value = sb->lower; if (sb->value > sb->upper) sb->value = sb->upper; } pos = dv->view->visible_position(); if (sb->value != pos.x) { pos.x = sb->value; dv->view->set_visible_position(pos); dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); } } else if (dview_xy_in_rect(dv, RECT_DVIEW_VSB, x, y) ) { /* on vertical scrollbar */ debug_view_xy pos; adjustment *sb = &dv->vsb; if (clicked) { rectangle r; int yt; dview_get_rect(dv, RECT_DVIEW_VSB, r); y -= r.min_y; yt = (y - HSB_HEIGHT) * (sb->upper - sb->lower) / (r.height() - 2 * HSB_HEIGHT) + sb->lower; if (y < HSB_HEIGHT) sb->value -= sb->step_increment; else if (y > r.height() - HSB_HEIGHT) sb->value += sb->step_increment; else if (yt < sb->value) sb->value -= sb->page_increment; else if (yt > sb->value) sb->value += sb->page_increment; if (sb->value < sb->lower) sb->value = sb->lower; if (sb->value > sb->upper) sb->value = sb->upper; } pos = dv->view->visible_position(); if (sb->value != pos.y) { pos.y = sb->value; dv->view->set_visible_position(pos); dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); } } else if (dview_xy_in_rect(dv, RECT_DVIEW_SIZE, x, y)) { /* on sizing area */ if (clicked) { dv->last_x = mx; dv->last_y = my; set_focus_view(dv); dview_set_state(dv, VIEW_STATE_SIZING, TRUE); } } else if (dview_xy_in_rect(dv, RECT_DVIEW_CLIENT, x, y)) { y -= TITLE_HEIGHT; if (dv->view->cursor_supported() && clicked && y >= 0) { debug_view_xy topleft = dv->view->visible_position(); debug_view_xy newpos; newpos.x = topleft.x + x / debug_font_width; newpos.y = topleft.y + y / debug_font_height; dv->view->set_cursor_position(newpos); dv->view->set_cursor_visible(true); } if (clicked) set_focus_view(dv); } else { handled = FALSE; } dview_set_state(dv, VIEW_STATE_BUTTON, button); return handled; } INLINE void map_attr_to_fg_bg(unsigned char attr, rgb_t *fg, rgb_t *bg) { *bg = MAKE_ARGB(0xff,0xff,0xff,0xff); *fg = MAKE_ARGB(0xff,0x00,0x00,0x00); if(attr & DCA_ANCILLARY) *bg = MAKE_ARGB(0xff,0xe0,0xe0,0xe0); if(attr & DCA_SELECTED) { *bg = MAKE_ARGB(0xff,0xff,0x80,0x80); } if(attr & DCA_CURRENT) { *bg = MAKE_ARGB(0xff,0xff,0xff,0x00); } if(attr & DCA_CHANGED) { *fg = MAKE_ARGB(0xff,0xff,0x00,0x00); } if(attr & DCA_INVALID) { *fg = MAKE_ARGB(0xff,0x00,0x00,0xff); } if(attr & DCA_DISABLED) { *fg = MAKE_ARGB(RGB_ALPHA(*fg), (RGB_RED(*fg)+RGB_RED(*bg)) >> 1, (RGB_GREEN(*fg)+RGB_GREEN(*bg)) >> 1, (RGB_BLUE(*fg)+RGB_BLUE(*bg)) >> 1); } if(attr & DCA_COMMENT) { *fg = MAKE_ARGB(0xff,0x00,0x80,0x00); } } static void dview_draw(DView *dv) { const debug_view_char *viewdata; debug_view_xy vsize; UINT32 i, j, xx, yy; rgb_t bg_base, bg, fg; rectangle r; vsize = dv->view->visible_size(); bg_base = MAKE_ARGB(0xff,0xff,0xff,0xff); /* always start clean */ dview_clear(dv); dview_draw_title(dv); dview_get_rect(dv, RECT_DVIEW_CLIENT, r); dview_draw_outlined_box(dv, RECT_DVIEW_CLIENT, 0, 0, r.width() /*- (dv->vs ? VSB_WIDTH : 0)*/, r.height() /*- (dv->hsb.visible ? HSB_HEIGHT : 0)*/, bg_base); /* background first */ viewdata = dv->view->viewdata(); yy = BORDER_YTHICKNESS; for(j=0; jattrib, &fg, &bg); if (bg != bg_base) dview_draw_box(dv, RECT_DVIEW_CLIENT, xx, yy, debug_font_width, debug_font_height, bg); xx += debug_font_width; viewdata++; } yy += debug_font_height; } /* now the text */ viewdata = dv->view->viewdata(); yy = BORDER_YTHICKNESS; for(j=0; jbyte; if (v != ' ') { if(v < 128) { s = v; } else { s = 0xc0 | (v>>6); s |= (0x80 | (v & 0x3f)); } map_attr_to_fg_bg(viewdata->attrib, &fg, &bg); dview_draw_char(dv, RECT_DVIEW_CLIENT, xx, yy, debug_font_height, fg, s); } xx += debug_font_width; viewdata++; } yy += debug_font_height; } if(dv->hsb.visible) dview_draw_hsb(dv); if(dv->vsb.visible) dview_draw_vsb(dv); dview_draw_size(dv); } static void dview_size_allocate(DView *dv) { debug_view_xy size, pos, col, vsize; render_container::user_settings rcus; rectangle r; dv->container->get_user_settings(rcus); rcus.m_xoffset = (float) dv->ofs_x / (float) dv->rt_width; rcus.m_yoffset = (float) dv->ofs_y / (float) dv->rt_height; rcus.m_xscale = 1.0; //(float) dv->bounds.width() / (float) dv->rt_width; rcus.m_yscale = 1.0; //(float) dv->bounds.height() / (float) dv->rt_height; dv->container->set_user_settings(rcus); //printf("%d %d %d %d\n", wpos.min_x, wpos.max_x, wpos.min_y, wpos.max_y); pos = dv->view->visible_position(); size = dv->view->total_size(); dv->hsb.visible = 0; dv->vsb.visible = 0; dview_get_rect(dv, RECT_DVIEW_CLIENT, r); dv->hsb.visible = (size.x * debug_font_width > r.width() ? 1 : 0); dv->vsb.visible = (size.y * debug_font_height > r.height() ? 1 : 0); dview_get_rect(dv, RECT_DVIEW_CLIENT, r); dv->hsb.visible = (size.x * debug_font_width > r.width() ? 1 : 0); dv->vsb.visible = (size.y * debug_font_height > r.height() ? 1 : 0); dview_get_rect(dv, RECT_DVIEW_CLIENT, r); col.y = (r.height() - 2 * BORDER_YTHICKNESS /*+ debug_font_height - 1*/) / debug_font_height; col.x = (r.width() - 2 * BORDER_XTHICKNESS /*+ debug_font_width - 1*/) / debug_font_width; vsize.y = size.y - pos.y; vsize.x = size.x - pos.x; if(vsize.y > col.y) vsize.y = col.y; else if(vsize.y < col.y) { pos.y = size.y-col.y; if(pos.y < 0) pos.y = 0; vsize.y = size.y-pos.y; } if(vsize.x > col.x) vsize.x = col.x; else if(vsize.x < col.x) { pos.x = size.x-col.x; if(pos.x < 0) pos.x = 0; vsize.x = size.x-pos.x; } dv->view->set_visible_position(pos); dv->view->set_visible_size(vsize); if(dv->hsb.visible) { int span = (r.width() - 2 * BORDER_XTHICKNESS) / debug_font_width; if(pos.x + span > size.x) pos.x = size.x - span; if(pos.x < 0) pos.x = 0; dv->hsb.lower = 0; dv->hsb.upper = size.x; dv->hsb.value = pos.x; dv->hsb.step_increment = 1; dv->hsb.page_increment = span; dv->hsb.page_size = span; dv->view->set_visible_position(pos); } if(dv->vsb.visible) { int span = (r.height() - 2 * BORDER_YTHICKNESS) / debug_font_height; if(pos.y + span > size.y) pos.y = size.y - span; if(pos.y < 0) pos.y = 0; dv->vsb.lower = 0; dv->vsb.upper = size.y; dv->vsb.value = pos.y; dv->vsb.step_increment = 1; dv->vsb.page_increment = span; dv->vsb.page_size = span; dv->view->set_visible_position(pos); } } static void dview_update(debug_view &dw, void *osdprivate) { DView *dv = (DView *) osdprivate; dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); #if 0 debug_view_xy size = dw.total_size(); if((dv->tr != size.y) || (dv->tc != size.x)) gtk_widget_queue_resize(GTK_WIDGET(dv)); else gtk_widget_queue_draw(GTK_WIDGET(dv)); #endif } static void debugint_exit(running_machine &machine) { for (DView *ndv = list; ndv != NULL; ) { DView *temp = ndv; ndv = ndv->next; dview_free(temp); } if (debug_font != NULL) { machine.render().font_free(debug_font); debug_font = NULL; } } void debugint_init(running_machine &machine) { unicode_char ch; int chw; debug_font = machine.render().font_alloc("ui.bdf"); //ui_get_font(machine); debug_font_width = 0; debug_font_height = 15; menu = NULL; cur_editor = NULL; list = NULL; focus_view = NULL; debug_font_aspect = machine.render().ui_aspect(); for (ch=0;ch<=127;ch++) { chw = debug_font->char_width(debug_font_height, debug_font_aspect, ch); if (chw>debug_font_width) debug_font_width = chw; } debug_font_width++; /* FIXME: above does not really work */ debug_font_width = 10; machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(debugint_exit), &machine)); } #if 0 static void set_view_by_name(render_target *target, const char *name) { int i = 0; const char *s; for (i = 0; ; i++ ) { s = target->view_name(i); if (s == NULL) return; //printf("%d %s\n", i, s); if (strcmp(name, s) == 0) { target->set_view(i); //printf("%d\n", target->view() ); return; } } } #endif /*------------------------------------------------- Menu Callbacks -------------------------------------------------*/ static void process_string(DView *dv, const char *str) { switch (dv->type) { case DVT_DISASSEMBLY: downcast(dv->view)->set_expression(str); break; case DVT_CONSOLE: if(!dv->editor.str[(int)0]) debug_cpu_get_visible_cpu(dv->machine())->debug()->single_step(); else debug_console_execute_command(dv->machine(), str, 1); break; case DVT_MEMORY: downcast(dv->view)->set_expression(str); break; } } static void on_memory_window_activate(DView *dv, const ui_menu_event *event) { } static void on_disassembly_window_activate(DView *dv, const ui_menu_event *event) { DView *ndv; render_target *target; const debug_view_source *source; target = &dv->machine().render().ui_target(); ndv = dview_alloc(target, dv->machine(), DVT_DISASSEMBLY, 0); ndv->editor.active = TRUE; ndv->editor.container = &dv->machine().render().ui_container(); source = ndv->view->source(); dview_set_title(ndv, source->name()); set_focus_view(ndv); } static void on_disasm_cpu_activate(DView *dv, const ui_menu_event *event) { const debug_view_source *current = dv->view->source(); if (event->iptkey == IPT_UI_RIGHT) { current = current->next(); if (current == NULL) { current = dv->view->source_list().head(); } dv->view->set_source(*current); dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); dview_set_title(dv, current->name()); } } static void on_log_window_activate(DView *dv, const ui_menu_event *event) { DView *ndv; render_target *target; target = &dv->machine().render().ui_target(); ndv = dview_alloc(target, dv->machine(), DVT_LOG, 0); dview_set_title(ndv, "Log"); set_focus_view(ndv); } static void on_close_activate(DView *dv, const ui_menu_event *event) { if (focus_view == dv) set_focus_view(dv->next); dview_free(dv); } static void on_run_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->go(); } #if 0 void on_run_h_activate(DView *dv, const ui_menu_event *event) { debugwin_show(0); debug_cpu_get_visible_cpu(dv->machine())->debug()->go(); } #endif static void on_run_cpu_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->go_next_device(); } static void on_run_irq_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->go_interrupt(); } static void on_run_vbl_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->go_vblank(); } static void on_step_into_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->single_step(); } static void on_step_over_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->single_step_over(); } #ifdef UNUSED_CODE static void on_step_out_activate(DView *dv, const ui_menu_event *event) { debug_cpu_get_visible_cpu(dv->machine())->debug()->single_step_out(); } #endif static void on_hard_reset_activate(DView *dv, const ui_menu_event *event) { dv->machine().schedule_hard_reset(); } static void on_soft_reset_activate(DView *dv, const ui_menu_event *event) { dv->machine().schedule_soft_reset(); debug_cpu_get_visible_cpu(dv->machine())->debug()->go(); } static void on_exit_activate(DView *dv, const ui_menu_event *event) { dv->machine().schedule_exit(); } static void on_view_opcodes_activate(DView *dv, const ui_menu_event *event) { debug_view_disasm *dasmview = downcast(focus_view->view); disasm_right_column rc = dasmview->right_column(); disasm_right_column new_rc = DASM_RIGHTCOL_NONE; if (event->iptkey == IPT_UI_RIGHT) { switch (rc) { case DASM_RIGHTCOL_RAW: new_rc = DASM_RIGHTCOL_ENCRYPTED; break; case DASM_RIGHTCOL_ENCRYPTED: new_rc = DASM_RIGHTCOL_COMMENTS; break; case DASM_RIGHTCOL_COMMENTS: new_rc = DASM_RIGHTCOL_RAW; break; default: break; } dasmview->set_right_column(new_rc); dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); } } static void on_run_to_cursor_activate(DView *dv, const ui_menu_event *event) { char command[64]; if (dv->view->cursor_visible() && debug_cpu_get_visible_cpu(dv->machine()) == dv->view->source()->device()) { offs_t address = downcast(dv->view)->selected_address(); sprintf(command, "go %X", address); debug_console_execute_command(dv->machine(), command, 1); } } /*------------------------------------------------- editor -------------------------------------------------*/ static void render_editor(DView_edit *editor) { float width, maxwidth; float x1, y1, x2, y2; editor->container->empty(); /* get the size of the text */ ui_draw_text_full(editor->container, editor->str, 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, NULL); width += 2 * UI_BOX_LR_BORDER; maxwidth = MAX(width, 0.5); /* compute our bounds */ x1 = 0.5f - 0.5f * maxwidth; x2 = x1 + maxwidth; y1 = 0.25f; y2 = 0.45f - UI_BOX_TB_BORDER; /* draw a box */ ui_draw_outlined_box(editor->container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); /* take off the borders */ x1 += UI_BOX_LR_BORDER; x2 -= UI_BOX_LR_BORDER; y1 += UI_BOX_TB_BORDER; y2 -= UI_BOX_TB_BORDER; /* draw the text within it */ ui_draw_text_full(editor->container, editor->str, x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, NULL, NULL); } /*------------------------------------------------- menu_main_populate - populate the main menu -------------------------------------------------*/ class ui_menu_debug : public ui_menu { public: ui_menu_debug(running_machine &machine, render_container *container) : ui_menu(machine, container) {} virtual ~ui_menu_debug() {} virtual void populate() {} virtual void handle() {} }; static void CreateMainMenu(running_machine &machine) { const char *subtext = ""; int rc; astring title; if (menu) auto_free(machine, menu); menu = auto_alloc_clear(machine, ui_menu_debug(machine, &machine.render().ui_container())); switch (focus_view->type) { case DVT_DISASSEMBLY: title = "Disassembly:"; break; case DVT_CONSOLE: title = "Console:"; break; case DVT_LOG: title = "Log:"; break; case DVT_MEMORY: title = "Memory:"; break; case DVT_STATE: title = "State:"; break; } menu->item_append(title.cat(focus_view->title), NULL, MENU_FLAG_DISABLE, NULL); menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); switch (focus_view->type) { case DVT_DISASSEMBLY: { rc = downcast(focus_view->view)->right_column(); switch(rc) { case DASM_RIGHTCOL_RAW: subtext = "Raw Opcodes"; break; case DASM_RIGHTCOL_ENCRYPTED: subtext = "Enc Opcodes"; break; case DASM_RIGHTCOL_COMMENTS: subtext = "Comments"; break; } menu->item_append("View", subtext, MENU_FLAG_RIGHT_ARROW, (void *)on_view_opcodes_activate); menu->item_append("Run to cursor", NULL, 0, (void *)on_run_to_cursor_activate); if (!dview_is_state(focus_view, VIEW_STATE_FOLLOW_CPU)) { menu->item_append("CPU", focus_view->view->source()->name(), MENU_FLAG_RIGHT_ARROW, (void *)on_disasm_cpu_activate); } menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); break; } } /* add input menu items */ menu->item_append("New Memory Window", NULL, 0, (void *)on_memory_window_activate); menu->item_append("New Disassembly Window", NULL, 0, (void *)on_disassembly_window_activate); menu->item_append("New Error Log Window", NULL, 0, (void *)on_log_window_activate); menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); menu->item_append("Run", NULL, 0, (void *)on_run_activate); menu->item_append("Run to Next CPU", NULL, 0, (void *)on_run_cpu_activate); menu->item_append("Run until Next Interrupt on This CPU", NULL, 0, (void *)on_run_irq_activate); menu->item_append("Run until Next VBLANK", NULL, 0, (void *)on_run_vbl_activate); menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); menu->item_append("Step Into", NULL, 0, (void *)on_step_into_activate); menu->item_append("Step Over", NULL, 0, (void *)on_step_over_activate); menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); menu->item_append("Soft Reset", NULL, 0, (void *)on_soft_reset_activate); menu->item_append("Hard Reset", NULL, 0, (void *)on_hard_reset_activate); menu->item_append(MENU_SEPARATOR_ITEM, NULL, 0, NULL); if (!dview_is_state(focus_view, VIEW_STATE_FOLLOW_CPU)) menu->item_append("Close Window", NULL, 0, (void *)on_close_activate); menu->item_append("Exit", NULL, 0, (void *)on_exit_activate); } static int map_point(DView *dv, INT32 target_x, INT32 target_y, INT32 *mapped_x, INT32 *mapped_y) { rectangle pos; /* default to point not mapped */ *mapped_x = -1; *mapped_y = -1; pos = dv->bounds; pos.min_x += dv->ofs_x; pos.max_x += dv->ofs_x; pos.min_y += dv->ofs_y; pos.max_y += dv->ofs_y; //render_target_get_component_container(target, name, &pos); if (target_x >= pos.min_x && target_x <= pos.max_x && target_y >= pos.min_y && target_y <= pos.max_y) { *mapped_x = target_x - pos.min_x; *mapped_y = target_y - pos.min_y; return TRUE; } return FALSE; } static void handle_mouse(running_machine &machine) { render_target * mouse_target; INT32 x,y; int button; if (menu != NULL) return; mouse_target = ui_input_find_mouse(machine, &x, &y, &button); if (mouse_target == NULL) return; //printf("mouse %d %d %d\n", x, y, button); for (DView *dv = list; dv != NULL; dv = dv->next) { if (mouse_target == dv->target) { if (dview_on_mouse(dv, x, y, button)) break; } } } /*------------------------------------------------- handle_editor - handle the editor -------------------------------------------------*/ static void handle_editor(running_machine &machine) { if (focus_view->editor.active) { ui_event event; /* loop while we have interesting events */ while (ui_input_pop_event(machine, &event)) { switch (event.event_type) { case UI_EVENT_CHAR: /* if it's a backspace and we can handle it, do so */ if ((event.ch == 8 || event.ch == 0x7f) && focus_view->editor.str.len() > 0) { /* autoschow */ cur_editor = &focus_view->editor; cur_editor->str = cur_editor->str.substr(0, cur_editor->str.len()-1); } /* if it's any other key and we're not maxed out, update */ else if (event.ch >= ' ' && event.ch < 0x7f) { char buf[10]; int ret; /* autoschow */ cur_editor = &focus_view->editor; ret = utf8_from_uchar(buf, 10, event.ch); buf[ret] = 0; cur_editor->str = cur_editor->str.cat(buf); } break; default: break; } } if (cur_editor != NULL) { render_editor(cur_editor); if (ui_input_pressed(machine, IPT_UI_SELECT)) { process_string(focus_view, focus_view->editor.str); focus_view->editor.str = ""; cur_editor = NULL; } if (ui_input_pressed(machine, IPT_UI_CANCEL)) cur_editor = NULL; } } } /*------------------------------------------------- menu_main - handle the main menu -------------------------------------------------*/ static void handle_menus(running_machine &machine) { const ui_menu_event *event; machine.render().ui_container().empty(); ui_input_frame_update(machine); if (menu != NULL) { /* process the menu */ event = menu->process(0); if (event != NULL && (event->iptkey == IPT_UI_SELECT || (event->iptkey == IPT_UI_RIGHT))) { //auto_free(machine, menu); //menu = NULL; ((void (*)(DView *, const ui_menu_event *)) event->itemref)(focus_view, event); //ui_menu_stack_push(ui_menu_alloc(machine, menu->container, (ui_menu_handler_func)event->itemref, NULL)); CreateMainMenu(machine); } else if (ui_input_pressed(machine, IPT_UI_CONFIGURE)) { auto_free(machine, menu); menu = NULL; } } else { /* turn on menus if requested */ if (ui_input_pressed(machine, IPT_UI_CONFIGURE)) CreateMainMenu(machine); /* turn on editor if requested */ //if (ui_input_pressed(machine, IPT_UI_UP) && focus_view->editor.active) // cur_editor = &focus_view->editor; handle_editor(machine); } } //============================================================ // followers_set_cpu //============================================================ static void followers_set_cpu(device_t *device) { astring title; for (DView *dv = list; dv != NULL; dv = dv->next) { if (dview_is_state(dv, VIEW_STATE_FOLLOW_CPU)) { const debug_view_source *source = dv->view->source_list().match_device(device); switch (dv->type) { case DVT_DISASSEMBLY: case DVT_STATE: dv->view->set_source(*source); title.printf("%s", source->name()); dview_set_title(dv, title); break; } } } // and recompute the children //console_recompute_children(main_console); } static void dview_update_view(DView *dv) { INT32 old_rt_width = dv->rt_width; INT32 old_rt_height = dv->rt_height; dv->rt_width = dv->target->width(); dv->rt_height = dv->target->height(); if (dview_is_state(dv, VIEW_STATE_NEEDS_UPDATE) || dv->rt_width != old_rt_width || dv->rt_height != old_rt_height) { dview_size_allocate(dv); dview_draw(dv); dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, FALSE); } } static void update_views(void) { DView *dv, *prev; LIST_GET_LAST(list, dv); while (dv != NULL) { dview_update_view(dv); LIST_GET_PREVIOUS(list, dv, prev); dv = prev; } } void debugint_wait_for_debugger(device_t &device, bool firststop) { if (firststop && list == NULL) { DView *dv; render_target *target; target = &device.machine().render().ui_target(); //set_view_by_name(target, "Debug"); dv = dview_alloc(target, device.machine(), DVT_DISASSEMBLY, VIEW_STATE_FOLLOW_CPU); dv->editor.active = TRUE; dv->editor.container = &device.machine().render().ui_container(); dv = dview_alloc(target, device.machine(), DVT_STATE, VIEW_STATE_FOLLOW_CPU); dv = dview_alloc(target, device.machine(), DVT_CONSOLE, VIEW_STATE_FOLLOW_CPU); dview_set_title(dv, "Console"); dv->editor.active = TRUE; dv->editor.container = &device.machine().render().ui_container(); set_focus_view(dv); } followers_set_cpu(&device); //ui_update_and_render(device.machine(), device.machine().render().ui_container()()); update_views(); device.machine().osd().update(false); handle_menus(device.machine()); handle_mouse(device.machine()); //osd_sleep(osd_ticks_per_second()/60); } void debugint_update_during_game(running_machine &machine) { if (!debug_cpu_is_stopped(machine) && machine.phase() == MACHINE_PHASE_RUNNING) { update_views(); } }