From 0898987bc3f7c308b7088d7dd259e6e65a3ca152 Mon Sep 17 00:00:00 2001 From: Couriersud Date: Thu, 11 Feb 2010 23:59:36 +0000 Subject: [PATCH] Internal debugger using the mame rendering infrastructure - added support for arbitrary number of containers for render_target - added command-line parameter -debug_internal (-di) to use the internal debugger when in debug mode - internal debugger supports all views except memory view - added "Debug" view to layout/vertical.lay to create more place for debug views in vertical games. The colors are ugly. Font rendering needs improvement. There are no shortcut keys right now. There is still a lot of room for more improvements. However, it works and does not depend on any ui toolkit. The interface has been designed to support displaying views programmatically e.g. from the ui. Currently, the ui render target is used. In order to support views being displayed in separate windows further changes are needed: - the osd layer must support creating and closing windows (render targets) on demand. - There must be a mode for render targets where their bounds follows the window size - Currently the render target size depends on the aspect of currently selected "artwork" view. - Render target needs a name property. Short HowTo: - Start MAME with "-debug -di" - Console, register and disasm views will be shown. Place them by dragging the view on the title bar. - Views can be resized by dragging the bottom-right yellow square. - The view having the focus has a green background title bar. - Hit "Tab" (IPT_UI_CONFIGURE) to show the menu. - Console and disasm views support a very simple facility to support entering commands and addresses. Just start typing. Hit "enter" when finished. --- .gitattributes | 2 + src/emu/debug/debugcpu.c | 6 +- src/emu/debugger.c | 4 + src/emu/debugint/debugint.c | 1497 +++++++++++++++++++++++++++++++++++ src/emu/debugint/debugint.h | 47 ++ src/emu/emu.mak | 4 +- src/emu/emuopts.c | 1 + src/emu/emuopts.h | 1 + src/emu/layout/vertical.lay | 13 + src/emu/mame.c | 5 +- src/emu/render.c | 156 ++-- src/emu/render.h | 5 +- src/emu/rendlay.c | 48 +- src/emu/rendlay.h | 36 +- src/emu/video.c | 4 + 15 files changed, 1711 insertions(+), 118 deletions(-) create mode 100644 src/emu/debugint/debugint.c create mode 100644 src/emu/debugint/debugint.h diff --git a/.gitattributes b/.gitattributes index 9da580f9cde..16b33914f15 100644 --- a/.gitattributes +++ b/.gitattributes @@ -556,6 +556,8 @@ src/emu/debug/textbuf.c svneol=native#text/plain src/emu/debug/textbuf.h svneol=native#text/plain src/emu/debugger.c svneol=native#text/plain src/emu/debugger.h svneol=native#text/plain +src/emu/debugint/debugint.c svneol=native#text/plain +src/emu/debugint/debugint.h svneol=native#text/plain src/emu/deprecat.h svneol=native#text/plain src/emu/devcb.c svneol=native#text/plain src/emu/devcb.h svneol=native#text/plain diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c index 511b3198403..b80c7835706 100644 --- a/src/emu/debug/debugcpu.c +++ b/src/emu/debug/debugcpu.c @@ -24,6 +24,7 @@ #include "express.h" #include "debugvw.h" #include "debugger.h" +#include "debugint/debugint.h" #include "uiinput.h" #include @@ -674,7 +675,10 @@ void debug_cpu_instruction_hook(running_device *device, offs_t curpc) /* clear the memory modified flag and wait */ global->memory_modified = FALSE; - osd_wait_for_debugger(device, firststop); + if (device->machine->debug_flags & DEBUG_FLAG_OSD_ENABLED) + osd_wait_for_debugger(device, firststop); + else if (device->machine->debug_flags & DEBUG_FLAG_ENABLED) + debugint_wait_for_debugger(device, firststop); firststop = FALSE; /* if something modified memory, update the screen */ diff --git a/src/emu/debugger.c b/src/emu/debugger.c index b722425b9fe..66c8277fda9 100644 --- a/src/emu/debugger.c +++ b/src/emu/debugger.c @@ -17,6 +17,7 @@ #include "debug/debugcon.h" #include "debug/express.h" #include "debug/debugvw.h" +#include "debugint/debugint.h" #include @@ -73,6 +74,9 @@ void debugger_init(running_machine *machine) debug_view_init(machine); debug_comment_init(machine); + /* always initialize the internal render debugger */ + debugint_init(machine); + /* allocate a new entry for our global list */ add_exit_callback(machine, debugger_exit); entry = global_alloc(machine_entry); diff --git a/src/emu/debugint/debugint.c b/src/emu/debugint/debugint.c new file mode 100644 index 00000000000..d969a2da90d --- /dev/null +++ b/src/emu/debugint/debugint.c @@ -0,0 +1,1497 @@ +/********************************************************************* + + 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 "uimenu.h" +#include "uiinput.h" +#include "video.h" +#include "osdepend.h" + +#include "debug/debugvw.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)rect_get_width(&(_dv)->bounds)) +//#define NY(_dv, _y) ((float) (_y)/(float)rect_get_height(&(_dv)->bounds)) +#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, int 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 = render_debug_alloc(target); + this->view = debug_view_alloc(machine, type, dview_update, this); + this->type = type; + this->machine = machine; + this->state = flags | VIEW_STATE_NEEDS_UPDATE; + + // initial size + this->bounds.min_x = 0; + this->bounds.min_y = 0; + this->bounds.max_x = 300; + this->bounds.max_y = 300; + + /* specials */ + switch (type) + { + case DVT_DISASSEMBLY: + /* set up disasm view */ + debug_view_begin_update(this->view); + disasm_view_set_expression(this->view, "curpc"); + //debug_view_ property_UINT32(dv->view, DVP_DASM_TRACK_LIVE, 1); + debug_view_end_update(this->view); + break; + } + } + ~DView() + { + render_debug_free(this->target, this->container); + debug_view_free(this->view); + } + + DView * next; + + int type; + debug_view * view; + render_container * container; + render_target * target; + running_machine * 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 rect_get_width(rectangle *r) +{ + return r->max_x - r->min_x + 1; +} + +INLINE int rect_get_height(rectangle *r) +{ + return r->max_y - r->min_y + 1; +} + +INLINE void rect_set_width(rectangle *r, int width) +{ + r->max_x = r->min_x + width - 1; +} + +INLINE void rect_set_height(rectangle *r, int height) +{ + r->max_y = r->min_y + height - 1; +} + +INLINE void rect_move(rectangle *r, int x, int y) +{ + int dx = x - r->min_x; + int dy = y - r->min_y; + + r->min_x += dx; + r->max_x += dx; + r->min_y += dy; + r->max_y += dy; +} + +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); + render_debug_top(dv->target, dv->container); + } +} + +static DView *dview_alloc(render_target *target, running_machine *machine, int 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) +{ + //astring_free(dv->title); + 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) +{ + render_container_empty(dv->container); +} + +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); + render_container_add_rect(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), 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); + render_container_add_char(dv->container, + NX(dv, x + r.min_x), + NY(dv, y + r.min_y), + NY(dv, h), + debug_font_aspect, + //(float) rect_get_height(&dv->bounds) / (float) rect_get_width(&dv->bounds), //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 (x >= r.min_x && x <= r.max_x && y >= r.min_y && y <= r.max_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, rect_get_width(&r) - VSB_WIDTH, 0, VSB_WIDTH, HSB_HEIGHT, MAKE_ARGB(0xff, 0xff, 0x00, 0x00)); + + ts = (r.max_x - r.min_x + 1) - 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, rect_get_height(&r) - 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.max_y - r.min_y + 1) - 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, + rect_get_width(&r),rect_get_height(&r), 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, rect_get_width(&dv->bounds), TITLE_HEIGHT, col); + + if (dv->title == NULL) + 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) / (rect_get_width(&r) - 2 * dv->vsb.visible * VSB_WIDTH) + sb->lower; + if (x < VSB_WIDTH) + sb->value -= sb->step_increment; + else if (x > rect_get_width(&r) - 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 = debug_view_get_visible_position(dv->view); + + if (sb->value != pos.x) + { + pos.x = sb->value; + debug_view_set_visible_position(dv->view, 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) / (rect_get_height(&r) - 2 * HSB_HEIGHT) + sb->lower; + + if (y < HSB_HEIGHT) + sb->value -= sb->step_increment; + else if (y > rect_get_height(&r) - 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 = debug_view_get_visible_position(dv->view); + + if (sb->value != pos.y) + { + pos.y = sb->value; + debug_view_set_visible_position(dv->view, 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 (debug_view_get_cursor_supported(dv->view) && clicked && y >= 0) + { + debug_view_xy topleft = debug_view_get_visible_position(dv->view); + debug_view_xy newpos; + newpos.x = topleft.x + x / debug_font_width; + newpos.y = topleft.y + y / debug_font_height; + debug_view_set_cursor_position(dv->view, newpos); + debug_view_set_cursor_visible(dv->view, 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 = debug_view_get_visible_size(dv->view); + + 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, + rect_get_width(&r) /*- (dv->vs ? VSB_WIDTH : 0)*/, + rect_get_height(&r) /*- (dv->hsb.visible ? HSB_HEIGHT : 0)*/, bg_base); + + /* background first */ + viewdata = debug_view_get_chars(dv->view); + + 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 = debug_view_get_chars(dv->view); + + 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; + + render_container_get_user_settings(dv->container, &rcus); + rcus.xoffset = (float) dv->ofs_x / (float) dv->rt_width; + rcus.yoffset = (float) dv->ofs_y / (float) dv->rt_height; + rcus.xscale = 1.0; //(float) rect_get_width(&dv->bounds) / (float) dv->rt_width; + rcus.yscale = 1.0; //(float) rect_get_height(&dv->bounds) / (float) dv->rt_height; + render_container_set_user_settings(dv->container, &rcus); + //printf("%d %d %d %d\n", wpos.min_x, wpos.max_x, wpos.min_y, wpos.max_y); + + pos = debug_view_get_visible_position(dv->view); + size = debug_view_get_total_size(dv->view); + + dv->hsb.visible = 0; + dv->vsb.visible = 0; + dview_get_rect(dv, RECT_DVIEW_CLIENT, &r); + + dv->hsb.visible = (size.x * debug_font_width > rect_get_width(&r) ? 1 : 0); + dv->vsb.visible = (size.y * debug_font_height > rect_get_height(&r) ? 1 : 0); + dview_get_rect(dv, RECT_DVIEW_CLIENT, &r); + + dv->hsb.visible = (size.x * debug_font_width > rect_get_width(&r) ? 1 : 0); + dv->vsb.visible = (size.y * debug_font_height > rect_get_height(&r) ? 1 : 0); + dview_get_rect(dv, RECT_DVIEW_CLIENT, &r); + + col.y = (rect_get_height(&r) - 2 * BORDER_YTHICKNESS /*+ debug_font_height - 1*/) / debug_font_height; + col.x = (rect_get_width(&r) - 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; + } + + debug_view_set_visible_position(dv->view, pos); + debug_view_set_visible_size(dv->view, vsize); + + if(dv->hsb.visible) { + int span = (rect_get_width(&r) - 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; + + debug_view_set_visible_position(dv->view, pos); + } + + if(dv->vsb.visible) { + int span = (rect_get_height(&r) - 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; + + debug_view_set_visible_position(dv->view, 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 = debug_view_get_total_size(dw); + + 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) + { + render_font_free(debug_font); + debug_font = NULL; + } + +} + +void debugint_init(running_machine *machine) +{ + unicode_char ch; + int chw; + debug_font = render_font_alloc("ui.bdf"); //ui_get_font(); + debug_font_width = 0; + debug_font_height = 15; + + menu = NULL; + cur_editor = NULL; + list = NULL; + focus_view = NULL; + + debug_font_aspect = render_get_ui_aspect(); + + for (ch=0;ch<=127;ch++) + { + chw = render_font_get_char_width(debug_font, 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; + add_exit_callback(machine, debugint_exit); +} + +#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 = render_target_get_view_name(target, i); + if (s == NULL) + return; + //printf("%d %s\n", i, s); + if (strcmp(name, s) == 0) + { + render_target_set_view(target, i); + //printf("%d\n", render_target_get_view(target) ); + return; + } + } +} +#endif + +/*------------------------------------------------- + Menu Callbacks + -------------------------------------------------*/ + +static void process_string(DView *dv, const char *str) +{ + switch (dv->type) + { + case DVT_DISASSEMBLY: + disasm_view_set_expression(dv->view, str); + break; + case DVT_CONSOLE: + if(!dv->editor.str[0]) + debug_cpu_single_step(dv->machine, 1); + else + debug_console_execute_command(dv->machine, str, 1); + break; + case DVT_MEMORY: + memory_view_set_expression(dv->view, str); + break; + } +} + +void on_memory_window_activate(DView *dv, const ui_menu_event *event) +{ +} + +void on_disassembly_window_activate(DView *dv, const ui_menu_event *event) +{ + DView *ndv; + render_target *target; + const disasm_subview_item *dasmsubitem; + + target = render_get_ui_target(); + + ndv = dview_alloc(target, dv->machine, DVT_DISASSEMBLY, 0); + ndv->editor.active = TRUE; + ndv->editor.container = render_container_get_ui(); + dasmsubitem = disasm_view_get_current_subview(ndv->view); + dview_set_title(ndv, dasmsubitem->name); + set_focus_view(ndv); + +} + +void on_disasm_cpu_activate(DView *dv, const ui_menu_event *event) +{ + const disasm_subview_item *subview; + int current = disasm_view_get_subview(dv->view); + + if (event->iptkey == IPT_UI_RIGHT) + { + current++; + subview = disasm_view_get_subview_by_index(disasm_view_get_subview_list(dv->view), current); + if (subview == NULL) + { + current = 0; + subview = disasm_view_get_subview_by_index(disasm_view_get_subview_list(dv->view), current); + } + disasm_view_set_subview(dv->view, current); + dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); + dview_set_title(dv, subview->name); + } +} + +void on_log_window_activate(DView *dv, const ui_menu_event *event) +{ + DView *ndv; + render_target *target; + + target = render_get_ui_target(); + ndv = dview_alloc(target, dv->machine, DVT_LOG, 0); + dview_set_title(ndv, "Log"); + set_focus_view(ndv); +} + +void on_close_activate(DView *dv, const ui_menu_event *event) +{ + if (focus_view == dv) + set_focus_view(dv->next); + dview_free(dv); +} + +void on_run_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_go(dv->machine, ~0); +} + +#if 0 +void on_run_h_activate(DView *dv, const ui_menu_event *event) +{ + debugwin_show(0); + debug_cpu_go(dv->machine, ~0); +} +#endif + +void on_run_cpu_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_next_cpu(dv->machine); +} + +void on_run_irq_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_go_interrupt(dv->machine, -1); +} + +void on_run_vbl_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_go_vblank(dv->machine); +} + +void on_step_into_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_single_step(dv->machine, 1); +} + +void on_step_over_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_single_step_over(dv->machine, 1); +} + +void on_step_out_activate(DView *dv, const ui_menu_event *event) +{ + debug_cpu_single_step_out(dv->machine); +} + +void on_hard_reset_activate(DView *dv, const ui_menu_event *event) +{ + mame_schedule_hard_reset(dv->machine); +} + +void on_soft_reset_activate(DView *dv, const ui_menu_event *event) +{ + mame_schedule_soft_reset(dv->machine); + debug_cpu_go(dv->machine, ~0); +} + +void on_exit_activate(DView *dv, const ui_menu_event *event) +{ + mame_schedule_exit(dv->machine); +} + +void on_view_opcodes_activate(DView *dv, const ui_menu_event *event) +{ + disasm_right_column rc = disasm_view_get_right_column(focus_view->view); + 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; + } + disasm_view_set_right_column(dv->view, new_rc); + dview_set_state(dv, VIEW_STATE_NEEDS_UPDATE, TRUE); + } +} + +void on_run_to_cursor_activate(DView *dv, const ui_menu_event *event) +{ + char command[64]; + + if (debug_view_get_cursor_visible(dv->view)) + { + const address_space *space = disasm_view_get_current_subview(dv->view)->space; + if (debug_cpu_get_visible_cpu(dv->machine) == space->cpu) + { + offs_t address = disasm_view_get_selected_address(dv->view); + 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; + + render_container_empty(editor->container); + /* 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.25; + y2 = 0.45 - 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 + -------------------------------------------------*/ + +static void CreateMainMenu(running_machine *machine) +{ + const char *subtext = ""; + int rc; + astring title; + + if (menu != NULL) + ui_menu_free(menu); + menu = ui_menu_alloc(machine, render_container_get_ui(),NULL,NULL); + + 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_REGISTERS: + title = "Registers:"; + break; + } + + ui_menu_item_append(menu, title.cat(focus_view->title), NULL, MENU_FLAG_DISABLE, NULL); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + + switch (focus_view->type) + { + case DVT_DISASSEMBLY: + rc = disasm_view_get_right_column(focus_view->view); + 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; + } + ui_menu_item_append(menu, "View", subtext, MENU_FLAG_RIGHT_ARROW, (void *)on_view_opcodes_activate); + ui_menu_item_append(menu, "Run to cursor", NULL, 0, (void *)on_run_to_cursor_activate); + + if (!dview_is_state(focus_view, VIEW_STATE_FOLLOW_CPU)) + { + const disasm_subview_item * dsi; + dsi = disasm_view_get_current_subview(focus_view->view); + ui_menu_item_append(menu, "CPU", dsi->name, MENU_FLAG_RIGHT_ARROW, (void *)on_disasm_cpu_activate); + } + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + break; + } + + /* add input menu items */ + + ui_menu_item_append(menu, "New Memory Window", NULL, 0, (void *)on_memory_window_activate); + ui_menu_item_append(menu, "New Disassembly Window", NULL, 0, (void *)on_disassembly_window_activate); + ui_menu_item_append(menu, "New Error Log Window", NULL, 0, (void *)on_log_window_activate); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + ui_menu_item_append(menu, "Run", NULL, 0, (void *)on_run_activate); + ui_menu_item_append(menu, "Run to Next CPU", NULL, 0, (void *)on_run_cpu_activate); + ui_menu_item_append(menu, "Run until Next Interrupt on This CPU", NULL, 0, (void *)on_run_irq_activate); + ui_menu_item_append(menu, "Run until Next VBLANK", NULL, 0, (void *)on_run_vbl_activate); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + ui_menu_item_append(menu, "Step Into", NULL, 0, (void *)on_step_into_activate); + ui_menu_item_append(menu, "Step Over", NULL, 0, (void *)on_step_over_activate); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + ui_menu_item_append(menu, "Soft Reset", NULL, 0, (void *)on_soft_reset_activate); + ui_menu_item_append(menu, "Hard Reset", NULL, 0, (void *)on_hard_reset_activate); + ui_menu_item_append(menu, MENU_SEPARATOR_ITEM, NULL, 0, NULL); + if (!dview_is_state(focus_view, VIEW_STATE_FOLLOW_CPU)) + ui_menu_item_append(menu, "Close Window", NULL, 0, (void *)on_close_activate); + ui_menu_item_append(menu, "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()); + } + /* 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; + + render_container_empty(render_container_get_ui()); + ui_input_frame_update(machine); + if (menu != NULL) + { + /* process the menu */ + event = ui_menu_process(machine, menu, 0); + if (event != NULL && (event->iptkey == IPT_UI_SELECT || (event->iptkey == IPT_UI_RIGHT))) + { + //ui_menu_free(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)) + { + ui_menu_free(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(running_device *device) +{ + const registers_subview_item *regsubitem = NULL; + const disasm_subview_item *dasmsubitem; + char title[256]; + + for (DView *dv = list; dv != NULL; dv = dv->next) + { + if (dview_is_state(dv, VIEW_STATE_FOLLOW_CPU)) + { + switch (dv->type) + { + case DVT_DISASSEMBLY: + for (dasmsubitem = disasm_view_get_subview_list(dv->view); dasmsubitem != NULL; dasmsubitem = dasmsubitem->next) + if (dasmsubitem->space->cpu == device) + { + disasm_view_set_subview(dv->view, dasmsubitem->index); + snprintf(title, ARRAY_LENGTH(title), "%s", dasmsubitem->name.cstr()); + dview_set_title(dv, title); + break; + } + break; + case DVT_REGISTERS: + for (regsubitem = registers_view_get_subview_list(dv->view); regsubitem != NULL; regsubitem = regsubitem->next) + if (regsubitem->device == device) + { + registers_view_set_subview(dv->view, regsubitem->index); + snprintf(title, ARRAY_LENGTH(title), "%s", regsubitem->name.cstr()); + dview_set_title(dv, title); + break; + } + 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; + + render_target_get_bounds(dv->target, &dv->rt_width, &dv->rt_height, NULL); + 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(running_device *device, int firststop) +{ + + if (firststop && list == NULL) + { + DView *dv; + render_target *target; + + target = render_get_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 = render_container_get_ui(); + dv = dview_alloc(target, device->machine, DVT_REGISTERS, 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 = render_container_get_ui(); + set_focus_view(dv); + } + + followers_set_cpu(device); + + //ui_update_and_render(device->machine, render_container_get_ui()); + update_views(); + osd_update(device->machine, 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) && mame_get_phase(machine) == MAME_PHASE_RUNNING) + { + update_views(); + } +} diff --git a/src/emu/debugint/debugint.h b/src/emu/debugint/debugint.h new file mode 100644 index 00000000000..88b55608657 --- /dev/null +++ b/src/emu/debugint/debugint.h @@ -0,0 +1,47 @@ +/********************************************************************* + + debugint.c + + Internal debugger frontend using render interface. + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +*********************************************************************/ + +#pragma once + +#ifndef __DEBUGINT_H__ +#define __DEBUGINT_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +/* initialize the internal debugger */ +void debugint_init(running_machine *machine); + +/* process events for internal debugger */ +void debugint_wait_for_debugger(running_device *device, int firststop); + +/* update the internal debugger during a game */ +void debugint_update_during_game(running_machine *machine); + +#endif diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 162cd94a729..f2c7e5e4fb5 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -23,6 +23,7 @@ OBJDIRS += \ $(EMUOBJ)/cpu \ $(EMUOBJ)/sound \ $(EMUOBJ)/debug \ + $(EMUOBJ)/debugint \ $(EMUOBJ)/audio \ $(EMUOBJ)/drivers \ $(EMUOBJ)/machine \ @@ -86,7 +87,8 @@ EMUOBJS = \ $(EMUOBJ)/debug/debughlp.o \ $(EMUOBJ)/debug/debugvw.o \ $(EMUOBJ)/debug/express.o \ - $(EMUOBJ)/debug/textbuf.o + $(EMUOBJ)/debug/textbuf.o \ + $(EMUOBJ)/debugint/debugint.o ifdef PROFILER EMUOBJS += \ diff --git a/src/emu/emuopts.c b/src/emu/emuopts.c index f7125a24785..829e82b7522 100644 --- a/src/emu/emuopts.c +++ b/src/emu/emuopts.c @@ -148,6 +148,7 @@ const options_entry mame_core_options[] = { "update_in_pause", "0", OPTION_BOOLEAN, "keep calling video updates while in pause" }, { "debug;d", "0", OPTION_BOOLEAN, "enable/disable debugger" }, { "debugscript", NULL, 0, "script for debugger" }, + { "debug_internal;di", "0", OPTION_BOOLEAN, "use the internal debugger for debugging" }, /* misc options */ { NULL, NULL, OPTION_HEADER, "CORE MISC OPTIONS" }, diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h index 359edabf5b2..1d46e2702fa 100644 --- a/src/emu/emuopts.h +++ b/src/emu/emuopts.h @@ -143,6 +143,7 @@ #define OPTION_VERBOSE "verbose" #define OPTION_LOG "log" #define OPTION_DEBUG "debug" +#define OPTION_DEBUG_INTERNAL "debug_internal" #define OPTION_DEBUGSCRIPT "debugscript" #define OPTION_UPDATEINPAUSE "update_in_pause" diff --git a/src/emu/layout/vertical.lay b/src/emu/layout/vertical.lay index 2f6b3d88602..2d66df317f8 100644 --- a/src/emu/layout/vertical.lay +++ b/src/emu/layout/vertical.lay @@ -21,4 +21,17 @@ + + + + + + + + + + + + + diff --git a/src/emu/mame.c b/src/emu/mame.c index 6d679764d65..9a7876a7b38 100644 --- a/src/emu/mame.c +++ b/src/emu/mame.c @@ -1317,7 +1317,10 @@ running_machine::running_machine(const game_driver *driver) /* fetch core options */ sample_rate = options_get_int(mame_options(), OPTION_SAMPLERATE); - debug_flags = options_get_bool(mame_options(), OPTION_DEBUG) ? (DEBUG_FLAG_ENABLED | DEBUG_FLAG_OSD_ENABLED | DEBUG_FLAG_CALL_HOOK) : 0; + if (options_get_bool(mame_options(), OPTION_DEBUG)) + debug_flags = (DEBUG_FLAG_ENABLED | DEBUG_FLAG_CALL_HOOK) | (options_get_bool(mame_options(), OPTION_DEBUG_INTERNAL) ? 0 : DEBUG_FLAG_OSD_ENABLED); + else + debug_flags = 0; } catch (std::bad_alloc &) { diff --git a/src/emu/render.c b/src/emu/render.c index d864e8a3fa7..34edf9c2a50 100644 --- a/src/emu/render.c +++ b/src/emu/render.c @@ -61,6 +61,15 @@ #define INTERNAL_FLAG_CHAR 0x00000001 +enum +{ + COMPONENT_TYPE_IMAGE = 0, + COMPONENT_TYPE_RECT, + COMPONENT_TYPE_DISK, + COMPONENT_TYPE_MAX +}; + + enum { CONTAINER_ITEM_LINE = 0, @@ -105,6 +114,7 @@ struct _object_transform float xscale, yscale; /* scale transforms */ render_color color; /* color transform */ int orientation; /* orientation transform */ + int no_center; /* center the container? */ }; @@ -157,6 +167,7 @@ public: int base_layerconfig; /* the layer configuration at the time of first frame */ int maxtexwidth; /* maximum width of a texture */ int maxtexheight; /* maximum height of a texture */ + render_container * debug_containers; }; @@ -271,7 +282,6 @@ static container_item *render_container_item_add_generic(render_container *conta static void render_container_overlay_scale(bitmap_t *dest, const bitmap_t *source, const rectangle *sbounds, void *param); static void render_container_recompute_lookups(render_container *container); static void render_container_update_palette(render_container *container); -static void render_target_free_component_containers(const render_target *target); @@ -1145,10 +1155,6 @@ void render_target_free(render_target *target) for (curr = &targetlist; *curr != target; curr = &(*curr)->next) ; *curr = target->next; - /* free any containers */ - - render_target_free_component_containers(target); - /* free any primitives */ for (listnum = 0; listnum < ARRAY_LENGTH(target->primlist); listnum++) { @@ -1636,6 +1642,22 @@ const render_primitive_list *render_target_get_primitives(render_target *target) } } + /* process the debug containers */ + for (render_container *debug = target->debug_containers; debug != NULL; debug = debug->next) + { + ui_xform.xoffs = 0; + ui_xform.yoffs = 0; + ui_xform.xscale = (float) target->width; + ui_xform.yscale = (float) target->height; + ui_xform.color.r = ui_xform.color.g = ui_xform.color.b = ui_xform.color.a = 1.0f; + ui_xform.color.a = 0.9; + ui_xform.orientation = target->orientation; + ui_xform.no_center = TRUE; + + /* add UI elements */ + add_container_primitives(target, &target->primlist[listnum], &ui_xform, debug, BLENDMODE_ALPHA); + } + /* process the UI if we are the UI target */ if (target == render_get_ui_target()) { @@ -1905,8 +1927,16 @@ static void add_container_primitives(render_target *target, render_primitive_lis if (container_xform.orientation & ORIENTATION_FLIP_Y) yoffs = -yoffs; container_xform.xscale = xform->xscale * xscale; container_xform.yscale = xform->yscale * yscale; - container_xform.xoffs = xform->xscale * (0.5f - 0.5f * xscale + xoffs) + xform->xoffs; - container_xform.yoffs = xform->yscale * (0.5f - 0.5f * yscale + yoffs) + xform->yoffs; + if (xform->no_center) + { + container_xform.xoffs = xform->xscale * (xoffs) + xform->xoffs; + container_xform.yoffs = xform->yscale * (yoffs) + xform->yoffs; + } + else + { + container_xform.xoffs = xform->xscale * (0.5f - 0.5f * xscale + xoffs) + xform->xoffs; + container_xform.yoffs = xform->yscale * (0.5f - 0.5f * yscale + yoffs) + xform->yoffs; + } container_xform.color = xform->color; } @@ -2111,19 +2141,6 @@ static void add_element_primitives(render_target *target, render_primitive_list else free_render_primitive(prim); } - /* Look for container components */ - for (element_component *component = element->complist; element != NULL; element = element->next ) - { - if (component->type == COMPONENT_TYPE_CONTAINER) - { - if (component->container != NULL) - add_container_primitives(target, list, xform, component->container, BLENDMODE_ALPHA); - component->scaled_bounds.min_x = render_round_nearest(xform->xoffs); - component->scaled_bounds.min_y = render_round_nearest(xform->yoffs); - component->scaled_bounds.max_x = render_round_nearest(xform->xoffs + xform->xscale); - component->scaled_bounds.max_y = render_round_nearest(xform->yoffs + xform->yscale); - } - } } @@ -3162,49 +3179,66 @@ static void render_container_update_palette(render_container *container) } } -static void render_target_free_component_containers(const render_target *target) + +render_container *render_debug_alloc(render_target *target) { - /* for each layer, get scan all components ... */ - for (int layer = 0; layer < ITEM_LAYER_MAX; layer++) - for (view_item *item = target->curview->itemlist[layer]; item != NULL; item = item->next) - { - for (layout_element *element = item->element; element != NULL; element = element->next) - { - for (element_component *component = element->complist; component != NULL; component = component->next) - { - if ((component->type == COMPONENT_TYPE_CONTAINER) && component->container != NULL) - { - render_container_free(component->container); - component->container = NULL; - } - } - } - } + render_container *container = render_container_alloc(target->machine); + + container->next = target->debug_containers; + target->debug_containers = container; + + return container; } -render_container *render_target_get_component_container(const render_target *target, const char *name, rectangle *scaled_bounds) -{ - /* for each layer, get scan all components ... */ - for (int layer = 0; layer < ITEM_LAYER_MAX; layer++) - for (view_item *item = target->curview->itemlist[layer]; item != NULL; item = item->next) - { - for (layout_element *element = item->element; element != NULL; element = element->next) - { - for (element_component *component = element->complist; component != NULL; component = component->next) - { - if ((component->type == COMPONENT_TYPE_CONTAINER) && (strcmp(name, component->string) == 0)) - { - if (scaled_bounds != NULL) - *scaled_bounds = component->scaled_bounds; - if (component->container == NULL) - { - component->container = render_container_alloc(target->machine); - } - return component->container; - } - } - } - } - return NULL; +void render_debug_free(render_target *target, render_container *container) +{ + if (container == target->debug_containers) + { + target->debug_containers = container->next; + } + else + { + render_container *c; + + for (c = target->debug_containers; c != NULL; c = c->next) + if (c->next == container) + break; + c->next = container->next; + } + render_container_free(container); } + + +void render_debug_top(render_target *target, render_container *container) +{ + /* remove */ + if (container == target->debug_containers) + { + target->debug_containers = container->next; + } + else + { + render_container *c; + + for (c = target->debug_containers; c != NULL; c = c->next) + if (c->next == container) + break; + c->next = container->next; + } + /* add to end */ + if (target->debug_containers == NULL) + target->debug_containers = container; + else + { + render_container *c; + + for (c = target->debug_containers; c != NULL; c = c->next) + if (c->next == NULL) + break; + c->next = container; + } + container->next = NULL; +} + + diff --git a/src/emu/render.h b/src/emu/render.h index d6655c49bfa..ccab0cd78f4 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -460,6 +460,9 @@ void render_container_add_quad(render_container *container, float x0, float y0, /* add a char item to the specified container */ void render_container_add_char(render_container *container, float x0, float y0, float height, float aspect, rgb_t argb, render_font *font, UINT16 ch); -render_container *render_target_get_component_container(const render_target *target, const char *name, rectangle *scaled_bounds); +/* "drawable" handling for internal debugger */ +render_container *render_debug_alloc(render_target *target); +void render_debug_free(render_target *target, render_container *container); +void render_debug_top(render_target *target, render_container *container); #endif /* __RENDER_H__ */ diff --git a/src/emu/rendlay.c b/src/emu/rendlay.c index 57d339a8053..dac640d67c9 100644 --- a/src/emu/rendlay.c +++ b/src/emu/rendlay.c @@ -106,11 +106,40 @@ #define LINE_CAP_START 1 #define LINE_CAP_END 2 +enum +{ + COMPONENT_TYPE_IMAGE = 0, + COMPONENT_TYPE_RECT, + COMPONENT_TYPE_DISK, + COMPONENT_TYPE_TEXT, + COMPONENT_TYPE_LED7SEG, + COMPONENT_TYPE_LED14SEG, + COMPONENT_TYPE_LED16SEG, + COMPONENT_TYPE_LED14SEGSC, + COMPONENT_TYPE_LED16SEGSC, + COMPONENT_TYPE_MAX +}; + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ +/* an element_component represents an image, rectangle, or disk in an element */ +struct _element_component +{ + element_component * next; /* link to next component */ + int type; /* type of component */ + int state; /* state where this component is visible (-1 means all states) */ + render_bounds bounds; /* bounds of the element */ + render_color color; /* color of the element */ + const char * string; /* string for text components */ + bitmap_t * bitmap; /* source bitmap for images */ + const char * dirname; /* directory name of image file (for lazy loading) */ + const char * imagefile; /* name of the image file (for lazy loading) */ + const char * alphafile; /* name of the alpha file (for lazy loading) */ + int hasalpha; /* is there any alpha component present? */ +}; @@ -363,10 +392,6 @@ static void layout_element_scale(bitmap_t *dest, const bitmap_t *source, const r layout_element_draw_text(dest, &bounds, &component->color, component->string); break; - case COMPONENT_TYPE_CONTAINER: - component->scaled_bounds = bounds; - break; - case COMPONENT_TYPE_LED7SEG: layout_element_draw_led7seg(dest, &bounds, &component->color, elemtex->state); break; @@ -1662,20 +1687,6 @@ static element_component *load_element_component(const machine_config *config, x component->alphafile = (afile == NULL) ? NULL : copy_string(afile); } - /* container nodes */ - else if (strcmp(compnode->name, "container") == 0) - { - const char *name = xml_get_attribute_string_with_subst(config, compnode, "name", ""); - char *string; - - /* allocate a copy of the string */ - component->type = COMPONENT_TYPE_CONTAINER; - string = global_alloc_array(char, strlen(name) + 1); - strcpy(string, name); - component->string = string; - component->container = NULL; - } - /* text nodes */ else if (strcmp(compnode->name, "text") == 0) { @@ -2113,4 +2124,3 @@ static void layout_element_free(layout_element *element) global_free(element->name); global_free(element); } - diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h index 18f901c4536..64592fc6d1d 100644 --- a/src/emu/rendlay.h +++ b/src/emu/rendlay.h @@ -70,21 +70,6 @@ enum }; -enum -{ - COMPONENT_TYPE_IMAGE = 0, - COMPONENT_TYPE_RECT, - COMPONENT_TYPE_DISK, - COMPONENT_TYPE_TEXT, - COMPONENT_TYPE_CONTAINER, - COMPONENT_TYPE_LED7SEG, - COMPONENT_TYPE_LED14SEG, - COMPONENT_TYPE_LED16SEG, - COMPONENT_TYPE_LED14SEGSC, - COMPONENT_TYPE_LED16SEGSC, - COMPONENT_TYPE_MAX -}; - /*************************************************************************** TYPE DEFINITIONS @@ -98,25 +83,6 @@ typedef struct _view_item view_item; typedef struct _layout_view layout_view; typedef struct _layout_file layout_file; -/* an element_component represents an image, rectangle, or disk in an element */ -struct _element_component -{ - element_component * next; /* link to next component */ - int type; /* type of component */ - int state; /* state where this component is visible (-1 means all states) */ - render_bounds bounds; /* bounds of the element */ - render_container * container; /* container for container elements */ - rectangle scaled_bounds; /* for container elements */ - render_color color; /* color of the element */ - const char * string; /* string for text components */ - /* name for container components */ - bitmap_t * bitmap; /* source bitmap for images */ - const char * dirname; /* directory name of image file (for lazy loading) */ - const char * imagefile; /* name of the image file (for lazy loading) */ - const char * alphafile; /* name of the alpha file (for lazy loading) */ - int hasalpha; /* is there any alpha component present? */ -}; - /* an element_texture encapsulates a texture for a given element in a given state */ struct _element_texture { @@ -201,6 +167,8 @@ void layout_view_recompute(layout_view *view, int layerconfig); layout_file *layout_file_load(const machine_config *config, const char *dirname, const char *filename); void layout_file_free(layout_file *file); + + /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ diff --git a/src/emu/video.c b/src/emu/video.c index 7b8c8691bcf..090de3e0e71 100644 --- a/src/emu/video.c +++ b/src/emu/video.c @@ -14,6 +14,7 @@ #include "profiler.h" #include "png.h" #include "debugger.h" +#include "debugint/debugint.h" #include "rendutil.h" #include "ui.h" #include "aviio.h" @@ -1301,6 +1302,9 @@ void video_frame_update(running_machine *machine, int debug) /* draw the user interface */ ui_update_and_render(machine, render_container_get_ui()); + /* update the internal render debugger */ + debugint_update_during_game(machine); + /* if we're throttling, synchronize before rendering */ if (!debug && !skipped_it && effective_throttle(machine)) update_throttle(machine, current_time);