summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2010-06-25 05:11:42 +0000
committer Aaron Giles <aaron@aarongiles.com>2010-06-25 05:11:42 +0000
commit29b6b0de4167319a4f64ee95ecc5f18ba3fdf923 (patch)
treea408b4561c3d622c98e267e9a8a269390e0210ba /src/emu/debug
parent1c9abccb20fc25c928990ef050bce82efac99cc8 (diff)
C++-ified the debugger views. Not quite architecturally where I would
like them, but it's a start. Split implementation of individual view types out to separate files. Updated all callers. Also: * fixed okim6295 memory view * changed emualloc to free resource pools from earliest to latest so that early objects can safely clean up stuff they allocated
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugcmd.c4
-rw-r--r--src/emu/debug/debugcmt.c6
-rw-r--r--src/emu/debug/debugcon.c10
-rw-r--r--src/emu/debug/debugcpu.c17
-rw-r--r--src/emu/debug/debugvw.c3433
-rw-r--r--src/emu/debug/debugvw.h661
-rw-r--r--src/emu/debug/dvdisasm.c710
-rw-r--r--src/emu/debug/dvdisasm.h146
-rw-r--r--src/emu/debug/dvmemory.c813
-rw-r--r--src/emu/debug/dvmemory.h160
-rw-r--r--src/emu/debug/dvstate.c370
-rw-r--r--src/emu/debug/dvstate.h117
-rw-r--r--src/emu/debug/dvtext.c184
-rw-r--r--src/emu/debug/dvtext.h90
14 files changed, 3274 insertions, 3447 deletions
diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c
index 1998851f001..7d00f073e06 100644
--- a/src/emu/debug/debugcmd.c
+++ b/src/emu/debug/debugcmd.c
@@ -1128,7 +1128,7 @@ static void execute_comment(running_machine *machine, int ref, int params, const
/* Now try adding the comment */
debug_comment_add(cpu, address, param[1], 0x00ff0000, debug_comment_get_opcode_crc32(cpu, address));
- debug_view_update_type(cpu->machine, DVT_DISASSEMBLY);
+ cpu->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
}
@@ -1152,7 +1152,7 @@ static void execute_comment_del(running_machine *machine, int ref, int params, c
/* If it's a number, it must be an address */
/* The bankoff and cbn will be pulled from what's currently active */
debug_comment_remove(cpu, address, debug_comment_get_opcode_crc32(cpu, address));
- debug_view_update_type(cpu->machine, DVT_DISASSEMBLY);
+ cpu->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
}
diff --git a/src/emu/debug/debugcmt.c b/src/emu/debug/debugcmt.c
index 69c0c8671e4..c73b0441c41 100644
--- a/src/emu/debug/debugcmt.c
+++ b/src/emu/debug/debugcmt.c
@@ -155,7 +155,7 @@ int debug_comment_add(device_t *device, offs_t addr, const char *comment, rgb_t
comments->change_count++;
/* force an update of disassembly views */
- debug_view_update_type(device->machine, DVT_DISASSEMBLY);
+ device->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
return 1;
}
@@ -170,7 +170,7 @@ int debug_comment_add(device_t *device, offs_t addr, const char *comment, rgb_t
comments->change_count++;
/* force an update of disassembly views */
- debug_view_update_type(device->machine, DVT_DISASSEMBLY);
+ device->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
return 1;
}
@@ -207,7 +207,7 @@ int debug_comment_remove(device_t *device, offs_t addr, UINT32 c_crc)
comments->change_count++;
/* force an update of disassembly views */
- debug_view_update_type(device->machine, DVT_DISASSEMBLY);
+ device->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
return 1;
}
diff --git a/src/emu/debug/debugcon.c b/src/emu/debug/debugcon.c
index 203cb17bfe5..10ed838ce47 100644
--- a/src/emu/debug/debugcon.c
+++ b/src/emu/debug/debugcon.c
@@ -382,7 +382,7 @@ CMDERR debug_console_execute_command(running_machine *machine, const char *comma
/* update all views */
if (echo)
{
- debug_view_update_all(machine);
+ machine->m_debug_view->update_all();
debugger_refresh_display(machine);
}
return result;
@@ -481,7 +481,7 @@ void CLIB_DECL debug_console_printf(running_machine *machine, const char *format
text_buffer_print(console_textbuf, buffer);
/* force an update of any console views */
- debug_view_update_type(machine, DVT_CONSOLE);
+ machine->m_debug_view->update_all(DVT_CONSOLE);
}
@@ -499,7 +499,7 @@ void CLIB_DECL debug_console_vprintf(running_machine *machine, const char *forma
text_buffer_print(console_textbuf, buffer);
/* force an update of any console views */
- debug_view_update_type(machine, DVT_CONSOLE);
+ machine->m_debug_view->update_all(DVT_CONSOLE);
}
@@ -521,7 +521,7 @@ void CLIB_DECL debug_console_printf_wrap(running_machine *machine, int wrapcol,
text_buffer_print_wrap(console_textbuf, buffer, wrapcol);
/* force an update of any console views */
- debug_view_update_type(machine, DVT_CONSOLE);
+ machine->m_debug_view->update_all(DVT_CONSOLE);
}
@@ -547,7 +547,7 @@ void debug_errorlog_write_line(running_machine *machine, const char *line)
text_buffer_print(errorlog_textbuf, line);
/* force an update of any log views */
- debug_view_update_type(machine, DVT_LOG);
+ machine->m_debug_view->update_all(DVT_LOG);
}
diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c
index 2996d9ac6cf..30b841e638c 100644
--- a/src/emu/debug/debugcpu.c
+++ b/src/emu/debug/debugcpu.c
@@ -321,7 +321,8 @@ symbol_table *debug_cpu_get_visible_symtable(running_machine *machine)
symbol_table *debug_cpu_get_symtable(device_t *device)
{
- return cpu_get_debug_data(device)->symtable;
+ cpu_device *cpu = dynamic_cast<cpu_device *>(device);
+ return (cpu != NULL) ? cpu_get_debug_data(device)->symtable : NULL;
}
@@ -425,8 +426,8 @@ void debug_cpu_start_hook(device_t *device, attotime endtime)
/* check for periodic updates */
if (device == global->visiblecpu && osd_ticks() > global->last_periodic_update_time + osd_ticks_per_second()/4)
{
- debug_view_update_all(device->machine);
- debug_view_flush_updates(device->machine);
+ device->machine->m_debug_view->update_all();
+ device->machine->m_debug_view->flush_osd_updates();
global->last_periodic_update_time = osd_ticks();
}
@@ -566,8 +567,8 @@ void debug_cpu_instruction_hook(device_t *device, offs_t curpc)
/* update every 100 steps until we are within 200 of the end */
else if ((cpudebug->flags & DEBUG_FLAG_STEPPING_OUT) == 0 && (cpudebug->stepsleft < 200 || cpudebug->stepsleft % 100 == 0))
{
- debug_view_update_all(device->machine);
- debug_view_flush_updates(device->machine);
+ device->machine->m_debug_view->update_all();
+ device->machine->m_debug_view->flush_osd_updates();
debugger_refresh_display(device->machine);
}
}
@@ -608,7 +609,7 @@ void debug_cpu_instruction_hook(device_t *device, offs_t curpc)
global->visiblecpu = device;
/* update all views */
- debug_view_update_all(device->machine);
+ device->machine->m_debug_view->update_all();
debugger_refresh_display(device->machine);
/* wait for the debugger; during this time, disable sound output */
@@ -616,7 +617,7 @@ void debug_cpu_instruction_hook(device_t *device, offs_t curpc)
while (global->execution_state == EXECUTION_STATE_STOPPED)
{
/* flush any pending updates before waiting again */
- debug_view_flush_updates(device->machine);
+ device->machine->m_debug_view->flush_osd_updates();
/* clear the memory modified flag and wait */
global->memory_modified = FALSE;
@@ -629,7 +630,7 @@ void debug_cpu_instruction_hook(device_t *device, offs_t curpc)
/* if something modified memory, update the screen */
if (global->memory_modified)
{
- debug_view_update_type(device->machine, DVT_DISASSEMBLY);
+ device->machine->m_debug_view->update_all(DVT_DISASSEMBLY);
debugger_refresh_display(device->machine);
}
diff --git a/src/emu/debug/debugvw.c b/src/emu/debug/debugvw.c
index c99f590d4e9..067896b64a5 100644
--- a/src/emu/debug/debugvw.c
+++ b/src/emu/debug/debugvw.c
@@ -4,3276 +4,641 @@
Debugger view engine.
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
-*********************************************************************/
+***************************************************************************/
#include "emu.h"
#include "debugvw.h"
+#include "dvtext.h"
+#include "dvstate.h"
+#include "dvdisasm.h"
+#include "dvmemory.h"
#include "debugcmd.h"
#include "debugcmt.h"
#include "debugcpu.h"
#include "debugcon.h"
#include "express.h"
-#include "textbuf.h"
#include <ctype.h>
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define DEFAULT_DASM_LINES (1000)
-#define DEFAULT_DASM_WIDTH (50)
-#define DASM_MAX_BYTES (16)
-#define MEM_MAX_LINE_WIDTH (1024)
-
-enum _view_notification
-{
- VIEW_NOTIFY_NONE,
- VIEW_NOTIFY_VISIBLE_CHANGED,
- VIEW_NOTIFY_CURSOR_CHANGED
-};
-typedef enum _view_notification view_notification;
-
-#define REG_DIVIDER -10
-#define REG_CYCLES -11
-#define REG_BEAMX -12
-#define REG_BEAMY -13
-#define REG_FRAME -14
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* internal callback function pointers */
-typedef int (*view_alloc_func)(debug_view *view);
-typedef void (*view_free_func)(debug_view *view);
-typedef void (*view_update_func)(debug_view *view);
-typedef void (*view_notify_func)(debug_view *view, view_notification type);
-typedef void (*view_char_func)(debug_view *view, int chval);
-
-
-/* debug_view_callbacks contains internal callbacks specific to a given view */
-typedef struct _debug_view_callbacks debug_view_callbacks;
-struct _debug_view_callbacks
-{
- view_alloc_func alloc; /* allocate memory */
- view_free_func free; /* free memory */
- view_update_func update; /* update contents */
- view_notify_func notify; /* notify of something changed */
- view_char_func handlechar; /* handle a typed character */
-};
-
-
-/* debug_view_section contains information about a section of a view */
-typedef struct _debug_view_section debug_view_section;
-struct _debug_view_section
-{
- INT32 pos; /* starting position */
- INT32 width; /* width of this section */
-};
-
-
-/* debug view expression contains information about an embedded expression */
-typedef struct _debug_view_expression debug_view_expression;
-struct _debug_view_expression
-{
- UINT64 result; /* last result from the expression */
- parsed_expression * parsed; /* parsed expression data */
- astring string; /* copy of the expression string */
- UINT8 dirty; /* true if the expression needs to be re-evaluated */
-};
-
-
-/* debug_view describes a single text-based view */
-class debug_view
-{
-public:
- /* core view data */
- debug_view * next; /* link to the next view */
- running_machine * machine; /* machine associated with this view */
- UINT8 type; /* type of view */
- void * extra_data; /* extra view-specific data */
- debug_view_callbacks cb; /* callback for this view */
-
- /* OSD data */
- debug_view_osd_update_func osdupdate; /* callback for the update */
- void * osdprivate; /* OSD-managed private data */
-
- /* visibility info */
- debug_view_xy visible; /* visible size (in rows and columns) */
- debug_view_xy total; /* total size (in rows and columns) */
- debug_view_xy topleft; /* top-left visible position (in rows and columns) */
- debug_view_xy cursor; /* cursor position */
- UINT8 supports_cursor; /* does this view support a cursor? */
- UINT8 cursor_visible; /* is the cursor visible? */
-
- /* update info */
- UINT8 recompute; /* does this view require a recomputation? */
- UINT8 update_level; /* update level; updates when this hits 0 */
- UINT8 update_pending; /* true if there is a pending update */
- UINT8 osd_update_pending; /* true if there is a pending update */
- debug_view_char * viewdata; /* current array of view data */
- int viewdata_size; /* number of elements of the viewdata array */
-};
-
-
-/* debug_view_registers contains data specific to a register view */
-typedef struct _debug_view_register debug_view_register;
-struct _debug_view_register
-{
- UINT64 lastval; /* last value */
- UINT64 currval; /* current value */
- int regnum; /* index */
- UINT8 vallen; /* number of value chars */
- astring symbol; /* symbol */
-};
-
-
-typedef struct _debug_view_registers debug_view_registers;
-struct _debug_view_registers
-{
- const registers_subview_item *subview; /* pointer to our subview */
- int divider; /* dividing column */
- UINT64 last_update; /* execution counter at last update */
- debug_view_register reg[MAX_REGS]; /* register data */
-};
-
-
-/* debug_view_disasm contains data specific to a disassembly view */
-typedef struct _debug_view_disasm debug_view_disasm;
-struct _debug_view_disasm
-{
- const address_space *space; /* address space whose data we are disassembling */
- disasm_right_column right_column; /* right column contents */
- UINT32 backwards_steps; /* number of backwards steps */
- UINT32 dasm_width; /* width of the disassembly area */
- UINT8 * last_direct_raw; /* last direct raw value */
- UINT8 * last_direct_decrypted; /* last direct decrypted value */
- UINT32 last_change_count; /* last comment change count */
- offs_t last_pcbyte; /* last PC byte value */
- int divider1, divider2; /* left and right divider columns */
- int divider3; /* comment divider column */
- debug_view_expression expression; /* expression-related information */
- debug_view_xy allocated; /* allocated rows/columns */
- offs_t * byteaddress; /* addresses of the instructions */
- char * dasm; /* disassembled instructions */
-};
-
-
-/* debug_view_memory contains data specific to a memory view */
-typedef struct _debug_view_memory debug_view_memory;
-struct _debug_view_memory
-{
- const memory_subview_item *subviewlist; /* linked list of memory subviews */
- const memory_subview_item *desc; /* description of our current subview */
- debug_view_expression expression; /* expression describing the start address */
- UINT32 chunks_per_row; /* number of chunks displayed per line */
- UINT8 bytes_per_chunk; /* bytes per chunk */
- UINT8 reverse_view; /* reverse-endian view? */
- UINT8 ascii_view; /* display ASCII characters? */
- UINT8 no_translation; /* don't run addresses through the cpu translation hook */
- debug_view_section section[3]; /* (derived) 3 sections to manage */
- offs_t maxaddr; /* (derived) maximum address to display */
- UINT32 bytes_per_row; /* (derived) number of bytes displayed per line */
- UINT32 byte_offset; /* (derived) offset of starting visible byte */
- char addrformat[10]; /* (derived) format string to use to print addresses */
-};
-
-
-/* debug_view_textbuf contains data specific to a textbuffer view */
-typedef struct _debug_view_textbuf debug_view_textbuf;
-struct _debug_view_textbuf
-{
- text_buffer * textbuf; /* pointer to the text buffer */
- UINT8 at_bottom; /* are we tracking new stuff being added? */
- UINT32 topseq; /* sequence number of the top line */
-};
-
-
-/* memory_view_pos contains positioning data for memory views */
-typedef struct _memory_view_pos memory_view_pos;
-struct _memory_view_pos
-{
- UINT8 spacing; /* spacing between each entry */
- UINT8 shift[24]; /* shift for each character */
-};
-
-
-/* debugvw_priate contains internal global data for this module */
-/* In mame.h: typedef struct _debugvw_private debugvw_priate; */
-struct _debugvw_private
-{
- debug_view * viewlist; /* list of views */
- const registers_subview_item *registers_subviews;/* linked list of registers subviews */
- const disasm_subview_item *disasm_subviews; /* linked list of disassembly subviews */
-};
-
-
-
-/***************************************************************************
- LOCAL VARIABLES
-***************************************************************************/
-
-static const memory_view_pos memory_pos_table[9] =
-{
- /* 0 bytes per chunk: */ { 0, { 0 } },
- /* 1 byte per chunk: 00 11 22 33 44 55 66 77 */ { 3, { 0x04, 0x00, 0x80 } },
- /* 2 bytes per chunk: 0011 2233 4455 6677 */ { 6, { 0x8c, 0x0c, 0x08, 0x04, 0x00, 0x80 } },
- /* 3 bytes per chunk: */ { 0, { 0 } },
- /* 4 bytes per chunk: 00112233 44556677 */ { 12, { 0x9c, 0x9c, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80 } },
- /* 5 bytes per chunk: */ { 0, { 0 } },
- /* 6 bytes per chunk: */ { 0, { 0 } },
- /* 7 bytes per chunk: */ { 0, { 0 } },
- /* 8 bytes per chunk: 0011223344556677 */ { 24, { 0xbc, 0xbc, 0xbc, 0xbc, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80 } }
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static void debug_view_exit(running_machine *machine);
-
-static int textbuf_view_alloc(debug_view *view, text_buffer *textbuf);
-static void textbuf_view_free(debug_view *view);
-static void textbuf_view_notify(debug_view *view, view_notification type);
-static void textbuf_view_update(debug_view *view);
-
-static int console_view_alloc(debug_view *view);
-
-static int log_view_alloc(debug_view *view);
-
-static const registers_subview_item *registers_view_enumerate_subviews(running_machine *machine);
-static int registers_view_alloc(debug_view *view);
-static void registers_view_free(debug_view *view);
-static void registers_view_update(debug_view *view);
-
-static const disasm_subview_item *disasm_view_enumerate_subviews(running_machine *machine);
-static int disasm_view_alloc(debug_view *view);
-static void disasm_view_free(debug_view *view);
-static void disasm_view_notify(debug_view *view, view_notification type);
-static void disasm_view_update(debug_view *view);
-static void disasm_view_char(debug_view *view, int chval);
-
-static const memory_subview_item *memory_view_enumerate_subviews(running_machine *machine);
-static int memory_view_alloc(debug_view *view);
-static void memory_view_free(debug_view *view);
-static void memory_view_notify(debug_view *view, view_notification type);
-static void memory_view_update(debug_view *view);
-static void memory_view_char(debug_view *view, int chval);
-static void memory_view_recompute(debug_view *view);
-static int memory_view_needs_recompute(debug_view *view);
-static void memory_view_get_cursor_pos(debug_view *view, offs_t *address, UINT8 *shift);
-static void memory_view_set_cursor_pos(debug_view *view, offs_t address, UINT8 shift);
-static int memory_view_read(debug_view_memory *memdata, UINT8 size, offs_t offs, UINT64 *data);
-static void memory_view_write(debug_view_memory *memdata, UINT8 size, offs_t offs, UINT64 data);
-
-static const debug_view_callbacks callback_table[] =
-{
- { NULL, NULL, NULL, NULL, NULL },
- { console_view_alloc, textbuf_view_free, textbuf_view_update, textbuf_view_notify, NULL },
- { registers_view_alloc, registers_view_free, registers_view_update, NULL, NULL },
- { disasm_view_alloc, disasm_view_free, disasm_view_update, disasm_view_notify, disasm_view_char },
- { memory_view_alloc, memory_view_free, memory_view_update, memory_view_notify, memory_view_char },
- { log_view_alloc, textbuf_view_free, textbuf_view_update, textbuf_view_notify, NULL }
-};
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
+//**************************************************************************
+// DEBUG VIEW SOURCE
+//**************************************************************************
-/*-------------------------------------------------
- in_section - return TRUE if the given X
- coordinate is within a section
--------------------------------------------------*/
+//-------------------------------------------------
+// debug_view_source - constructor
+//-------------------------------------------------
-INLINE int in_section(int x, const debug_view_section *section)
+debug_view_source::debug_view_source(const char *name, device_t *device)
+ : m_next(NULL),
+ m_name(name),
+ m_device(device)
{
- return (x >= section->pos && x < section->pos + section->width);
}
-/*-------------------------------------------------
- adjust_visible_x_for_cursor - adjust a view's
- visible X position to ensure the cursor is
- visible
--------------------------------------------------*/
+//-------------------------------------------------
+// ~debug_view_source - destructor
+//-------------------------------------------------
-INLINE void adjust_visible_x_for_cursor(debug_view *view)
+debug_view_source::~debug_view_source()
{
- if (view->cursor.x < view->topleft.x)
- view->topleft.x = view->cursor.x;
- else if (view->cursor.x >= view->topleft.x + view->visible.x - 1)
- view->topleft.x = view->cursor.x - view->visible.x + 2;
}
-/*-------------------------------------------------
- adjust_visible_y_for_cursor - adjust a view's
- visible Y position to ensure the cursor is
- visible
--------------------------------------------------*/
-
-INLINE void adjust_visible_y_for_cursor(debug_view *view)
-{
- if (view->cursor.y < view->topleft.y)
- view->topleft.y = view->cursor.y;
- else if (view->cursor.y >= view->topleft.y + view->visible.y - 1)
- view->topleft.y = view->cursor.y - view->visible.y + 2;
-}
+//**************************************************************************
+// DEBUG VIEW SOURCE LIST
+//**************************************************************************
+//-------------------------------------------------
+// debug_view_source_list - constructor
+//-------------------------------------------------
-/***************************************************************************
- INITIALIZATION AND SHUTDOWN
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_init - initializes the view system
--------------------------------------------------*/
-
-void debug_view_init(running_machine *machine)
+debug_view_source_list::debug_view_source_list(running_machine &machine)
+ : m_machine(machine),
+ m_head(NULL),
+ m_tail(NULL),
+ m_count(0)
{
- debugvw_private *global;
-
- /* allocate memory for our globals */
- global = machine->debugvw_data = auto_alloc_clear(machine, debugvw_private);
-
- /* register for some manual cleanup */
- add_exit_callback(machine, debug_view_exit);
-
- /* build a list of disassembly and memory subviews */
- global->registers_subviews = registers_view_enumerate_subviews(machine);
- global->disasm_subviews = disasm_view_enumerate_subviews(machine);
}
-/*-------------------------------------------------
- debug_view_exit - exits the view system
--------------------------------------------------*/
+//-------------------------------------------------
+// ~debug_view_source_list - destructor
+//-------------------------------------------------
-static void debug_view_exit(running_machine *machine)
+debug_view_source_list::~debug_view_source_list()
{
- debugvw_private *global = machine->debugvw_data;
-
- /* kill all the views */
- while (global->viewlist != NULL)
- debug_view_free(global->viewlist);
+ reset();
}
+//-------------------------------------------------
+// index - return the index of a source
+//-------------------------------------------------
-/***************************************************************************
- VIEW CREATION/DELETION
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_alloc - allocate a new debug
- view
--------------------------------------------------*/
-
-debug_view *debug_view_alloc(running_machine *machine, int type, debug_view_osd_update_func osdupdate, void *osdprivate)
+int debug_view_source_list::index(const debug_view_source &source) const
{
- debugvw_private *global = machine->debugvw_data;
- debug_view *view;
-
- assert(type >= 0 && type < ARRAY_LENGTH(callback_table));
-
- /* allocate memory for the view */
- view = auto_alloc_clear(machine, debug_view);
-
- /* set the view type information */
- view->machine = machine;
- view->type = type;
- view->cb = callback_table[type];
- view->osdupdate = osdupdate;
- view->osdprivate = osdprivate;
-
- /* set up some reasonable defaults */
- view->visible.x = view->total.x = 10;
- view->visible.y = view->total.y = 10;
-
- /* allocate memory for the buffer */
- view->viewdata_size = view->visible.y * view->visible.x;
- view->viewdata = auto_alloc_array(machine, debug_view_char, view->viewdata_size);
-
- /* allocate extra memory */
- if (view->cb.alloc != NULL && !(*view->cb.alloc)(view))
+ int result = 0;
+ for (debug_view_source *cursource = m_head; cursource != NULL; cursource = cursource->m_next)
{
- auto_free(machine, view->viewdata);
- auto_free(machine, view);
- return NULL;
- }
-
- /* link it in */
- view->next = global->viewlist;
- global->viewlist = view;
-
- /* require a recomputation on the first update */
- view->recompute = TRUE;
- view->update_pending = TRUE;
-
- return view;
-}
-
-
-/*-------------------------------------------------
- debug_view_free - free a debug view
--------------------------------------------------*/
-
-void debug_view_free(debug_view *view)
-{
- debugvw_private *global = view->machine->debugvw_data;
- debug_view **viewptr;
-
- /* find the view */
- for (viewptr = &global->viewlist; *viewptr != NULL; viewptr = &(*viewptr)->next)
- if (*viewptr == view)
- {
- /* unlink */
- *viewptr = view->next;
-
- /* free memory */
- if (view->cb.free != NULL)
- (*view->cb.free)(view);
- if (view->viewdata != NULL)
- auto_free(view->machine, view->viewdata);
- auto_free(view->machine, view);
+ if (cursource == &source)
break;
- }
-}
-
-
-
-/***************************************************************************
- UPDATE MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_begin_update - bracket a sequence
- of changes so that only one update occurs
--------------------------------------------------*/
-
-void debug_view_begin_update(debug_view *view)
-{
- /* bump the level */
- view->update_level++;
-}
-
-
-/*-------------------------------------------------
- debug_view_end_update - bracket a sequence
- of changes so that only one update occurs
--------------------------------------------------*/
-
-void debug_view_end_update(debug_view *view)
-{
- /* if we hit zero, call the update function */
- if (view->update_level == 1)
- {
- while (view->update_pending)
- {
- int size;
-
- /* no longer pending, but flag for the OSD */
- view->update_pending = FALSE;
- view->osd_update_pending = TRUE;
-
- /* resize the viewdata if needed */
- size = view->visible.x * view->visible.y;
- if (size > view->viewdata_size)
- {
- view->viewdata_size = size;
- auto_free(view->machine, view->viewdata);
- view->viewdata = auto_alloc_array(view->machine, debug_view_char, view->viewdata_size);
- }
-
- /* update the view */
- if (view->cb.update != NULL)
- (*view->cb.update)(view);
- }
+ result++;
}
-
- /* decrement the level */
- view->update_level--;
-}
-
-
-/*-------------------------------------------------
- debug_view_flush_updates - force all updates
- to notify the OSD
--------------------------------------------------*/
-
-void debug_view_flush_updates(running_machine *machine)
-{
- debugvw_private *global = machine->debugvw_data;
- debug_view *view;
-
- /* skip if we're not ready yet */
- if (global == NULL)
- return;
-
- /* loop over each view and force an update */
- for (view = global->viewlist; view != NULL; view = view->next)
- if (view->osd_update_pending)
- {
- /* update the owner */
- if (view->osdupdate != NULL)
- (*view->osdupdate)(view, view->osdprivate);
- view->osd_update_pending = FALSE;
- }
+ return result;
}
-/*-------------------------------------------------
- debug_view_update_all - force all views to
- refresh
--------------------------------------------------*/
+//-------------------------------------------------
+// by_index - return a source given an index
+//-------------------------------------------------
-void debug_view_update_all(running_machine *machine)
+const debug_view_source *debug_view_source_list::by_index(int index) const
{
- debugvw_private *global = machine->debugvw_data;
- debug_view *view;
-
- /* skip if we're not ready yet */
- if (global == NULL)
- return;
-
- /* loop over each view and force an update */
- for (view = global->viewlist; view != NULL; view = view->next)
- {
- debug_view_begin_update(view);
- view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- debug_view_update_type - force all views of
- a given type to refresh
--------------------------------------------------*/
-
-void debug_view_update_type(running_machine *machine, int type)
-{
- debugvw_private *global = machine->debugvw_data;
- debug_view *view;
-
- /* skip if we're not ready yet */
- if (global == NULL)
- return;
-
- /* loop over each view and force an update */
- for (view = global->viewlist; view != NULL; view = view->next)
- if (view->type == type)
- {
- debug_view_begin_update(view);
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
-
-
-
-/***************************************************************************
- STANDARD VIEW PROPERTIES
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_get_chars - return a pointer to
- a 2-dimentional array of characters that
- represent the visible area of the view
--------------------------------------------------*/
-
-const debug_view_char *debug_view_get_chars(debug_view *view)
-{
- return view->viewdata;
-}
-
-
-/*-------------------------------------------------
- debug_view_type_character - type a character
- into a view
--------------------------------------------------*/
-
-void debug_view_type_character(debug_view *view, int character)
-{
- /* if the view has a character handler, forward it on */
- if (view->cb.handlechar != NULL)
- (*view->cb.handlechar)(view, character);
-}
-
-
-
-/***************************************************************************
- STANDARD VIEW SIZING
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_get_total_size - return the total
- view size in rows and columns
--------------------------------------------------*/
-
-debug_view_xy debug_view_get_total_size(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->total;
-}
-
-
-/*-------------------------------------------------
- debug_view_get_visible_size - return the
- visible size in rows and columns
--------------------------------------------------*/
-
-debug_view_xy debug_view_get_visible_size(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->visible;
-}
-
-
-/*-------------------------------------------------
- debug_view_get_visible_position - return the
- top left position of the visible area in rows
- and columns
--------------------------------------------------*/
-
-debug_view_xy debug_view_get_visible_position(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->topleft;
-}
-
-
-/*-------------------------------------------------
- debug_view_set_visible_size - set the visible
- size in rows and columns
--------------------------------------------------*/
-
-void debug_view_set_visible_size(debug_view *view, debug_view_xy size)
-{
- if (size.x != view->visible.x || size.y != view->visible.y)
- {
- debug_view_begin_update(view);
- view->visible = size;
- view->update_pending = TRUE;
- if (view->cb.notify != NULL)
- (*view->cb.notify)(view, VIEW_NOTIFY_VISIBLE_CHANGED);
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- debug_view_set_visible_position - set the
- top left position of the visible area in rows
- and columns
--------------------------------------------------*/
-
-void debug_view_set_visible_position(debug_view *view, debug_view_xy pos)
-{
- if (pos.x != view->topleft.x || pos.y != view->topleft.y)
- {
- debug_view_begin_update(view);
- view->topleft = pos;
- view->update_pending = TRUE;
- if (view->cb.notify != NULL)
- (*view->cb.notify)(view, VIEW_NOTIFY_VISIBLE_CHANGED);
- debug_view_end_update(view);
- }
-}
-
-
-
-/***************************************************************************
- STANDARD VIEW CURSOR MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_get_cursor_position - return the
- current cursor position as a row and column
--------------------------------------------------*/
-
-debug_view_xy debug_view_get_cursor_position(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->cursor;
-}
-
-
-/*-------------------------------------------------
- debug_view_get_cursor_supported - return TRUE
- if a cursor is supported for this view type
--------------------------------------------------*/
-
-int debug_view_get_cursor_supported(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->supports_cursor;
-}
-
-
-/*-------------------------------------------------
- debug_view_get_cursor_visible - return TRUE
- if a cursor is currently visible
--------------------------------------------------*/
-
-int debug_view_get_cursor_visible(debug_view *view)
-{
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return view->cursor_visible;
-}
-
-
-/*-------------------------------------------------
- debug_view_set_cursor_position - set the
- current cursor position as a row and column
--------------------------------------------------*/
-
-void debug_view_set_cursor_position(debug_view *view, debug_view_xy pos)
-{
- if (pos.x != view->cursor.x || pos.y != view->cursor.y)
- {
- debug_view_begin_update(view);
- view->cursor = pos;
- view->update_pending = TRUE;
- if (view->cb.notify != NULL)
- (*view->cb.notify)(view, VIEW_NOTIFY_CURSOR_CHANGED);
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- debug_view_set_cursor_visible - set the
- visible state of the cursor
--------------------------------------------------*/
-
-void debug_view_set_cursor_visible(debug_view *view, int visible)
-{
- if (visible != view->cursor_visible)
- {
- debug_view_begin_update(view);
- view->cursor_visible = visible;
- view->update_pending = TRUE;
- if (view->cb.notify != NULL)
- (*view->cb.notify)(view, VIEW_NOTIFY_CURSOR_CHANGED);
- debug_view_end_update(view);
- }
-}
-
-
-
-/***************************************************************************
- GENERIC EXPRESSION HANDLING
-***************************************************************************/
-
-/*-------------------------------------------------
- debug_view_expression_alloc - allocate data
- for an expression
--------------------------------------------------*/
-
-static void debug_view_expression_alloc(debug_view_expression *expression)
-{
-}
-
-
-/*-------------------------------------------------
- debug_view_expression_free - free data
- allocated for an expression
--------------------------------------------------*/
-
-static void debug_view_expression_free(debug_view_expression *expression)
-{
- if (expression->parsed != NULL)
- expression_free(expression->parsed);
-}
-
-
-/*-------------------------------------------------
- debug_view_expression_set - set a new
- expression string
--------------------------------------------------*/
-
-static void debug_view_expression_set(debug_view_expression *expression, const char *string)
-{
- expression->string.cpy(string);
- expression->dirty = TRUE;
-}
-
-
-/*-------------------------------------------------
- debug_view_expression_changed_value - update an
- expression and return TRUE if its value has
- changed
--------------------------------------------------*/
-
-static int debug_view_expression_changed_value(debug_view *view, debug_view_expression *expression, device_t *cpu)
-{
- int changed = expression->dirty;
- EXPRERR exprerr;
-
- /* if dirty, re-evaluate */
- if (expression->dirty)
- {
- symbol_table *symtable = (cpu != NULL) ? debug_cpu_get_symtable(cpu) : debug_cpu_get_global_symtable(view->machine);
- parsed_expression *expr;
-
- /* parse the new expression */
- exprerr = expression_parse(expression->string, symtable, &debug_expression_callbacks, view->machine, &expr);
-
- /* if it worked, update the expression */
- if (exprerr == EXPRERR_NONE)
- {
- if (expression->parsed != NULL)
- expression_free(expression->parsed);
- expression->parsed = expr;
- }
- }
-
- /* if we have a parsed expression, evalute it */
- if (expression->parsed != NULL)
- {
- UINT64 oldresult = expression->result;
-
- /* recompute the value of the expression */
- exprerr = expression_execute(expression->parsed, &expression->result);
- changed |= (expression->result != oldresult);
- }
-
- /* expression no longer dirty by definition */
- expression->dirty = FALSE;
- return changed;
-}
-
-
-
-/***************************************************************************
- TEXT BUFFER-BASED VIEWS
-***************************************************************************/
-
-/*-------------------------------------------------
- console_view_alloc - allocate memory for the
- console view
--------------------------------------------------*/
-
-static int console_view_alloc(debug_view *view)
-{
- return textbuf_view_alloc(view, debug_console_get_textbuf());
-}
-
-
-/*-------------------------------------------------
- log_view_alloc - allocate memory for the log
- view
--------------------------------------------------*/
-
-static int log_view_alloc(debug_view *view)
-{
- return textbuf_view_alloc(view, debug_errorlog_get_textbuf());
-}
-
-
-/*-------------------------------------------------
- textbuf_view_alloc - allocate memory for a
- text buffer-based view
--------------------------------------------------*/
-
-static int textbuf_view_alloc(debug_view *view, text_buffer *textbuf)
-{
- debug_view_textbuf *textdata;
-
- /* allocate memory */
- textdata = auto_alloc_clear(view->machine, debug_view_textbuf);
-
- /* by default we track live */
- textdata->textbuf = textbuf;
- textdata->at_bottom = TRUE;
-
- /* stash the extra data pointer */
- view->extra_data = textdata;
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- textbuf_view_free - free memory for a text
- buffer-based view
--------------------------------------------------*/
-
-static void textbuf_view_free(debug_view *view)
-{
- debug_view_textbuf *textdata = (debug_view_textbuf *)view->extra_data;
-
- /* free any memory we callocated */
- auto_free(view->machine, textdata);
- view->extra_data = NULL;
+ if (m_head == NULL)
+ return NULL;
+ const debug_view_source *result;
+ for (result = m_head; index > 0 && result->m_next != NULL; result = result->m_next)
+ index--;
+ return result;
}
-/*-------------------------------------------------
- textbuf_view_update - update a text buffer-
- based view
--------------------------------------------------*/
+//-------------------------------------------------
+// reset - free all the view_sources
+//-------------------------------------------------
-static void textbuf_view_update(debug_view *view)
+void debug_view_source_list::reset()
{
- debug_view_textbuf *textdata = (debug_view_textbuf *)view->extra_data;
- debug_view_char *dest = view->viewdata;
- UINT32 curseq = 0, row;
-
- /* update the console info */
- view->total.x = text_buffer_max_width(textdata->textbuf);
- view->total.y = text_buffer_num_lines(textdata->textbuf);
- if (view->total.x < 80)
- view->total.x = 80;
-
- /* determine the starting sequence number */
- if (!textdata->at_bottom)
- {
- curseq = textdata->topseq;
- if (!text_buffer_get_seqnum_line(textdata->textbuf, curseq))
- textdata->at_bottom = TRUE;
- }
- if (textdata->at_bottom)
- {
- curseq = text_buffer_line_index_to_seqnum(textdata->textbuf, view->total.y - 1);
- if (view->total.y < view->visible.y)
- curseq -= view->total.y - 1;
- else
- curseq -= view->visible.y - 1;
- }
- view->topleft.y = curseq - text_buffer_line_index_to_seqnum(textdata->textbuf, 0);
-
- /* loop over visible rows */
- for (row = 0; row < view->visible.y; row++)
+ // free from the head
+ while (m_head != NULL)
{
- const char *line = text_buffer_get_seqnum_line(textdata->textbuf, curseq++);
- UINT32 col = 0;
-
- /* if this visible row is valid, add it to the buffer */
- if (line != NULL)
- {
- size_t len = strlen(line);
- UINT32 effcol = view->topleft.x;
-
- /* copy data */
- while (col < view->visible.x && effcol < len)
- {
- dest->byte = line[effcol++];
- dest->attrib = DCA_NORMAL;
- dest++;
- col++;
- }
- }
-
- /* fill the rest with blanks */
- while (col < view->visible.x)
- {
- dest->byte = ' ';
- dest->attrib = DCA_NORMAL;
- dest++;
- col++;
- }
+ debug_view_source *source = m_head;
+ m_head = source->m_next;
+ auto_free(&m_machine, source);
}
+
+ // reset the tail pointer and index
+ m_tail = NULL;
+ m_count = 0;
}
-/*-------------------------------------------------
- textbuf_view_notify - handle notification of
- updates to visible area
--------------------------------------------------*/
+//-------------------------------------------------
+// append - add a view_source to the end of the
+// list
+//-------------------------------------------------
-static void textbuf_view_notify(debug_view *view, view_notification type)
+void debug_view_source_list::append(debug_view_source &source)
{
- debug_view_textbuf *textdata = (debug_view_textbuf *)view->extra_data;
-
- if (type == VIEW_NOTIFY_VISIBLE_CHANGED)
- {
- /* if the bottom line is visible, just track the bottom */
- textdata->at_bottom = (view->total.y >= view->topleft.y && view->total.y <= view->topleft.y + view->visible.y);
+ // set the next and index values
+ source.m_next = NULL;
- /* otherwise, track the seqence number of the top line */
- if (!textdata->at_bottom)
- textdata->topseq = text_buffer_line_index_to_seqnum(textdata->textbuf, view->topleft.y);
- }
+ // append to the end
+ if (m_tail == NULL)
+ m_head = m_tail = &source;
+ else
+ m_tail->m_next = &source;
+ m_tail = &source;
+ m_count++;
}
+//-------------------------------------------------
+// match_device - find the first view that
+// matches the given device
+//-------------------------------------------------
-/***************************************************************************
- REGISTERS VIEW
-***************************************************************************/
-
-/*-------------------------------------------------
- registers_view_enumerate_subviews - enumerate
- all possible subviews for a registers view
--------------------------------------------------*/
-
-static const registers_subview_item *registers_view_enumerate_subviews(running_machine *machine)
+const debug_view_source *debug_view_source_list::match_device(device_t *device) const
{
- registers_subview_item *head = NULL;
- registers_subview_item **tailptr = &head;
- int curindex = 0;
-
- /* iterate over CPUs with program address spaces */
- device_state_interface *state = NULL;
- for (bool gotone = machine->devicelist.first(state); gotone; gotone = state->next(state))
- {
- registers_subview_item *subview = auto_alloc(machine, registers_subview_item);
-
- /* populate the subview */
- subview->next = NULL;
- subview->index = curindex++;
- subview->name.printf("CPU '%s' (%s)", state->device().tag(), state->device().name());
- subview->stateintf = state;
- state->device().interface(subview->execintf);
-
- /* add to the list */
- *tailptr = subview;
- tailptr = &subview->next;
- }
-
- return head;
+ for (debug_view_source *source = m_head; source != NULL; source = source->m_next)
+ if (device == source->m_device)
+ return source;
+ return m_head;
}
-/*-------------------------------------------------
- registers_view_alloc - allocate memory for the
- registers view
--------------------------------------------------*/
-
-static int registers_view_alloc(debug_view *view)
-{
- /* fail if no available subviews */
- if (view->machine->debugvw_data->registers_subviews == NULL)
- return FALSE;
-
- /* allocate memory */
- debug_view_registers *regdata = auto_alloc_clear(view->machine, debug_view_registers);
-
- /* default to the first subview */
- regdata->subview = view->machine->debugvw_data->registers_subviews;
-
- /* stash the extra data pointer */
- view->extra_data = regdata;
- return TRUE;
-}
+//**************************************************************************
+// DEBUG VIEW
+//**************************************************************************
-/*-------------------------------------------------
- registers_view_free - free memory for the
- registers view
--------------------------------------------------*/
+//-------------------------------------------------
+// debug_view - constructor
+//-------------------------------------------------
-static void registers_view_free(debug_view *view)
+debug_view::debug_view(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : m_next(NULL),
+ m_machine(machine),
+ m_type(type),
+ m_source(NULL),
+ m_source_list(machine),
+ m_osdupdate(osdupdate),
+ m_osdprivate(osdprivate),
+ m_visible(10,10),
+ m_total(10,10),
+ m_topleft(0,0),
+ m_cursor(0,0),
+ m_supports_cursor(false),
+ m_cursor_visible(false),
+ m_recompute(true),
+ m_update_level(0),
+ m_update_pending(true),
+ m_osd_update_pending(true),
+ m_viewdata(NULL),
+ m_viewdata_size(0)
{
- debug_view_registers *regdata = (debug_view_registers *)view->extra_data;
-
- /* free any memory we callocated */
- if (regdata != NULL)
- auto_free(view->machine, regdata);
- view->extra_data = NULL;
+ // allocate memory for the buffer
+ m_viewdata_size = m_visible.y * m_visible.x;
+ m_viewdata = auto_alloc_array(&machine, debug_view_char, m_viewdata_size);
}
-/*-------------------------------------------------
- registers_view_recompute - recompute all info
- for the registers view
--------------------------------------------------*/
+//-------------------------------------------------
+// ~debug_view - destructor
+//-------------------------------------------------
-static void registers_view_recompute(debug_view *view)
+debug_view::~debug_view()
{
- debug_view_registers *regdata = (debug_view_registers *)view->extra_data;
- int maxtaglen, maxvallen;
-
- /* reset the view parameters */
- view->topleft.y = 0;
- view->topleft.x = 0;
- view->total.y = 0;
- view->total.x = 0;
- regdata->divider = 0;
-
- /* add a cycles entry: cycles:99999999 */
- maxtaglen = 0;
- maxvallen = 0;
- if (regdata->subview->execintf != NULL)
- {
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = REG_CYCLES;
- regdata->reg[view->total.y].symbol.cpy("cycles");
- regdata->reg[view->total.y].vallen = 8;
- maxtaglen = regdata->reg[view->total.y].symbol.len();
- maxvallen = regdata->reg[view->total.y].vallen;
- view->total.y++;
- }
-
- /* add a beam entry: beamx:123 */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = REG_BEAMX;
- regdata->reg[view->total.y].symbol.cpy("beamx");
- regdata->reg[view->total.y].vallen = 3;
- maxtaglen = MAX(maxtaglen, regdata->reg[view->total.y].symbol.len());
- maxvallen = MAX(maxvallen, regdata->reg[view->total.y].vallen);
- view->total.y++;
-
- /* add a beam entry: beamy:456 */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = REG_BEAMY;
- regdata->reg[view->total.y].symbol.cpy("beamy");
- regdata->reg[view->total.y].vallen = 3;
- maxtaglen = MAX(maxtaglen, regdata->reg[view->total.y].symbol.len());
- maxvallen = MAX(maxvallen, regdata->reg[view->total.y].vallen);
- view->total.y++;
-
- /* add a beam entry: frame:123456 */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = REG_FRAME;
- regdata->reg[view->total.y].symbol.cpy("frame");
- regdata->reg[view->total.y].vallen = 6;
- maxtaglen = MAX(maxtaglen, regdata->reg[view->total.y].symbol.len());
- maxvallen = MAX(maxvallen, regdata->reg[view->total.y].vallen);
- view->total.y++;
-
- /* add a flags entry: flags:xxxxxxxx */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = STATE_GENFLAGS;
- regdata->reg[view->total.y].symbol.cpy("flags");
- regdata->reg[view->total.y].vallen = regdata->subview->stateintf->state_string_max_length(regdata->reg[view->total.y].regnum);
- maxtaglen = MAX(maxtaglen, regdata->reg[view->total.y].symbol.len());
- maxvallen = MAX(maxvallen, regdata->reg[view->total.y].vallen);
- view->total.y++;
-
- /* add a divider entry */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = 0;
- regdata->reg[view->total.y].regnum = REG_DIVIDER;
- view->total.y++;
-
- /* add all registers into it */
- for (const device_state_entry *entry = regdata->subview->stateintf->state_first(); entry != NULL; entry = entry->next())
- if (entry->visible())
- {
- /* note the register number and info */
- regdata->reg[view->total.y].lastval =
- regdata->reg[view->total.y].currval = regdata->subview->stateintf->state_value(entry->index());
- regdata->reg[view->total.y].regnum = entry->index();
- regdata->reg[view->total.y].symbol.cpy(entry->symbol());
- regdata->reg[view->total.y].vallen = regdata->subview->stateintf->state_string_max_length(entry->index());
- maxtaglen = MAX(maxtaglen, regdata->reg[view->total.y].symbol.len());
- maxvallen = MAX(maxvallen, regdata->reg[view->total.y].vallen);
- view->total.y++;
- }
-
- /* set the current divider and total cols */
- regdata->divider = 1 + maxtaglen + 1;
- view->total.x = 1 + maxtaglen + 2 + maxvallen + 1;
-
- /* no longer need to recompute */
- view->recompute = FALSE;
}
-/*-------------------------------------------------
- registers_view_update - update the contents of
- the register view
--------------------------------------------------*/
+//-------------------------------------------------
+// end_update - bracket a sequence of changes so
+// that only one update occurs
+//-------------------------------------------------
-static void registers_view_update(debug_view *view)
+void debug_view::end_update()
{
- screen_device *screen = view->machine->primary_screen;
- debug_view_registers *regdata = (debug_view_registers *)view->extra_data;
- debug_view_char *dest = view->viewdata;
- UINT64 total_cycles;
- UINT32 row, i;
-
- /* if our assumptions changed, revisit them */
- if (view->recompute)
- registers_view_recompute(view);
-
- /* cannot update if no active CPU */
- total_cycles = 0;
- if (regdata->subview->execintf != NULL)
- total_cycles = regdata->subview->execintf->total_cycles();
-
- /* loop over visible rows */
- for (row = 0; row < view->visible.y; row++)
+ /* if we hit zero, call the update function */
+ if (m_update_level == 1)
{
- UINT32 effrow = view->topleft.y + row;
- UINT32 col = 0;
-
- /* if this visible row is valid, add it to the buffer */
- if (effrow < view->total.y)
+ while (m_update_pending)
{
- debug_view_register *reg = &regdata->reg[effrow];
- UINT32 effcol = view->topleft.x;
- UINT8 attrib = DCA_NORMAL;
- UINT32 len = 0;
- astring valstr;
-
- /* get the effective string */
- if (reg->regnum >= REG_FRAME && reg->regnum <= REG_DIVIDER)
- {
- reg->lastval = reg->currval;
- switch (reg->regnum)
- {
- case REG_DIVIDER:
- reg->vallen = 0;
- reg->symbol.reset();
- for (i = 0; i < view->total.x; i++)
- reg->symbol.cat("-");
- break;
-
- case REG_CYCLES:
- if (regdata->subview->execintf != NULL)
- {
- reg->currval = regdata->subview->execintf->cycles_remaining();
- valstr.printf("%-8d", (UINT32)reg->currval);
- }
- break;
-
- case REG_BEAMX:
- if (screen != NULL)
- {
- reg->currval = screen->hpos();
- valstr.printf("%3d", (UINT32)reg->currval);
- }
- break;
-
- case REG_BEAMY:
- if (screen != NULL)
- {
- reg->currval = screen->vpos();
- valstr.printf("%3d", (UINT32)reg->currval);
- }
- break;
-
- case REG_FRAME:
- if (screen != NULL)
- {
- reg->currval = screen->frame_number();
- valstr.printf("%3d", (UINT32)reg->currval);
- }
- break;
- }
- }
- else
- {
- if (regdata->last_update != total_cycles)
- reg->lastval = reg->currval;
- reg->currval = regdata->subview->stateintf->state_value(reg->regnum);
- regdata->subview->stateintf->state_string(reg->regnum, valstr);
- }
+ // no longer pending, but flag for the OSD
+ m_update_pending = false;
+ m_osd_update_pending = true;
- /* see if we changed */
- if (reg->lastval != reg->currval)
- attrib = DCA_CHANGED;
-
- /* build up a string */
- char temp[256];
- if (reg->symbol.len() < regdata->divider - 1)
+ // resize the viewdata if needed
+ int size = m_visible.x * m_visible.y;
+ if (size > m_viewdata_size)
{
- memset(&temp[len], ' ', regdata->divider - 1 - reg->symbol.len());
- len += regdata->divider - 1 - reg->symbol.len();
+ m_viewdata_size = size;
+ auto_free(&m_machine, m_viewdata);
+ m_viewdata = auto_alloc_array(&m_machine, debug_view_char, m_viewdata_size);
}
- memcpy(&temp[len], reg->symbol.cstr(), reg->symbol.len());
- len += reg->symbol.len();
-
- temp[len++] = ' ';
- temp[len++] = ' ';
-
- memcpy(&temp[len], valstr.cstr(), reg->vallen);
- len += reg->vallen;
-
- temp[len++] = ' ';
- temp[len] = 0;
-
- /* copy data */
- while (col < view->visible.x && effcol < len)
- {
- dest->byte = temp[effcol++];
- dest->attrib = attrib | ((effcol <= regdata->divider) ? DCA_ANCILLARY : DCA_NORMAL);
- dest++;
- col++;
- }
- }
-
- /* fill the rest with blanks */
- while (col < view->visible.x)
- {
- dest->byte = ' ';
- dest->attrib = DCA_NORMAL;
- dest++;
- col++;
+ // update the view
+ view_update();
}
}
- /* remember the last update */
- regdata->last_update = total_cycles;
+ // decrement the level
+ m_update_level--;
}
-/*-------------------------------------------------
- registers_view_get_subview_list - return a
- linked list of subviews
--------------------------------------------------*/
+//-------------------------------------------------
+// flush_osd_updates - notify the OSD of any
+// pending updates
+//-------------------------------------------------
-const registers_subview_item *registers_view_get_subview_list(debug_view *view)
+void debug_view::flush_osd_updates()
{
- assert(view->type == DVT_REGISTERS);
- return view->machine->debugvw_data->registers_subviews;
+ if (m_osd_update_pending && m_osdupdate != NULL)
+ (*m_osdupdate)(*this, m_osdprivate);
+ m_osd_update_pending = false;
}
-/*-------------------------------------------------
- registers_view_get_subview - return the current
- subview index
--------------------------------------------------*/
+//-------------------------------------------------
+// set_visible_size - set the visible size in
+// rows and columns
+//-------------------------------------------------*/
-int registers_view_get_subview(debug_view *view)
+void debug_view::set_visible_size(debug_view_xy size)
{
- debug_view_registers *regdata = (debug_view_registers *)view->extra_data;
- const registers_subview_item *subview;
- int index = 0;
-
- assert(view->type == DVT_REGISTERS);
- debug_view_begin_update(view);
- debug_view_end_update(view);
-
- for (subview = view->machine->debugvw_data->registers_subviews; subview != NULL; subview = subview->next)
+ if (size.x != m_visible.x || size.y != m_visible.y)
{
- if (regdata->subview == subview)
- return index;
- index++;
+ begin_update();
+ m_visible = size;
+ m_update_pending = true;
+ view_notify(VIEW_NOTIFY_VISIBLE_CHANGED);
+ end_update();
}
- return 0;
}
-/*-------------------------------------------------
- registers_view_set_subview - select a new
- subview by index
--------------------------------------------------*/
+//-------------------------------------------------
+// set_visible_position - set the top left
+// position of the visible area in rows and
+// columns
+//-------------------------------------------------
-void registers_view_set_subview(debug_view *view, int index)
+void debug_view::set_visible_position(debug_view_xy pos)
{
- const registers_subview_item *subview = registers_view_get_subview_by_index(view->machine->debugvw_data->registers_subviews, index);
- debug_view_registers *regdata = (debug_view_registers *)view->extra_data;
-
- assert(view->type == DVT_REGISTERS);
- assert(subview != NULL);
- if (subview == NULL)
- return;
-
- /* handle a change */
- if (regdata->subview != subview)
+ if (pos.x != m_topleft.x || pos.y != m_topleft.y)
{
- debug_view_begin_update(view);
- regdata->subview = subview;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
+ begin_update();
+ m_topleft = pos;
+ m_update_pending = true;
+ view_notify(VIEW_NOTIFY_VISIBLE_CHANGED);
+ end_update();
}
}
+//-------------------------------------------------
+// set_cursor_position - set the current cursor
+// position as a row and column
+//-------------------------------------------------
-/***************************************************************************
- DISASSEMBLY VIEW
-***************************************************************************/
-
-/*-------------------------------------------------
- disasm_view_enumerate_subviews - enumerate
- all possible subviews for a disassembly view
--------------------------------------------------*/
-
-static const disasm_subview_item *disasm_view_enumerate_subviews(running_machine *machine)
+void debug_view::set_cursor_position(debug_view_xy pos)
{
- disasm_subview_item *head = NULL;
- disasm_subview_item **tailptr = &head;
- int curindex = 0;
-
- /* iterate over CPUs with program address spaces */
- device_execute_interface *exec = NULL;
- for (bool gotone = machine->devicelist.first(exec); gotone; gotone = exec->next(exec))
+ if (pos.x != m_cursor.x || pos.y != m_cursor.y)
{
- disasm_subview_item *subview = auto_alloc(machine, disasm_subview_item);
-
- /* populate the subview */
- subview->next = NULL;
- subview->index = curindex++;
- subview->name.printf("%s '%s'", exec->device().name(), exec->device().tag());
- subview->space = cpu_get_address_space(*exec, ADDRESS_SPACE_PROGRAM);
-
- /* add to the list */
- *tailptr = subview;
- tailptr = &subview->next;
- }
-
- return head;
-}
-
-
-/*-------------------------------------------------
- disasm_view_alloc - allocate disasm for the
- disassembly view
--------------------------------------------------*/
-
-static int disasm_view_alloc(debug_view *view)
-{
- debug_view_disasm *dasmdata;
- int total_comments = 0;
- device_t *cpu;
-
- /* fail if no available subviews */
- if (view->machine->debugvw_data->disasm_subviews == NULL)
- return FALSE;
-
- /* allocate disasm */
- dasmdata = auto_alloc_clear(view->machine, debug_view_disasm);
-
- /* default to the first subview */
- dasmdata->space = view->machine->debugvw_data->disasm_subviews->space;
-
- /* allocate the expression data */
- debug_view_expression_alloc(&dasmdata->expression);
-
- /* count the number of comments */
- for (cpu = view->machine->firstcpu; cpu != NULL; cpu = cpu_next(cpu))
- total_comments += debug_comment_get_count(cpu);
-
- /* initialize */
- dasmdata->right_column = (total_comments > 0) ? DASM_RIGHTCOL_COMMENTS : DASM_RIGHTCOL_RAW;
- dasmdata->backwards_steps = 3;
- dasmdata->dasm_width = DEFAULT_DASM_WIDTH;
-
- /* stash the extra data pointer */
- view->total.y = DEFAULT_DASM_LINES;
- view->extra_data = dasmdata;
-
- /* we support cursors */
- view->supports_cursor = TRUE;
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- disasm_view_free - free disasm for the
- disassembly view
--------------------------------------------------*/
-
-static void disasm_view_free(debug_view *view)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
-
- /* free any disasm we callocated */
- if (dasmdata != NULL)
- {
- debug_view_expression_free(&dasmdata->expression);
- if (dasmdata->byteaddress != NULL)
- auto_free(view->machine, dasmdata->byteaddress);
- if (dasmdata->dasm != NULL)
- auto_free(view->machine, dasmdata->dasm);
- auto_free(view->machine, dasmdata);
- }
- view->extra_data = NULL;
-}
-
-
-/*-------------------------------------------------
- disasm_view_notify - handle notification of
- updates to cursor changes
--------------------------------------------------*/
-
-static void disasm_view_notify(debug_view *view, view_notification type)
-{
- if (type == VIEW_NOTIFY_CURSOR_CHANGED)
- adjust_visible_y_for_cursor(view);
-}
-
-
-/*-------------------------------------------------
- disasm_view_char - handle a character typed
- within the current view
--------------------------------------------------*/
-
-static void disasm_view_char(debug_view *view, int chval)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- debug_view_xy origcursor = view->cursor;
- UINT8 end_buffer = 3;
- INT32 temp;
-
- switch (chval)
- {
- case DCH_UP:
- if (view->cursor.y > 0)
- view->cursor.y--;
- break;
-
- case DCH_DOWN:
- if (view->cursor.y < view->total.y - 1)
- view->cursor.y++;
- break;
-
- case DCH_PUP:
- temp = view->cursor.y - (view->visible.y - end_buffer);
- if (temp < 0)
- view->cursor.y = 0;
- else
- view->cursor.y = temp;
- break;
-
- case DCH_PDOWN:
- temp = view->cursor.y + (view->visible.y - end_buffer);
- if (temp > view->total.y - 1)
- view->cursor.y = view->total.y - 1;
- else
- view->cursor.y = temp;
- break;
-
- case DCH_HOME: /* set the active column to the PC */
- {
- offs_t pc = memory_address_to_byte(dasmdata->space, cpu_get_pc(dasmdata->space->cpu)) & dasmdata->space->logbytemask;
- int curline;
-
- /* figure out which row the pc is on */
- for (curline = 0; curline < dasmdata->allocated.y; curline++)
- if (dasmdata->byteaddress[curline] == pc)
- view->cursor.y = curline;
- break;
- }
-
- case DCH_CTRLHOME:
- view->cursor.y = 0;
- break;
-
- case DCH_CTRLEND:
- view->cursor.y = view->total.y - 1;
- break;
- }
-
- /* send a cursor changed notification */
- if (view->cursor.y != origcursor.y)
- {
- debug_view_begin_update(view);
- disasm_view_notify(view, VIEW_NOTIFY_CURSOR_CHANGED);
- view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- disasm_view_find_pc_backwards - back up the
- specified numberof instructions from the given
- PC
--------------------------------------------------*/
-
-static offs_t disasm_view_find_pc_backwards(const address_space *space, offs_t targetpc, int numinstrs)
-{
- cpu_device *cpudevice = downcast<cpu_device *>(space->cpu);
- assert(cpudevice != NULL);
-
- int minlen = memory_byte_to_address(space, cpudevice->min_opcode_bytes());
- int maxlen = memory_byte_to_address(space, cpudevice->max_opcode_bytes());
- offs_t targetpcbyte = memory_address_to_byte(space, targetpc) & space->logbytemask;
- offs_t lastgoodpc = targetpc;
- offs_t fillpcbyte, curpc;
- UINT8 opbuf[1024], argbuf[1024];
- char dasmbuffer[100];
-
- /* compute the increment */
- if (minlen == 0) minlen = 1;
- if (maxlen == 0) maxlen = 1;
-
- /* start off numinstrs back */
- curpc = targetpc - minlen * numinstrs;
- if (curpc > targetpc)
- curpc = 0;
-
- /* loop until we find what we are looking for */
- fillpcbyte = targetpcbyte;
- while (1)
- {
- offs_t curpcbyte = memory_address_to_byte(space, curpc) & space->logbytemask;
- offs_t scanpc;
- int instcount = 0;
- int instlen;
-
- /* fill the buffer up to the target */
- while (curpcbyte < fillpcbyte)
- {
- fillpcbyte--;
- opbuf[1000 + fillpcbyte - targetpcbyte] = debug_read_opcode(space, fillpcbyte, 1, FALSE);
- argbuf[1000 + fillpcbyte - targetpcbyte] = debug_read_opcode(space, fillpcbyte, 1, TRUE);
- }
-
- /* loop until we get past the target instruction */
- for (scanpc = curpc; scanpc < targetpc; scanpc += instlen)
- {
- offs_t scanpcbyte = memory_address_to_byte(space, scanpc) & space->logbytemask;
- offs_t physpcbyte = scanpcbyte;
-
- /* get the disassembly, but only if mapped */
- instlen = 1;
- if (debug_cpu_translate(space, TRANSLATE_FETCH, &physpcbyte))
- instlen = debug_cpu_disassemble(space->cpu, dasmbuffer, scanpc, &opbuf[1000 + scanpcbyte - targetpcbyte], &argbuf[1000 + scanpcbyte - targetpcbyte]) & DASMFLAG_LENGTHMASK;
-
- /* count this one */
- instcount++;
- }
-
- /* if we ended up right on targetpc, this is a good candidate */
- if (scanpc == targetpc && instcount <= numinstrs)
- lastgoodpc = curpc;
-
- /* we're also done if we go back too far */
- if (targetpc - curpc >= numinstrs * maxlen)
- break;
-
- /* and if we hit 0, we're done */
- if (curpc == 0)
- break;
-
- /* back up one more and try again */
- curpc -= minlen;
- if (curpc > targetpc)
- curpc = 0;
+ begin_update();
+ m_cursor = pos;
+ m_update_pending = true;
+ view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
+ end_update();
}
-
- return lastgoodpc;
-}
-
-
-/*-------------------------------------------------
- disasm_view_generate_bytes - generate the
- opcode byte values
--------------------------------------------------*/
-
-static void disasm_view_generate_bytes(const address_space *space, offs_t pcbyte, int numbytes, int minbytes, char *string, int maxchars, int encrypted)
-{
- int byte, offset = 0;
-
- /* output the first value */
- if (maxchars >= 2 * minbytes)
- offset = sprintf(string, "%s", core_i64_hex_format(debug_read_opcode(space, pcbyte, minbytes, FALSE), minbytes * 2));
-
- /* output subsequent values */
- for (byte = minbytes; byte < numbytes && offset + 1 + 2 * minbytes < maxchars; byte += minbytes)
- offset += sprintf(&string[offset], " %s", core_i64_hex_format(debug_read_opcode(space, pcbyte + byte, minbytes, encrypted), minbytes * 2));
-
- /* if we ran out of room, indicate more */
- string[maxchars - 1] = 0;
- if (byte < numbytes && maxchars > 3)
- string[maxchars - 2] = string[maxchars - 3] = string[maxchars - 4] = '.';
}
-/*-------------------------------------------------
- disasm_view_recompute - recompute selected info
- for the disassembly view
--------------------------------------------------*/
+//-------------------------------------------------
+// set_cursor_visible - set the visible state of
+// the cursor
+//-------------------------------------------------
-static int disasm_view_recompute(debug_view *view, offs_t pc, int startline, int lines)
+void debug_view::set_cursor_visible(bool visible)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- const address_space *space = dasmdata->space;
- int minbytes, maxbytes, maxbytes_clamped;
- int changed = FALSE;
- int line;
-
- /* determine how many characters we need for an address and set the divider */
- dasmdata->divider1 = 1 + space->logaddrchars + 1;
-
- /* assume a fixed number of characters for the disassembly */
- dasmdata->divider2 = dasmdata->divider1 + 1 + dasmdata->dasm_width + 1;
-
- /* determine how many bytes we might need to display */
- cpu_device *cpudevice = downcast<cpu_device *>(space->cpu);
- assert(cpudevice != NULL);
- minbytes = cpudevice->min_opcode_bytes();
- maxbytes = cpudevice->max_opcode_bytes();
-
- /* ensure that the PC is aligned to the minimum opcode size */
- pc &= ~memory_byte_to_address_end(space, minbytes - 1);
-
- /* set the width of the third column according to display mode */
- if (dasmdata->right_column == DASM_RIGHTCOL_RAW || dasmdata->right_column == DASM_RIGHTCOL_ENCRYPTED)
+ if (visible != m_cursor_visible)
{
- maxbytes_clamped = MIN(maxbytes, DASM_MAX_BYTES);
- view->total.x = dasmdata->divider2 + 1 + 2 * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1;
+ begin_update();
+ m_cursor_visible = visible;
+ m_update_pending = true;
+ view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
+ end_update();
}
- else if (dasmdata->right_column == DASM_RIGHTCOL_COMMENTS)
- view->total.x = dasmdata->divider2 + 1 + 50; /* DEBUG_COMMENT_MAX_LINE_LENGTH */
- else
- view->total.x = dasmdata->divider2 + 1;
-
- /* reallocate memory if we don't have enough */
- if (dasmdata->allocated.x < view->total.x || dasmdata->allocated.y < view->total.y)
- {
- /* update our values */
- dasmdata->allocated.x = view->total.x;
- dasmdata->allocated.y = view->total.y;
-
- /* allocate address array */
- auto_free(view->machine, dasmdata->byteaddress);
- dasmdata->byteaddress = auto_alloc_array(view->machine, offs_t, dasmdata->allocated.y);
-
- /* allocate disassembly buffer */
- auto_free(view->machine, dasmdata->dasm);
- dasmdata->dasm = auto_alloc_array(view->machine, char, dasmdata->allocated.x * dasmdata->allocated.y);
- }
-
- /* iterate over lines */
- for (line = 0; line < lines; line++)
- {
- int instr = startline + line;
- char *destbuf = &dasmdata->dasm[instr * dasmdata->allocated.x];
- char buffer[100], oldbuf[100];
- offs_t pcbyte, physpcbyte;
- int numbytes = 0;
-
- /* convert PC to a byte offset */
- pcbyte = memory_address_to_byte(space, pc) & space->logbytemask;
-
- /* save a copy of the previous line as a backup if we're only doing one line */
- if (lines == 1)
- strncpy(oldbuf, destbuf, MIN(sizeof(oldbuf), dasmdata->allocated.x));
-
- /* convert back and set the address of this instruction */
- dasmdata->byteaddress[instr] = pcbyte;
- sprintf(&destbuf[0], " %s ", core_i64_hex_format(memory_byte_to_address(space, pcbyte), space->logaddrchars));
-
- /* make sure we can translate the address, and then disassemble the result */
- physpcbyte = pcbyte;
- if (debug_cpu_translate(space, TRANSLATE_FETCH_DEBUG, &physpcbyte))
- {
- UINT8 opbuf[64], argbuf[64];
-
- /* fetch the bytes up to the maximum */
- for (numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, FALSE);
- argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, TRUE);
- }
-
- /* disassemble the result */
- pc += numbytes = debug_cpu_disassemble(space->cpu, buffer, pc & space->logaddrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
- }
- else
- strcpy(buffer, "<unmapped>");
-
- /* append the disassembly to the buffer */
- sprintf(&destbuf[dasmdata->divider1 + 1], "%-*s ", dasmdata->dasm_width, buffer);
-
- /* output the right column */
- if (dasmdata->right_column == DASM_RIGHTCOL_RAW || dasmdata->right_column == DASM_RIGHTCOL_ENCRYPTED)
- {
- /* get the bytes */
- numbytes = memory_address_to_byte(space, numbytes) & space->logbytemask;
- disasm_view_generate_bytes(space, pcbyte, numbytes, minbytes, &destbuf[dasmdata->divider2], dasmdata->allocated.x - dasmdata->divider2, dasmdata->right_column == DASM_RIGHTCOL_ENCRYPTED);
- }
- else if (dasmdata->right_column == DASM_RIGHTCOL_COMMENTS)
- {
- offs_t comment_address = memory_byte_to_address(space, dasmdata->byteaddress[instr]);
- const char *text;
-
- /* get and add the comment, if present */
- text = debug_comment_get_text(space->cpu, comment_address, debug_comment_get_opcode_crc32(space->cpu, comment_address));
- if (text != NULL)
- sprintf(&destbuf[dasmdata->divider2], "// %.*s", dasmdata->allocated.x - dasmdata->divider2 - 1, text);
- }
-
- /* see if the line changed at all */
- if (lines == 1 && strncmp(oldbuf, destbuf, MIN(sizeof(oldbuf), dasmdata->allocated.x)) != 0)
- changed = TRUE;
- }
-
- /* update opcode base information */
- dasmdata->last_direct_decrypted = space->direct.decrypted;
- dasmdata->last_direct_raw = space->direct.raw;
- dasmdata->last_change_count = debug_comment_all_change_count(space->machine);
-
- /* now longer need to recompute */
- view->recompute = FALSE;
- return changed;
}
-/*-------------------------------------------------
- disasm_view_update - update the contents of
- the disassembly view
--------------------------------------------------*/
+//-------------------------------------------------
+// set_subview - set the current subview
+//-------------------------------------------------
-static void disasm_view_update(debug_view *view)
+void debug_view::set_source(const debug_view_source &source)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- const address_space *space = dasmdata->space;
- debug_view_char *dest = view->viewdata;
- int recomputed_this_time = FALSE;
- offs_t pc, pcbyte;
- EXPRERR exprerr;
- UINT32 row;
-
- /* no space, do nothing */
- if (space == NULL)
- return;
- pc = cpu_get_pc(space->cpu);
- pcbyte = memory_address_to_byte(space, pc) & space->logbytemask;
-
- /* if our expression is dirty, fix it */
- if (dasmdata->expression.dirty)
+ if (&source != m_source)
{
- parsed_expression *expr;
-
- /* parse the new expression */
- exprerr = expression_parse(dasmdata->expression.string, debug_cpu_get_symtable(space->cpu), &debug_expression_callbacks, space->machine, &expr);
-
- /* if it worked, update the expression */
- if (exprerr == EXPRERR_NONE)
- {
- if (dasmdata->expression.parsed != NULL)
- expression_free(dasmdata->expression.parsed);
- dasmdata->expression.parsed = expr;
- }
-
- /* always recompute if the expression is dirty */
- view->recompute = TRUE;
- }
-
- /* if we're tracking a value, make sure it is visible */
- if (dasmdata->expression.parsed != NULL)
- {
- UINT64 result;
-
- /* recompute the value of the expression */
- exprerr = expression_execute(dasmdata->expression.parsed, &result);
- if (exprerr == EXPRERR_NONE && result != dasmdata->expression.result)
- {
- offs_t resultbyte = memory_address_to_byte(space, result) & space->logbytemask;
-
- /* update the result */
- dasmdata->expression.result = result;
-
- /* see if the new result is an address we already have */
- for (row = 0; row < dasmdata->allocated.y; row++)
- if (dasmdata->byteaddress[row] == resultbyte)
- break;
-
- /* if we didn't find it, or if it's really close to the bottom, recompute */
- if (row == dasmdata->allocated.y || row >= view->total.y - view->visible.y)
- view->recompute = TRUE;
-
- /* otherwise, if it's not visible, adjust the view so it is */
- else if (row < view->topleft.y || row >= view->topleft.y + view->visible.y - 2)
- view->topleft.y = (row > 3) ? row - 3 : 0;
- }
-
- /* no longer dirty */
- dasmdata->expression.dirty = FALSE;
- }
-
- /* if the opcode base has changed, rework things */
- if (space->direct.decrypted != dasmdata->last_direct_decrypted || space->direct.raw != dasmdata->last_direct_raw)
- view->recompute = TRUE;
-
- /* if the comments have changed, redo it */
- if (dasmdata->last_change_count != debug_comment_all_change_count(space->machine))
- view->recompute = TRUE;
-
- /* if we need to recompute, do it */
-recompute:
- if (view->recompute)
- {
- /* recompute the view */
- if (dasmdata->byteaddress != NULL && dasmdata->last_change_count != debug_comment_all_change_count(space->machine))
- {
- /* smoosh us against the left column, but not the top row */
- view->topleft.x = 0;
-
- /* recompute from where we last recomputed! */
- disasm_view_recompute(view, memory_byte_to_address(space, dasmdata->byteaddress[0]), 0, view->total.y);
- }
- else
- {
- /* determine the addresses of what we will display */
- offs_t backpc = disasm_view_find_pc_backwards(space, (UINT32)dasmdata->expression.result, dasmdata->backwards_steps);
-
- /* put ourselves back in the top left */
- view->topleft.y = 0;
- view->topleft.x = 0;
-
- disasm_view_recompute(view, backpc, 0, view->total.y);
- }
- recomputed_this_time = TRUE;
- }
-
- /* figure out the row where the PC is and recompute the disassembly */
- if (pcbyte != dasmdata->last_pcbyte)
- {
- /* find the row with the PC on it */
- for (row = 0; row < view->visible.y; row++)
- {
- UINT32 effrow = view->topleft.y + row;
- if (effrow >= dasmdata->allocated.y)
- break;
- if (pcbyte == dasmdata->byteaddress[effrow])
- {
- /* see if we changed */
- int changed = disasm_view_recompute(view, pc, effrow, 1);
- if (changed && !recomputed_this_time)
- {
- view->recompute = TRUE;
- goto recompute;
- }
-
- /* set the effective row and PC */
- view->cursor.y = effrow;
- }
- }
- dasmdata->last_pcbyte = pcbyte;
- }
-
- /* loop over visible rows */
- for (row = 0; row < view->visible.y; row++)
- {
- UINT32 effrow = view->topleft.y + row;
- UINT8 attrib = DCA_NORMAL;
- debug_cpu_breakpoint *bp;
- UINT32 col = 0;
-
- /* if this visible row is valid, add it to the buffer */
- if (effrow < dasmdata->allocated.y)
- {
- const char *data = &dasmdata->dasm[effrow * dasmdata->allocated.x];
- UINT32 effcol = view->topleft.x;
- UINT32 len = 0;
-
- /* if we're on the line with the PC, recompute and hilight it */
- if (pcbyte == dasmdata->byteaddress[effrow])
- attrib = DCA_CURRENT;
-
- /* if we're on a line with a breakpoint, tag it changed */
- else
- {
- const cpu_debug_data *cpuinfo = cpu_get_debug_data(space->cpu);
- for (bp = cpuinfo->bplist; bp != NULL; bp = bp->next)
- if (dasmdata->byteaddress[effrow] == (memory_address_to_byte(space, bp->address) & space->logbytemask))
- attrib = DCA_CHANGED;
- }
-
- /* if we're on the active column and everything is couth, highlight it */
- if (view->cursor_visible && effrow == view->cursor.y)
- attrib |= DCA_SELECTED;
-
- /* get the effective string */
- len = (UINT32)strlen(data);
-
- /* copy data */
- while (col < view->visible.x && effcol < len)
- {
- dest->byte = data[effcol++];
- dest->attrib = (effcol <= dasmdata->divider1 || effcol >= dasmdata->divider2) ? (attrib | DCA_ANCILLARY) : attrib;
-
- /* comments are just green for now - maybe they shouldn't even be this? */
- if (effcol >= dasmdata->divider2 && dasmdata->right_column == DASM_RIGHTCOL_COMMENTS)
- attrib |= DCA_COMMENT;
-
- dest++;
- col++;
- }
- }
-
- /* fill the rest with blanks */
- while (col < view->visible.x)
- {
- dest->byte = ' ';
- dest->attrib = (effrow < view->total.y) ? (attrib | DCA_ANCILLARY) : attrib;
- dest++;
- col++;
- }
+ begin_update();
+ m_source = &source;
+ m_update_pending = true;
+ view_notify(VIEW_NOTIFY_SOURCE_CHANGED);
+ end_update();
}
}
-/*-------------------------------------------------
- disasm_view_get_subview_list - return a linked
- list of subviews
--------------------------------------------------*/
+//-------------------------------------------------
+// adjust_visible_x_for_cursor - adjust a view's
+// visible X position to ensure the cursor is
+// visible
+//-------------------------------------------------
-const disasm_subview_item *disasm_view_get_subview_list(debug_view *view)
+void debug_view::adjust_visible_x_for_cursor()
{
- assert(view->type == DVT_DISASSEMBLY);
- return view->machine->debugvw_data->disasm_subviews;
-}
-
-
-/*-------------------------------------------------
- disasm_view_get_subview - return the current
- subview index
--------------------------------------------------*/
-
-int disasm_view_get_subview(debug_view *view)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- const disasm_subview_item *subview;
- int index = 0;
-
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
-
- for (subview = view->machine->debugvw_data->disasm_subviews; subview != NULL; subview = subview->next)
- {
- if (subview->space == dasmdata->space)
- return index;
- index++;
- }
- return 0;
+ if (m_cursor.x < m_topleft.x)
+ m_topleft.x = m_cursor.x;
+ else if (m_cursor.x >= m_topleft.x + m_visible.x - 1)
+ m_topleft.x = m_cursor.x - m_visible.x + 2;
}
-/*-------------------------------------------------
- disasm_view_get_expression - return the
- expression string describing the home address
--------------------------------------------------*/
+//-------------------------------------------------
+// adjust_visible_y_for_cursor - adjust a view's
+// visible Y position to ensure the cursor is
+// visible
+//-------------------------------------------------
-const char *disasm_view_get_expression(debug_view *view)
+void debug_view::adjust_visible_y_for_cursor()
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return dasmdata->expression.string;
+ if (m_cursor.y < m_topleft.y)
+ m_topleft.y = m_cursor.y;
+ else if (m_cursor.y >= m_topleft.y + m_visible.y - 1)
+ m_topleft.y = m_cursor.y - m_visible.y + 2;
}
-/*-------------------------------------------------
- disasm_view_get_right_column - return the
- contents of the right column
--------------------------------------------------*/
+//-------------------------------------------------
+// view_notify - handle notification of updates
+//-------------------------------------------------
-disasm_right_column disasm_view_get_right_column(debug_view *view)
+void debug_view::view_notify(debug_view_notification type)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return dasmdata->right_column;
+ // default does nothing
}
-/*-------------------------------------------------
- disasm_view_get_backward_steps - return the
- number of instructions displayed before the
- home address
--------------------------------------------------*/
+//-------------------------------------------------
+// view_char - handle a character typed within
+// the current view
+//-------------------------------------------------
-UINT32 disasm_view_get_backward_steps(debug_view *view)
+void debug_view::view_char(int chval)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return dasmdata->backwards_steps;
+ // default does nothing
}
-/*-------------------------------------------------
- disasm_view_get_disasm_width - return the
- width in characters of the main disassembly
- section
--------------------------------------------------*/
-UINT32 disasm_view_get_disasm_width(debug_view *view)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return dasmdata->dasm_width;
-}
+//**************************************************************************
+// DEBUG VIEW MANAGER
+//**************************************************************************
+//-------------------------------------------------
+// debug_view_manager - constructor
+//-------------------------------------------------
-/*-------------------------------------------------
- disasm_view_get_selected_address - return the
- PC of the currently selected address in the
- view
--------------------------------------------------*/
-
-offs_t disasm_view_get_selected_address(debug_view *view)
+debug_view_manager::debug_view_manager(running_machine &machine)
+ : m_machine(machine),
+ m_viewlist(NULL)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- assert(view->type == DVT_DISASSEMBLY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memory_byte_to_address(dasmdata->space, dasmdata->byteaddress[view->cursor.y]);
}
-/*-------------------------------------------------
- disasm_view_set_subview - select a new subview
- by index
--------------------------------------------------*/
+//-------------------------------------------------
+// ~debug_view_manager - destructor
+//-------------------------------------------------
-void disasm_view_set_subview(debug_view *view, int index)
+debug_view_manager::~debug_view_manager()
{
- const disasm_subview_item *subview = disasm_view_get_subview_by_index(view->machine->debugvw_data->disasm_subviews, index);
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
-
- assert(view->type == DVT_DISASSEMBLY);
- assert(subview != NULL);
- if (subview == NULL)
- return;
-
- /* handle a change */
- if (subview->space != dasmdata->space)
+ while (m_viewlist != NULL)
{
- debug_view_begin_update(view);
- dasmdata->space = subview->space;
-
- /* we need to recompute the expression in the context of the new space's CPU */
- dasmdata->expression.dirty = TRUE;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
+ debug_view *oldhead = m_viewlist;
+ m_viewlist = oldhead->m_next;
+ auto_free(&m_machine, oldhead);
}
}
-/*-------------------------------------------------
- disasm_view_set_expression - set the
- expression string describing the home address
--------------------------------------------------*/
+//-------------------------------------------------
+// alloc_view - create a new view
+//-------------------------------------------------
-void disasm_view_set_expression(debug_view *view, const char *expression)
+debug_view *debug_view_manager::alloc_view(debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
-
- assert(view->type == DVT_DISASSEMBLY);
- assert(expression != NULL);
-
- debug_view_begin_update(view);
- debug_view_expression_set(&dasmdata->expression, expression);
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
-}
-
-
-/*-------------------------------------------------
- disasm_view_set_right_column - set the
- contents of the right column
--------------------------------------------------*/
-
-void disasm_view_set_right_column(debug_view *view, disasm_right_column contents)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
-
- assert(view->type == DVT_DISASSEMBLY);
- assert(contents == DASM_RIGHTCOL_RAW || contents == DASM_RIGHTCOL_ENCRYPTED || contents == DASM_RIGHTCOL_COMMENTS);
-
- if (contents != dasmdata->right_column)
+ switch (type)
{
- debug_view_begin_update(view);
- dasmdata->right_column = contents;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
+ case DVT_CONSOLE:
+ return append(auto_alloc(&m_machine, debug_view_console(m_machine, osdupdate, osdprivate)));
+ case DVT_STATE:
+ return append(auto_alloc(&m_machine, debug_view_state(m_machine, osdupdate, osdprivate)));
-/*-------------------------------------------------
- disasm_view_set_backward_steps - set the
- number of instructions displayed before the
- home address
--------------------------------------------------*/
+ case DVT_DISASSEMBLY:
+ return append(auto_alloc(&m_machine, debug_view_disasm(m_machine, osdupdate, osdprivate)));
-void disasm_view_set_backward_steps(debug_view *view, UINT32 steps)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
+ case DVT_MEMORY:
+ return append(auto_alloc(&m_machine, debug_view_memory(m_machine, osdupdate, osdprivate)));
- assert(view->type == DVT_DISASSEMBLY);
+ case DVT_LOG:
+ return append(auto_alloc(&m_machine, debug_view_log(m_machine, osdupdate, osdprivate)));
- if (steps != dasmdata->backwards_steps)
- {
- debug_view_begin_update(view);
- dasmdata->backwards_steps = steps;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
+ case DVT_TIMERS:
+// return append(auto_alloc(&m_machine, debug_view_timers(m_machine, osdupdate, osdprivate)));
-
-/*-------------------------------------------------
- disasm_view_set_disasm_width - set the
- width in characters of the main disassembly
- section
--------------------------------------------------*/
-
-void disasm_view_set_disasm_width(debug_view *view, UINT32 width)
-{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
-
- assert(view->type == DVT_DISASSEMBLY);
-
- if (width != dasmdata->dasm_width)
- {
- debug_view_begin_update(view);
- dasmdata->dasm_width = width;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
+ case DVT_ALLOCS:
+// return append(auto_alloc(&m_machine, debug_view_allocs(m_machine, osdupdate, osdprivate)));
+
+ default:
+ fatalerror("Attempt to create invalid debug view type %d\n", type);
}
+ return NULL;
}
-/*-------------------------------------------------
- disasm_view_set_selected_address - set the
- PC of the currently selected address in the
- view
--------------------------------------------------*/
+//-------------------------------------------------
+// free_view - free a view
+//-------------------------------------------------
-void disasm_view_set_selected_address(debug_view *view, offs_t address)
+void debug_view_manager::free_view(debug_view &view)
{
- debug_view_disasm *dasmdata = (debug_view_disasm *)view->extra_data;
- offs_t byteaddress = memory_address_to_byte(dasmdata->space, address) & dasmdata->space->logbytemask;
- int line;
-
- assert(view->type == DVT_DISASSEMBLY);
-
- for (line = 0; line < view->total.y; line++)
- if (dasmdata->byteaddress[line] == byteaddress)
+ // free us but only if we're in the list
+ for (debug_view **viewptr = &m_viewlist; *viewptr != NULL; viewptr = &(*viewptr)->m_next)
+ if (*viewptr == &view)
{
- view->cursor.y = line;
- debug_view_set_cursor_position(view, view->cursor);
+ *viewptr = view.m_next;
+ auto_free(&m_machine, &view);
break;
}
}
+//-------------------------------------------------
+// update_all - force all views to refresh
+//-------------------------------------------------
-/***************************************************************************
- MEMORY VIEW
-***************************************************************************/
-
-/*-------------------------------------------------
- memory_view_enumerate_subviews - enumerate
- all possible subviews for a memory view
--------------------------------------------------*/
-
-static const memory_subview_item *memory_view_enumerate_subviews(running_machine *machine)
+void debug_view_manager::update_all(debug_view_type type)
{
- memory_subview_item *head = NULL;
- memory_subview_item **tailptr = &head;
- int curindex = 0;
-
- /* first add all the device's address spaces */
- device_memory_interface *memintf = NULL;
- for (bool gotone = machine->devicelist.first(memintf); gotone; gotone = memintf->next(memintf))
- for (int spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
- {
- const address_space *space = memintf->space(spacenum);
- if (space != NULL)
- {
- memory_subview_item *subview = auto_alloc(machine, memory_subview_item);
-
- /* populate the subview */
- subview->next = NULL;
- subview->index = curindex++;
- subview->name.printf("%s '%s' %s space memory", memintf->device().name(), memintf->device().tag(), space->name);
- subview->space = space;
- subview->endianness = space->endianness;
- subview->prefsize = space->dbits / 8;
-
- /* add to the list */
- *tailptr = subview;
- tailptr = &subview->next;
- }
- }
-
- /* then add all the memory regions */
- for (const region_info *region = machine->regionlist.first(); region != NULL; region = region->next())
- {
- memory_subview_item *subview = auto_alloc(machine, memory_subview_item);
-
- /* populate the subview */
- subview->next = NULL;
- subview->index = curindex++;
- subview->name.printf("Region '%s'", region->name.cstr());
- subview->base = *region;
- subview->length = region->bytes();
- subview->offsetxor = NATIVE_ENDIAN_VALUE_LE_BE(region->width() - 1, 0);
- subview->endianness = region->endianness();
- subview->prefsize = MIN(region->width(), 8);
-
- /* add to the list */
- *tailptr = subview;
- tailptr = &subview->next;
- }
-
- /* finally add all global array symbols */
- for (int itemnum = 0; itemnum < 10000; itemnum++)
- {
- /* stop when we run out of items */
- UINT32 valsize, valcount;
- void *base;
- const char *name = state_save_get_indexed_item(machine, itemnum, &base, &valsize, &valcount);
- if (name == NULL)
- break;
-
- /* if this is a single-entry global, add it */
- if (valcount > 1 && strstr(name, "globals/"))
- {
- memory_subview_item *subview = auto_alloc(machine, memory_subview_item);
-
- /* populate the subview */
- subview->next = NULL;
- subview->index = curindex++;
- subview->name.cpy(strrchr(name, '/') + 1);
- subview->base = base;
- subview->length = valcount * valsize;
- subview->prefsize = MIN(valsize, 8);
-
- /* add to the list */
- *tailptr = subview;
- tailptr = &subview->next;
- }
- }
-
- return head;
-}
-
-
-/*-------------------------------------------------
- memory_view_alloc - allocate memory for the
- memory view
--------------------------------------------------*/
-
-static int memory_view_alloc(debug_view *view)
-{
- const memory_subview_item *subviews = memory_view_enumerate_subviews(view->machine);
- debug_view_memory *memdata;
-
- /* if no subviews, fail */
- if (subviews == NULL)
- return FALSE;
-
- /* allocate memory */
- memdata = auto_alloc_clear(view->machine, debug_view_memory);
- memdata->subviewlist = subviews;
-
- /* allocate the expression data */
- debug_view_expression_alloc(&memdata->expression);
-
- /* stash the extra data pointer */
- view->extra_data = memdata;
-
- /* we support cursors */
- view->supports_cursor = TRUE;
-
- /* default to the first subview */
- memdata->desc = memdata->subviewlist;
-
- /* start out with 16 bytes in a single column and ASCII displayed */
- memdata->bytes_per_chunk = memdata->desc->prefsize;
- memdata->chunks_per_row = 16 / memdata->desc->prefsize;
- memdata->bytes_per_row = memdata->bytes_per_chunk * memdata->chunks_per_row;
- memdata->ascii_view = TRUE;
-
- return TRUE;
+ // loop over each view and force an update
+ for (debug_view *view = m_viewlist; view != NULL; view = view->next())
+ if (type == DVT_NONE || type == view->type())
+ view->force_update();
}
-/*-------------------------------------------------
- memory_view_free - free memory for the
- memory view
--------------------------------------------------*/
+//-------------------------------------------------
+// flush_osd_updates - flush all pending OSD
+// updates
+//-------------------------------------------------
-static void memory_view_free(debug_view *view)
+void debug_view_manager::flush_osd_updates()
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- /* free any memory we allocated */
- if (memdata != NULL)
- {
- while (memdata->subviewlist != NULL)
- {
- memory_subview_item *item = (memory_subview_item *)memdata->subviewlist;
- memdata->subviewlist = item->next;
- auto_free(view->machine, item);
- }
- debug_view_expression_free(&memdata->expression);
- auto_free(view->machine, memdata);
- }
- view->extra_data = NULL;
-}
-
-
-/*-------------------------------------------------
- memory_view_notify - handle notification of
- updates to cursor changes
--------------------------------------------------*/
-
-static void memory_view_notify(debug_view *view, view_notification type)
-{
- if (type == VIEW_NOTIFY_CURSOR_CHANGED)
- {
- offs_t address;
- UINT8 shift;
-
- /* normalize the cursor */
- memory_view_get_cursor_pos(view, &address, &shift);
- memory_view_set_cursor_pos(view, address, shift);
- }
+ for (debug_view *view = m_viewlist; view != NULL; view = view->m_next)
+ view->flush_osd_updates();
}
-/*-------------------------------------------------
- memory_view_update - update the contents of
- the memory view
--------------------------------------------------*/
+//-------------------------------------------------
+// append - append a view to the end of our list
+//-------------------------------------------------
-static void memory_view_update(debug_view *view)
+debug_view *debug_view_manager::append(debug_view *view)
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const address_space *space = memdata->desc->space;
- const memory_view_pos *posdata;
- UINT32 row;
-
- /* if we need to recompute, do it now */
- if (memory_view_needs_recompute(view))
- memory_view_recompute(view);
-
- /* get positional data */
- posdata = &memory_pos_table[memdata->bytes_per_chunk];
-
- /* loop over visible rows */
- for (row = 0; row < view->visible.y; row++)
- {
- debug_view_char *destmin = view->viewdata + row * view->visible.x;
- debug_view_char *destmax = destmin + view->visible.x;
- debug_view_char *destrow = destmin - view->topleft.x;
- UINT32 effrow = view->topleft.y + row;
- debug_view_char *dest;
- int ch, chunknum;
-
- /* reset the line of data; section 1 is normal, others are ancillary, cursor is selected */
- dest = destmin;
- for (ch = 0; ch < view->visible.x; ch++, dest++)
- {
- UINT32 effcol = view->topleft.x + ch;
- dest->byte = ' ';
- dest->attrib = DCA_ANCILLARY;
- if (in_section(effcol, &memdata->section[1]))
- {
- dest->attrib = DCA_NORMAL;
- if (view->cursor_visible && effrow == view->cursor.y && effcol == view->cursor.x)
- dest->attrib |= DCA_SELECTED;
- }
- }
-
- /* if this visible row is valid, add it to the buffer */
- if (effrow < view->total.y)
- {
- offs_t addrbyte = memdata->byte_offset + effrow * memdata->bytes_per_row;
- offs_t address = (space != NULL) ? memory_byte_to_address(space, addrbyte) : addrbyte;
- char addrtext[20];
-
- /* generate the address */
- sprintf(addrtext, memdata->addrformat, address);
- dest = destrow + memdata->section[0].pos + 1;
- for (ch = 0; addrtext[ch] != 0 && ch < memdata->section[0].width - 1; ch++, dest++)
- if (dest >= destmin && dest < destmax)
- dest->byte = addrtext[ch];
-
- /* generate the data */
- for (chunknum = 0; chunknum < memdata->chunks_per_row; chunknum++)
- {
- int chunkindex = memdata->reverse_view ? (memdata->chunks_per_row - 1 - chunknum) : chunknum;
- UINT64 chunkdata;
- int ismapped;
-
- ismapped = memory_view_read(memdata, memdata->bytes_per_chunk, addrbyte + chunknum * memdata->bytes_per_chunk, &chunkdata);
- dest = destrow + memdata->section[1].pos + 1 + chunkindex * posdata->spacing;
- for (ch = 0; ch < posdata->spacing; ch++, dest++)
- if (dest >= destmin && dest < destmax)
- {
- UINT8 shift = posdata->shift[ch];
- if (shift < 64)
- dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*';
- }
- }
-
- /* generate the ASCII data */
- if (memdata->section[2].width > 0)
- {
- dest = destrow + memdata->section[2].pos + 1;
- for (ch = 0; ch < memdata->bytes_per_row; ch++, dest++)
- if (dest >= destmin && dest < destmax)
- {
- int ismapped;
- UINT64 chval;
-
- ismapped = memory_view_read(memdata, 1, addrbyte + ch, &chval);
- dest->byte = (ismapped && isprint(chval)) ? chval : '.';
- }
- }
- }
- }
+ debug_view **viewptr;
+ for (viewptr = &m_viewlist; *viewptr != NULL; viewptr = &(*viewptr)->m_next) ;
+ *viewptr = view;
+ return view;
}
-/*-------------------------------------------------
- memory_view_char - handle a character typed
- within the current view
--------------------------------------------------*/
-
-static void memory_view_char(debug_view *view, int chval)
-{
- static const char hexvals[] = "0123456789abcdef";
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- offs_t address;
- char *hexchar;
- int ismapped;
- UINT64 data;
- UINT32 delta;
- UINT8 shift;
-
- /* get the position */
- memory_view_get_cursor_pos(view, &address, &shift);
-
- /* handle the incoming key */
- switch (chval)
- {
- case DCH_UP:
- if (address >= memdata->byte_offset + memdata->bytes_per_row)
- address -= memdata->bytes_per_row;
- break;
-
- case DCH_DOWN:
- if (address <= memdata->maxaddr - memdata->bytes_per_row)
- address += memdata->bytes_per_row;
- break;
-
- case DCH_PUP:
- for (delta = (view->visible.y - 2) * memdata->bytes_per_row; delta > 0; delta -= memdata->bytes_per_row)
- if (address >= memdata->byte_offset + delta)
- {
- address -= delta;
- break;
- }
- break;
- case DCH_PDOWN:
- for (delta = (view->visible.y - 2) * memdata->bytes_per_row; delta > 0; delta -= memdata->bytes_per_row)
- if (address <= memdata->maxaddr - delta)
- {
- address += delta;
- break;
- }
- break;
+//**************************************************************************
+// DEBUG VIEW EXPRESSION
+//**************************************************************************
- case DCH_HOME:
- address -= address % memdata->bytes_per_row;
- shift = (memdata->bytes_per_chunk * 8) - 4;
- break;
+//-------------------------------------------------
+// debug_view_expression - constructor
+//-------------------------------------------------
- case DCH_CTRLHOME:
- address = memdata->byte_offset;
- shift = (memdata->bytes_per_chunk * 8) - 4;
- break;
-
- case DCH_END:
- address += (memdata->bytes_per_row - (address % memdata->bytes_per_row) - 1);
- shift = 0;
- break;
-
- case DCH_CTRLEND:
- address = memdata->maxaddr;
- shift = 0;
- break;
-
- case DCH_CTRLLEFT:
- if (address >= memdata->byte_offset + memdata->bytes_per_chunk)
- address -= memdata->bytes_per_chunk;
- break;
-
- case DCH_CTRLRIGHT:
- if (address <= memdata->maxaddr - memdata->bytes_per_chunk)
- address += memdata->bytes_per_chunk;
- break;
-
- default:
- hexchar = (char *)strchr(hexvals, tolower(chval));
- if (hexchar == NULL)
- break;
- ismapped = memory_view_read(memdata, memdata->bytes_per_chunk, address, &data);
- if (!ismapped)
- break;
- data &= ~((UINT64)0x0f << shift);
- data |= (UINT64)(hexchar - hexvals) << shift;
- memory_view_write(memdata, memdata->bytes_per_chunk, address, data);
- /* fall through... */
-
- case DCH_RIGHT:
- if (shift == 0 && address != memdata->maxaddr)
- {
- shift = memdata->bytes_per_chunk * 8 - 4;
- address += memdata->bytes_per_chunk;
- }
- else
- shift -= 4;
- break;
-
- case DCH_LEFT:
- if (shift == memdata->bytes_per_chunk * 8 - 4 && address != memdata->byte_offset)
- {
- shift = 0;
- address -= memdata->bytes_per_chunk;
- }
- else
- shift += 4;
- break;
- }
-
- /* set a new position */
- debug_view_begin_update(view);
- memory_view_set_cursor_pos(view, address, shift);
- view->update_pending = TRUE;
- debug_view_end_update(view);
-}
-
-
-/*-------------------------------------------------
- memory_view_recompute - recompute the internal
- data and structure of the memory view
--------------------------------------------------*/
-
-static void memory_view_recompute(debug_view *view)
+debug_view_expression::debug_view_expression(running_machine &machine)
+ : m_machine(machine),
+ m_dirty(true),
+ m_result(0),
+ m_parsed(NULL),
+ m_string("0"),
+ m_context(debug_cpu_get_global_symtable(&machine))
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const address_space *space = memdata->desc->space;
- offs_t cursoraddr;
- UINT8 cursorshift;
- int addrchars;
-
- /* get the current cursor position */
- memory_view_get_cursor_pos(view, &cursoraddr, &cursorshift);
-
- /* determine the maximum address and address format string from the raw information */
- if (space != NULL)
- {
- memdata->maxaddr = memdata->no_translation ? space->bytemask : space->logbytemask;
- addrchars = memdata->no_translation ? space->addrchars : space->logaddrchars;
- }
- else
- {
- memdata->maxaddr = memdata->desc->length - 1;
- addrchars = sprintf(memdata->addrformat, "%X", memdata->maxaddr);
- }
-
- /* generate an 8-byte aligned format for the address */
- if (!memdata->reverse_view)
- sprintf(memdata->addrformat, "%*s%%0%dX", 8 - addrchars, "", addrchars);
- else
- sprintf(memdata->addrformat, "%%0%dX%*s", addrchars, 8 - addrchars, "");
-
- /* if we are viewing a space with a minimum chunk size, clamp the bytes per chunk */
- if (space != NULL && space->ashift < 0)
- {
- UINT32 min_bytes_per_chunk = 1 << -space->ashift;
- while (memdata->bytes_per_chunk < min_bytes_per_chunk)
- {
- memdata->bytes_per_chunk *= 2;
- memdata->chunks_per_row /= 2;
- }
- memdata->chunks_per_row = MAX(1, memdata->chunks_per_row);
- }
-
- /* recompute the byte offset based on the most recent expression result */
- memdata->bytes_per_row = memdata->bytes_per_chunk * memdata->chunks_per_row;
- memdata->byte_offset = memdata->expression.result % memdata->bytes_per_row;
-
- /* compute the section widths */
- memdata->section[0].width = 1 + 8 + 1;
- memdata->section[1].width = 1 + 3 * memdata->bytes_per_row + 1;
- memdata->section[2].width = memdata->ascii_view ? (1 + memdata->bytes_per_row + 1) : 0;
-
- /* compute the section positions */
- if (!memdata->reverse_view)
- {
- memdata->section[0].pos = 0;
- memdata->section[1].pos = memdata->section[0].pos + memdata->section[0].width;
- memdata->section[2].pos = memdata->section[1].pos + memdata->section[1].width;
- view->total.x = memdata->section[2].pos + memdata->section[2].width;
- }
- else
- {
- memdata->section[2].pos = 0;
- memdata->section[1].pos = memdata->section[2].pos + memdata->section[2].width;
- memdata->section[0].pos = memdata->section[1].pos + memdata->section[1].width;
- view->total.x = memdata->section[0].pos + memdata->section[0].width;
- }
-
- /* derive total sizes from that */
- view->total.y = ((UINT64)memdata->maxaddr - (UINT64)memdata->byte_offset + (UINT64)memdata->bytes_per_row - 1) / memdata->bytes_per_row;
-
- /* reset the current cursor position */
- memory_view_set_cursor_pos(view, cursoraddr, cursorshift);
}
-/*-------------------------------------------------
- memory_view_needs_recompute - determine if
- anything has changed that requires a
- recomputation
--------------------------------------------------*/
+//-------------------------------------------------
+// ~debug_view_expression - destructor
+//-------------------------------------------------
-static int memory_view_needs_recompute(debug_view *view)
+debug_view_expression::~debug_view_expression()
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const address_space *space = memdata->desc->space;
- int recompute = view->recompute;
-
- /* handle expression changes */
- if (debug_view_expression_changed_value(view, &memdata->expression, (space != NULL && space->cpu != NULL && space->cpu->type() == CPU) ? space->cpu : NULL))
- {
- offs_t resultbyte;
-
- recompute = TRUE;
- view->topleft.y = (memdata->expression.result - memdata->byte_offset) / memdata->bytes_per_row;
- view->topleft.y = MAX(view->topleft.y, 0);
- view->topleft.y = MIN(view->topleft.y, view->total.y - 1);
- if (space != NULL)
- resultbyte = memory_address_to_byte(space, memdata->expression.result) & space->logbytemask;
- else
- resultbyte = memdata->expression.result;
-
- memory_view_set_cursor_pos(view, resultbyte, memdata->bytes_per_chunk * 8 - 4);
- }
-
- /* expression is clean at this point, and future recomputation is not necessary */
- view->recompute = FALSE;
- return recompute;
+ // free our parsed expression
+ if (m_parsed != NULL)
+ expression_free(m_parsed);
}
-/*-------------------------------------------------
- memory_view_get_cursor_pos - return the cursor
- position as an address and a shift value
--------------------------------------------------*/
+//-------------------------------------------------
+// set_string - set the expression string
+//-------------------------------------------------
-static void memory_view_get_cursor_pos(debug_view *view, offs_t *address, UINT8 *shift)
+void debug_view_expression::set_string(const char *string)
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const memory_view_pos *posdata = &memory_pos_table[memdata->bytes_per_chunk];
- int xposition, chunknum, chunkoffs;
-
- /* start with the base address for this row */
- *address = memdata->byte_offset + view->cursor.y * memdata->bytes_per_chunk * memdata->chunks_per_row;
-
- /* determine the X position within the middle section, clamping as necessary */
- xposition = view->cursor.x - memdata->section[1].pos - 1;
- if (xposition < 0)
- xposition = 0;
- else if (xposition >= posdata->spacing * memdata->chunks_per_row)
- xposition = posdata->spacing * memdata->chunks_per_row - 1;
-
- /* compute chunk number and offset within that chunk */
- chunknum = xposition / posdata->spacing;
- chunkoffs = xposition % posdata->spacing;
-
- /* reverse the chunknum if we're reversed */
- if (memdata->reverse_view)
- chunknum = memdata->chunks_per_row - 1 - chunknum;
-
- /* compute the address and shift */
- *address += chunknum * memdata->bytes_per_chunk;
- *shift = posdata->shift[chunkoffs] & 0x7f;
+ m_string = string;
+ m_dirty = true;
}
-/*-------------------------------------------------
- memory_view_set_cursor_pos - set the cursor
- position as a function of an address and a
- shift value
--------------------------------------------------*/
+//-------------------------------------------------
+// set_context - set the context for the
+// expression
+//-------------------------------------------------
-static void memory_view_set_cursor_pos(debug_view *view, offs_t address, UINT8 shift)
+void debug_view_expression::set_context(symbol_table *context)
{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const memory_view_pos *posdata = &memory_pos_table[memdata->bytes_per_chunk];
- int chunknum;
-
- /* offset the address by the byte offset */
- if (address < memdata->byte_offset)
- address = memdata->byte_offset;
- address -= memdata->byte_offset;
-
- /* compute the Y coordinate and chunk index */
- view->cursor.y = address / memdata->bytes_per_row;
- chunknum = (address % memdata->bytes_per_row) / memdata->bytes_per_chunk;
-
- /* reverse the chunknum if we're reversed */
- if (memdata->reverse_view)
- chunknum = memdata->chunks_per_row - 1 - chunknum;
-
- /* scan within the chunk to find the shift */
- for (view->cursor.x = 0; view->cursor.x < posdata->spacing; view->cursor.x++)
- if (posdata->shift[view->cursor.x] == shift)
- break;
-
- /* add in the chunk offset and shift to the right of divider1 */
- view->cursor.x += memdata->section[1].pos + 1 + posdata->spacing * chunknum;
-
- /* clamp to the window bounds */
- view->cursor.x = MIN(view->cursor.x, view->total.x);
- view->cursor.y = MIN(view->cursor.y, view->total.y);
-
- /* scroll if out of range */
- adjust_visible_x_for_cursor(view);
- adjust_visible_y_for_cursor(view);
+ m_context = (context != NULL) ? context : debug_cpu_get_global_symtable(&m_machine);
+ m_dirty = true;
}
-/*-------------------------------------------------
- memory_view_read - generic memory view data
- reader
--------------------------------------------------*/
+//-------------------------------------------------
+// recompute - recompute the value of an
+// expression
+//-------------------------------------------------
-static int memory_view_read(debug_view_memory *memdata, UINT8 size, offs_t offs, UINT64 *data)
+bool debug_view_expression::recompute()
{
- /* if no raw data, just use the standard debug routines */
- if (memdata->desc->space != NULL)
- {
- const address_space *space = memdata->desc->space;
- offs_t dummyaddr = offs;
- int ismapped;
-
- ismapped = memdata->no_translation ? TRUE : debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &dummyaddr);
- *data = ~(UINT64)0;
- if (ismapped)
- {
- switch (size)
- {
- case 1: *data = debug_read_byte(space, offs, !memdata->no_translation); break;
- case 2: *data = debug_read_word(space, offs, !memdata->no_translation); break;
- case 4: *data = debug_read_dword(space, offs, !memdata->no_translation); break;
- case 8: *data = debug_read_qword(space, offs, !memdata->no_translation); break;
- }
- }
- return ismapped;
- }
+ bool changed = m_dirty;
- /* if larger than a byte, reduce by half and recurse */
- if (size > 1)
+ // if dirty, re-evaluate
+ if (m_dirty)
{
- UINT64 data0, data1;
- int ismapped;
-
- size /= 2;
- ismapped = memory_view_read(memdata, size, offs + 0 * size, &data0);
- ismapped |= memory_view_read(memdata, size, offs + 1 * size, &data1);
- if (memdata->desc->endianness == ENDIANNESS_LITTLE)
- *data = data0 | (data1 << (size * 8));
- else
- *data = data1 | (data0 << (size * 8));
- return ismapped;
- }
-
- /* all 0xff if out of bounds */
- offs ^= memdata->desc->offsetxor;
- if (offs >= memdata->desc->length)
- return FALSE;
- *data = *((UINT8 *)memdata->desc->base + offs);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- memory_view_write - generic memory view data
- writer
--------------------------------------------------*/
-
-static void memory_view_write(debug_view_memory *memdata, UINT8 size, offs_t offs, UINT64 data)
-{
- /* if no raw data, just use the standard debug routines */
- if (memdata->desc->space != NULL)
- {
- const address_space *space = memdata->desc->space;
-
- switch (size)
- {
- case 1: debug_write_byte(space, offs, data, !memdata->no_translation); break;
- case 2: debug_write_word(space, offs, data, !memdata->no_translation); break;
- case 4: debug_write_dword(space, offs, data, !memdata->no_translation); break;
- case 8: debug_write_qword(space, offs, data, !memdata->no_translation); break;
- }
- return;
- }
+ // parse the new expression
+ parsed_expression *expr;
+ EXPRERR exprerr = expression_parse(m_string, m_context, &debug_expression_callbacks, &m_machine, &expr);
- /* if larger than a byte, reduce by half and recurse */
- if (size > 1)
- {
- size /= 2;
- if (memdata->desc->endianness == ENDIANNESS_LITTLE)
- {
- memory_view_write(memdata, size, offs + 0 * size, data);
- memory_view_write(memdata, size, offs + 1 * size, data >> (8 * size));
- }
- else
+ // if it worked, update the expression
+ if (exprerr == EXPRERR_NONE)
{
- memory_view_write(memdata, size, offs + 1 * size, data);
- memory_view_write(memdata, size, offs + 0 * size, data >> (8 * size));
+ if (m_parsed != NULL)
+ expression_free(m_parsed);
+ m_parsed = expr;
}
- return;
- }
-
- /* ignore if out of bounds */
- offs ^= memdata->desc->offsetxor;
- if (offs >= memdata->desc->length)
- return;
- *((UINT8 *)memdata->desc->base + offs) = data;
-
-/* hack for FD1094 editing */
-#ifdef FD1094_HACK
- if (memdata->desc->base == memory_region(view->machine, "user2"))
- {
- extern void fd1094_regenerate_key(running_machine *machine);
- fd1094_regenerate_key(view->machine);
}
-#endif
-}
-
-
-/*-------------------------------------------------
- memory_view_get_subview_list - return a linked
- list of subviews
--------------------------------------------------*/
-
-const memory_subview_item *memory_view_get_subview_list(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- return memdata->subviewlist;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_subview - return the current
- subview index
--------------------------------------------------*/
-
-int memory_view_get_subview(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
-
- return memdata->desc->index;
-}
-
-/*-------------------------------------------------
- memory_view_get_expression - return the
- expression string describing the home address
--------------------------------------------------*/
-
-const char *memory_view_get_expression(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->expression.string;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_bytes_per_chunk - return the
- currently displayed bytes per chunk
--------------------------------------------------*/
-
-UINT8 memory_view_get_bytes_per_chunk(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->bytes_per_chunk;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_chunks_per_row - return the
- number of chunks displayed across a row
--------------------------------------------------*/
-
-UINT32 memory_view_get_chunks_per_row(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->chunks_per_row;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_reverse - return TRUE if the
- memory view is displayed reverse
--------------------------------------------------*/
-
-UINT8 memory_view_get_reverse(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->reverse_view;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_ascii - return TRUE if the
- memory view is displaying an ASCII
- representation
--------------------------------------------------*/
-
-UINT8 memory_view_get_ascii(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->ascii_view;
-}
-
-
-/*-------------------------------------------------
- memory_view_get_physical - return TRUE if the
- memory view is displaying physical addresses
- versus logical addresses
--------------------------------------------------*/
-
-UINT8 memory_view_get_physical(debug_view *view)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- assert(view->type == DVT_MEMORY);
- debug_view_begin_update(view);
- debug_view_end_update(view);
- return memdata->no_translation;
-}
-
-
-/*-------------------------------------------------
- memory_view_set_subview - select a new subview
- by index
--------------------------------------------------*/
-
-void memory_view_set_subview(debug_view *view, int index)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
- const memory_subview_item *subview;
-
- assert(view->type == DVT_MEMORY);
-
- /* pick the requested view */
- subview = memory_view_get_subview_by_index(memdata->subviewlist, index);
- if (subview == NULL)
- return;
-
- /* handle a change */
- if (subview != memdata->desc)
+ // if we have a parsed expression, evalute it
+ if (m_parsed != NULL)
{
- debug_view_begin_update(view);
- memdata->desc = subview;
- memdata->chunks_per_row = memdata->bytes_per_chunk * memdata->chunks_per_row / memdata->desc->prefsize;
- memdata->bytes_per_chunk = memdata->desc->prefsize;
-
- /* we need to recompute the expression in the context of the new space */
- memdata->expression.dirty = TRUE;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
- }
-}
+ UINT64 oldresult = m_result;
-
-/*-------------------------------------------------
- memory_view_set_expression - set the
- expression string describing the home address
--------------------------------------------------*/
-
-void memory_view_set_expression(debug_view *view, const char *expression)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
- assert(expression != NULL);
-
- debug_view_begin_update(view);
- debug_view_expression_set(&memdata->expression, expression);
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
-}
-
-
-/*-------------------------------------------------
- memory_view_set_bytes_per_chunk - specify the
- number of bytes displayed per chunk
--------------------------------------------------*/
-
-void memory_view_set_bytes_per_chunk(debug_view *view, UINT8 chunkbytes)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
- assert(chunkbytes < ARRAY_LENGTH(memory_pos_table) && memory_pos_table[chunkbytes].spacing != 0);
-
- if (chunkbytes != memdata->bytes_per_chunk)
- {
- int endianness = memdata->desc->endianness;
- offs_t address;
- UINT8 shift;
-
- debug_view_begin_update(view);
- memory_view_get_cursor_pos(view, &address, &shift);
- address += (shift / 8) ^ ((endianness == ENDIANNESS_LITTLE) ? 0 : (memdata->bytes_per_chunk - 1));
- shift %= 8;
-
- memdata->bytes_per_chunk = chunkbytes;
- memdata->chunks_per_row = memdata->bytes_per_row / chunkbytes;
- view->recompute = view->update_pending = TRUE;
-
- shift += 8 * ((address % memdata->bytes_per_chunk) ^ ((endianness == ENDIANNESS_LITTLE) ? 0 : (memdata->bytes_per_chunk - 1)));
- address -= address % memdata->bytes_per_chunk;
- memory_view_set_cursor_pos(view, address, shift);
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- memory_view_set_chunks_per_row - specify the
- number of chunks displayed across a row
--------------------------------------------------*/
-
-void memory_view_set_chunks_per_row(debug_view *view, UINT32 rowchunks)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
-
- if (rowchunks < 1)
- return;
-
- if (rowchunks != memdata->chunks_per_row)
- {
- offs_t address;
- UINT8 shift;
-
- debug_view_begin_update(view);
- memory_view_get_cursor_pos(view, &address, &shift);
- memdata->chunks_per_row = rowchunks;
- view->recompute = view->update_pending = TRUE;
- memory_view_set_cursor_pos(view, address, shift);
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- memory_view_set_reverse - specify TRUE if the
- memory view is displayed reverse
--------------------------------------------------*/
-
-void memory_view_set_reverse(debug_view *view, UINT8 reverse)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
-
- if (reverse != memdata->reverse_view)
- {
- offs_t address;
- UINT8 shift;
-
- debug_view_begin_update(view);
- memory_view_get_cursor_pos(view, &address, &shift);
- memdata->reverse_view = reverse;
- view->recompute = view->update_pending = TRUE;
- memory_view_set_cursor_pos(view, address, shift);
- debug_view_end_update(view);
+ // recompute the value of the expression
+ EXPRERR exprerr = expression_execute(m_parsed, &m_result);
+ if (m_result != oldresult)
+ changed = true;
}
-}
-
-
-/*-------------------------------------------------
- memory_view_set_ascii - specify TRUE if the
- memory view should display an ASCII
- representation
--------------------------------------------------*/
-
-void memory_view_set_ascii(debug_view *view, UINT8 ascii)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
- if (ascii != memdata->ascii_view)
- {
- offs_t address;
- UINT8 shift;
-
- debug_view_begin_update(view);
- memory_view_get_cursor_pos(view, &address, &shift);
- memdata->ascii_view = ascii;
- view->recompute = view->update_pending = TRUE;
- memory_view_set_cursor_pos(view, address, shift);
- debug_view_end_update(view);
- }
-}
-
-
-/*-------------------------------------------------
- memory_view_set_physical - specify TRUE if the
- memory view should display physical addresses
- versus logical addresses
--------------------------------------------------*/
-
-void memory_view_set_physical(debug_view *view, UINT8 physical)
-{
- debug_view_memory *memdata = (debug_view_memory *)view->extra_data;
-
- assert(view->type == DVT_MEMORY);
-
- if (physical != memdata->no_translation)
- {
- debug_view_begin_update(view);
- memdata->no_translation = physical;
- view->recompute = view->update_pending = TRUE;
- debug_view_end_update(view);
- }
+ // expression no longer dirty by definition
+ m_dirty = false;
+ return changed;
}
diff --git a/src/emu/debug/debugvw.h b/src/emu/debug/debugvw.h
index c133da69f95..86f7ae463a2 100644
--- a/src/emu/debug/debugvw.h
+++ b/src/emu/debug/debugvw.h
@@ -4,173 +4,113 @@
Debugger view engine.
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
-*********************************************************************/
+***************************************************************************/
#ifndef __DEBUGVIEW_H__
#define __DEBUGVIEW_H__
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* types passed to debug_view_alloc */
-#define DVT_CONSOLE (1)
-#define DVT_REGISTERS (2)
-#define DVT_DISASSEMBLY (3)
-#define DVT_MEMORY (4)
-#define DVT_LOG (5)
-#define DVT_TIMERS (6)
-#define DVT_ALLOCS (7)
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
-enum _disasm_right_column
+// types passed to debug_view_manager::alloc_view()
+enum debug_view_type
{
- DASM_RIGHTCOL_NONE,
- DASM_RIGHTCOL_RAW,
- DASM_RIGHTCOL_ENCRYPTED,
- DASM_RIGHTCOL_COMMENTS
+ DVT_NONE,
+ DVT_CONSOLE,
+ DVT_STATE,
+ DVT_DISASSEMBLY,
+ DVT_MEMORY,
+ DVT_LOG,
+ DVT_TIMERS,
+ DVT_ALLOCS
};
-typedef enum _disasm_right_column disasm_right_column;
-
-/* properties available for disassembly views */
-#define DVP_DASM_EXPRESSION (101) /* r/w - const char * */
-#define DVP_DASM_TRACK_LIVE (102) /* r/w - UINT32 */
-#define DVP_DASM_RIGHT_COLUMN (103) /* r/w - UINT32 */
-#define DVP_DASM_BACKWARD_STEPS (104) /* r/w - UINT32 */
-#define DVP_DASM_WIDTH (105) /* r/w - UINT32 */
-#define DVP_DASM_ACTIVE_ADDRESS (112) /* r/w - UINT32 */
-
-/* properties available for memory views */
-#define DVP_MEM_SPACE (100) /* r/w - address space * */
-#define DVP_MEM_EXPRESSION (101) /* r/w - const char * */
-#define DVP_MEM_TRACK_LIVE (102) /* r/w - UINT32 */
-#define DVP_MEM_SPACENUM (103) /* r/w - UINT32 */
-#define DVP_MEM_BYTES_PER_CHUNK (104) /* r/w - UINT32 */
-#define DVP_MEM_REVERSE_VIEW (105) /* r/w - UINT32 */
-#define DVP_MEM_ASCII_VIEW (106) /* r/w - UINT32 */
-#define DVP_MEM_RAW_BASE (107) /* r/w - void * */
-#define DVP_MEM_RAW_LENGTH (108) /* r/w - UINT32 */
-#define DVP_MEM_RAW_OFFSET_XOR (109) /* r/w - UINT32 */
-#define DVP_MEM_RAW_LITTLE_ENDIAN (110) /* r/w - UINT32 */
-#define DVP_MEM_WIDTH (111) /* r/w - UINT32 */
-#define DVP_MEM_NO_TRANSLATION (113) /* r/w - UINT32 */
-
-/* attribute bits for debug_view_char.attrib */
-#define DCA_NORMAL (0x00) /* in Windows: black on white */
-#define DCA_CHANGED (0x01) /* in Windows: red foreground */
-#define DCA_SELECTED (0x02) /* in Windows: light red background */
-#define DCA_INVALID (0x04) /* in Windows: dark blue foreground */
-#define DCA_DISABLED (0x08) /* in Windows: darker foreground */
-#define DCA_ANCILLARY (0x10) /* in Windows: grey background */
-#define DCA_CURRENT (0x20) /* in Windows: yellow background */
-#define DCA_COMMENT (0x40) /* in Windows: green foreground */
-
-/* special characters that can be passed as a DVP_CHARACTER */
-#define DCH_UP (1) /* up arrow */
-#define DCH_DOWN (2) /* down arrow */
-#define DCH_LEFT (3) /* left arrow */
-#define DCH_RIGHT (4) /* right arrow */
-#define DCH_PUP (5) /* page up */
-#define DCH_PDOWN (6) /* page down */
-#define DCH_HOME (7) /* home */
-#define DCH_CTRLHOME (8) /* ctrl+home */
-#define DCH_END (9) /* end */
-#define DCH_CTRLEND (10) /* ctrl+end */
-#define DCH_CTRLRIGHT (11) /* ctrl+right */
-#define DCH_CTRLLEFT (12) /* ctrl+left */
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* opaque structure representing a debug view */
-class debug_view;
-
-
-/* OSD callback function for a view */
-typedef void (*debug_view_osd_update_func)(debug_view *view, void *osdprivate);
-/* pair of X,Y coordinates for sizing */
-struct debug_view_xy
+// notifications passed to view_notify()
+enum debug_view_notification
{
- INT32 x;
- INT32 y;
+ VIEW_NOTIFY_NONE,
+ VIEW_NOTIFY_VISIBLE_CHANGED,
+ VIEW_NOTIFY_CURSOR_CHANGED,
+ VIEW_NOTIFY_SOURCE_CHANGED
};
-/* a registers subview item */
-class registers_subview_item
-{
- DISABLE_COPYING(registers_subview_item);
+// attribute bits for debug_view_char.attrib
+const UINT8 DCA_NORMAL = 0x00; // in Windows: black on white
+const UINT8 DCA_CHANGED = 0x01; // in Windows: red foreground
+const UINT8 DCA_SELECTED = 0x02; // in Windows: light red background
+const UINT8 DCA_INVALID = 0x04; // in Windows: dark blue foreground
+const UINT8 DCA_DISABLED = 0x08; // in Windows: darker foreground
+const UINT8 DCA_ANCILLARY = 0x10; // in Windows: grey background
+const UINT8 DCA_CURRENT = 0x20; // in Windows: yellow background
+const UINT8 DCA_COMMENT = 0x40; // in Windows: green foreground
-public:
- registers_subview_item()
- : next(NULL),
- index(0),
- stateintf(NULL),
- execintf(NULL) { }
-
- registers_subview_item *next; /* link to next item */
- int index; /* index of this item */
- astring name; /* name of the subview item */
- device_state_interface *stateintf; /* state interface */
- device_execute_interface *execintf; /* execution interface */
-};
+// special characters that can be passed to process_char()
+const int DCH_UP = 1; // up arrow
+const int DCH_DOWN = 2; // down arrow
+const int DCH_LEFT = 3; // left arrow
+const int DCH_RIGHT = 4; // right arrow
+const int DCH_PUP = 5; // page up
+const int DCH_PDOWN = 6; // page down
+const int DCH_HOME = 7; // home
+const int DCH_CTRLHOME = 8; // ctrl+home
+const int DCH_END = 9; // end
+const int DCH_CTRLEND = 10; // ctrl+end
+const int DCH_CTRLRIGHT = 11; // ctrl+right
+const int DCH_CTRLLEFT = 12; // ctrl+left
-/* a disassembly subview item */
-class disasm_subview_item
-{
- DISABLE_COPYING(disasm_subview_item);
-public:
- disasm_subview_item()
- : next(NULL),
- index(0),
- space(NULL) { }
-
- disasm_subview_item *next; /* link to next item */
- int index; /* index of this item */
- astring name; /* name of the subview item */
- const address_space *space; /* address space to display */
-};
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
-/* a memory subview item */
-class memory_subview_item
-{
- DISABLE_COPYING(memory_subview_item);
+// forward references
+class debug_view;
+typedef struct _symbol_table symbol_table;
+typedef struct _parsed_expression parsed_expression;
-public:
- memory_subview_item()
- : next(NULL),
- index(0),
- space(NULL),
- base(NULL),
- length(0),
- offsetxor(0),
- endianness(ENDIANNESS_NATIVE),
- prefsize(1) { }
-
- memory_subview_item *next; /* link to next item */
- int index; /* index of this item */
- astring name; /* name of the subview item */
- const address_space *space; /* address space we reference (if any) */
- void * base; /* pointer to memory base */
- offs_t length; /* length of memory */
- offs_t offsetxor; /* XOR to apply to offsets */
- UINT8 endianness; /* endianness of memory */
- UINT8 prefsize; /* preferred bytes per chunk */
-};
+
+// OSD callback function for a view
+typedef void (*debug_view_osd_update_func)(debug_view &view, void *osdprivate);
-/* a single "character" in the debug view has an ASCII value and an attribute byte */
+// a single "character" in the debug view has an ASCII value and an attribute byte
struct debug_view_char
{
UINT8 byte;
@@ -178,281 +118,212 @@ struct debug_view_char
};
+// pair of X,Y coordinates for sizing
+class debug_view_xy
+{
+public:
+ debug_view_xy(int _x = 0, int _y = 0) : x(_x), y(_y) { }
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-
-/* ----- initialization and cleanup ----- */
-
-/* initializes the view system */
-void debug_view_init(running_machine *machine);
-
-
-
-/* ----- view creation/deletion ----- */
-
-/* allocate a new debug view */
-debug_view *debug_view_alloc(running_machine *machine, int type, debug_view_osd_update_func osdupdate, void *osdprivate);
-
-/* free a debug view */
-void debug_view_free(debug_view *view);
-
-
-
-/* ----- update management ----- */
-
-/* begin a sequence of changes so that only one update occurs */
-void debug_view_begin_update(debug_view *view);
-
-/* complete a sequence of changes so that only one update occurs */
-void debug_view_end_update(debug_view *view);
-
-/* flush any pending updates to the OSD layer */
-void debug_view_flush_updates(running_machine *machine);
-
-/* force all views to refresh */
-void debug_view_update_all(running_machine *machine);
-
-/* force all views of a given type to refresh */
-void debug_view_update_type(running_machine *machine, int type);
-
-
-
-/* ----- standard view properties ----- */
-
-/* return a pointer to a 2-dimentional array of characters that represent the visible area of the view */
-const debug_view_char *debug_view_get_chars(debug_view *view);
-
-/* type a character into a view */
-void debug_view_type_character(debug_view *view, int character);
-
-
-
-/* ----- standard view sizing ----- */
-
-/* return the total view size in rows and columns */
-debug_view_xy debug_view_get_total_size(debug_view *view);
-
-/* return the visible size in rows and columns */
-debug_view_xy debug_view_get_visible_size(debug_view *view);
-
-/* return the top left position of the visible area in rows and columns */
-debug_view_xy debug_view_get_visible_position(debug_view *view);
-
-/* set the visible size in rows and columns */
-void debug_view_set_visible_size(debug_view *view, debug_view_xy size);
-
-/* set the top left position of the visible area in rows and columns */
-void debug_view_set_visible_position(debug_view *view, debug_view_xy pos);
-
-
-
-/* ----- standard view cursor management ----- */
-
-/* return the current cursor position as a row and column */
-debug_view_xy debug_view_get_cursor_position(debug_view *view);
-
-/* return TRUE if a cursor is supported for this view type */
-int debug_view_get_cursor_supported(debug_view *view);
-
-/* return TRUE if a cursor is currently visible */
-int debug_view_get_cursor_visible(debug_view *view);
-
-/* set the current cursor position as a row and column */
-void debug_view_set_cursor_position(debug_view *view, debug_view_xy pos);
-
-/* set the visible state of the cursor */
-void debug_view_set_cursor_visible(debug_view *view, int visible);
-
-
-
-/* ----- registers view-specific properties ----- */
-
-/* return a linked list of subviews */
-const registers_subview_item *registers_view_get_subview_list(debug_view *view);
-
-/* return the current subview index */
-int registers_view_get_subview(debug_view *view);
-
-/* select a new subview by index */
-void registers_view_set_subview(debug_view *view, int index);
-
-
-
-/* ----- disassembly view-specific properties ----- */
-
-/* return a linked list of subviews */
-const disasm_subview_item *disasm_view_get_subview_list(debug_view *view);
-
-/* return the current subview index */
-int disasm_view_get_subview(debug_view *view);
-
-/* return the expression string describing the home address */
-const char *disasm_view_get_expression(debug_view *view);
-
-/* return the contents of the right column */
-disasm_right_column disasm_view_get_right_column(debug_view *view);
-
-/* return the number of instructions displayed before the home address */
-UINT32 disasm_view_get_backward_steps(debug_view *view);
-
-/* return the width in characters of the main disassembly section */
-UINT32 disasm_view_get_disasm_width(debug_view *view);
-
-/* return the PC of the currently selected address in the view */
-offs_t disasm_view_get_selected_address(debug_view *view);
-
-/* select a new subview by index */
-void disasm_view_set_subview(debug_view *view, int index);
-
-/* set the expression string describing the home address */
-void disasm_view_set_expression(debug_view *view, const char *expression);
-
-/* set the contents of the right column */
-void disasm_view_set_right_column(debug_view *view, disasm_right_column contents);
-
-/* set the number of instructions displayed before the home address */
-void disasm_view_set_backward_steps(debug_view *view, UINT32 steps);
-
-/* set the width in characters of the main disassembly section */
-void disasm_view_set_disasm_width(debug_view *view, UINT32 width);
-
-/* set the PC of the currently selected address in the view */
-void disasm_view_set_selected_address(debug_view *view, offs_t address);
-
-
-
-/* ----- memory view-specific properties ----- */
-
-/* return a linked list of subviews */
-const memory_subview_item *memory_view_get_subview_list(debug_view *view);
-
-/* return the current subview index */
-int memory_view_get_subview(debug_view *view);
-
-/* return the expression string describing the home address */
-const char *memory_view_get_expression(debug_view *view);
-
-/* return the currently displayed bytes per chunk */
-UINT8 memory_view_get_bytes_per_chunk(debug_view *view);
-
-/* return the number of chunks displayed across a row */
-UINT32 memory_view_get_chunks_per_row(debug_view *view);
-
-/* return TRUE if the memory view is displayed reverse */
-UINT8 memory_view_get_reverse(debug_view *view);
-
-/* return TRUE if the memory view is displaying an ASCII representation */
-UINT8 memory_view_get_ascii(debug_view *view);
-
-/* return TRUE if the memory view is displaying physical addresses versus logical addresses */
-UINT8 memory_view_get_physical(debug_view *view);
-
-/* select a new subview by index */
-void memory_view_set_subview(debug_view *view, int index);
-
-/* set the expression string describing the home address */
-void memory_view_set_expression(debug_view *view, const char *expression);
-
-/* specify the number of bytes displayed per chunk */
-void memory_view_set_bytes_per_chunk(debug_view *view, UINT8 chunkbytes);
-
-/* specify the number of chunks displayed across a row */
-void memory_view_set_chunks_per_row(debug_view *view, UINT32 rowchunks);
-
-/* specify TRUE if the memory view is displayed reverse */
-void memory_view_set_reverse(debug_view *view, UINT8 reverse);
-
-/* specify TRUE if the memory view should display an ASCII representation */
-void memory_view_set_ascii(debug_view *view, UINT8 ascii);
-
-/* specify TRUE if the memory view should display physical addresses versus logical addresses */
-void memory_view_set_physical(debug_view *view, UINT8 physical);
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
+ INT32 x;
+ INT32 y;
+};
-/*-------------------------------------------------
- registers_view_get_subview_by_index - return a
- pointer to a registers subview by index
--------------------------------------------------*/
-INLINE const registers_subview_item *registers_view_get_subview_by_index(const registers_subview_item *itemlist, int index)
+// debug_view_sources select from multiple sources available within a view
+class debug_view_source
{
- for ( ; itemlist != NULL; itemlist = itemlist->next)
- if (itemlist->index == index)
- return itemlist;
- return NULL;
-}
+ DISABLE_COPYING(debug_view_source);
+
+ friend class debug_view_source_list;
+public:
+ // construction/destruction
+ debug_view_source(const char *name, device_t *device = NULL);
+ virtual ~debug_view_source();
+
+ // getters
+ const char *name() const { return m_name; }
+ debug_view_source *next() const { return m_next; }
+ device_t *device() const { return m_device; }
+
+private:
+ // internal state
+ debug_view_source * m_next; // link to next item
+ astring m_name; // name of the source item
+ device_t * m_device; // associated device (if applicable)
+};
-/*-------------------------------------------------
- registers_view_get_current_subview - return a
- pointer to the current subview of a
- registers view
--------------------------------------------------*/
-INLINE const registers_subview_item *registers_view_get_current_subview(debug_view *view)
+// a debug_view_source_list contains a list of debug_view_sources
+class debug_view_source_list
{
- return registers_view_get_subview_by_index(registers_view_get_subview_list(view), registers_view_get_subview(view));
-}
+ DISABLE_COPYING(debug_view_source_list);
+public:
+ // construction/destruction
+ debug_view_source_list(running_machine &machine);
+ ~debug_view_source_list();
+
+ // getters
+ const debug_view_source *head() const { return m_head; }
+ int count() const { return m_count; }
+ int index(const debug_view_source &source) const;
+ const debug_view_source *by_index(int index) const;
+
+ // operations
+ void reset();
+ void append(debug_view_source &view_source);
+ const debug_view_source *match_device(device_t *device) const;
+ int match_device_index(device_t *device) const { return index(*match_device(device)); }
+
+private:
+ // internal state
+ running_machine & m_machine; // reference to our machine
+ debug_view_source * m_head; // head of the list
+ debug_view_source * m_tail; // end of the tail
+ UINT32 m_count; // number of items in the list
+};
-/*-------------------------------------------------
- disasm_view_get_subview_by_index - return a
- pointer to a disasm subview by index
--------------------------------------------------*/
-INLINE const disasm_subview_item *disasm_view_get_subview_by_index(const disasm_subview_item *itemlist, int index)
+// debug_view describes a single text-based view
+class debug_view
{
- for ( ; itemlist != NULL; itemlist = itemlist->next)
- if (itemlist->index == index)
- return itemlist;
- return NULL;
-}
+ friend class debug_view_manager;
+
+protected:
+ // construction/destruction
+ debug_view(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate);
+ virtual ~debug_view();
+public:
+ // getters
+ running_machine &machine() const { return m_machine; }
+ debug_view *next() const { return m_next; }
+ debug_view_type type() const { return m_type; }
+ const debug_view_char *viewdata() const { return m_viewdata; }
+ debug_view_xy total_size() { flush_updates(); return m_total; }
+ debug_view_xy visible_size() { flush_updates(); return m_visible; }
+ debug_view_xy visible_position() { flush_updates(); return m_topleft; }
+ debug_view_xy cursor_position() { flush_updates(); return m_cursor; }
+ bool cursor_supported() { flush_updates(); return m_supports_cursor; }
+ bool cursor_visible() { flush_updates(); return m_cursor_visible; }
+ const debug_view_source *source() const { return m_source; }
+ const debug_view_source_list &source_list() const { return m_source_list; }
+
+ // setters
+ void set_size(int width, int height);
+ void set_visible_size(debug_view_xy size);
+ void set_visible_position(debug_view_xy pos);
+ void set_cursor_position(debug_view_xy pos);
+ void set_cursor_visible(bool visible = true);
+ void set_source(const debug_view_source &source);
+ void process_char(int character) { view_char(character); }
+
+protected:
+ // internal updating helpers
+ void begin_update() { m_update_level++; }
+ void end_update();
+ void force_update() { begin_update(); m_update_pending = true; end_update(); }
+ void flush_updates() { begin_update(); end_update(); }
+ void flush_osd_updates();
+
+ // cursor management helpers
+ void adjust_visible_x_for_cursor();
+ void adjust_visible_y_for_cursor();
+
+ // overridables
+ virtual void view_update() = 0;
+ virtual void view_notify(debug_view_notification type);
+ virtual void view_char(int chval);
+
+protected:
+ // core view data
+ debug_view * m_next; // link to the next view
+ running_machine & m_machine; // machine associated with this view
+ debug_view_type m_type; // type of view
+ const debug_view_source *m_source; // currently selected data source
+ debug_view_source_list m_source_list; // list of available data sources
+
+ // OSD data
+ debug_view_osd_update_func m_osdupdate; // callback for the update
+ void * m_osdprivate; // OSD-managed private data
+
+ // visibility info
+ debug_view_xy m_visible; // visible size (in rows and columns)
+ debug_view_xy m_total; // total size (in rows and columns)
+ debug_view_xy m_topleft; // top-left visible position (in rows and columns)
+ debug_view_xy m_cursor; // cursor position
+ bool m_supports_cursor; // does this view support a cursor?
+ bool m_cursor_visible; // is the cursor visible?
+
+ // update info
+ bool m_recompute; // does this view require a recomputation?
+ UINT8 m_update_level; // update level; updates when this hits 0
+ bool m_update_pending; // true if there is a pending update
+ bool m_osd_update_pending; // true if there is a pending update
+ debug_view_char * m_viewdata; // current array of view data
+ int m_viewdata_size; // number of elements of the viewdata array
+};
-/*-------------------------------------------------
- disasm_view_get_current_subview - return a
- pointer to the current subview of a
- disassembly view
--------------------------------------------------*/
-INLINE const disasm_subview_item *disasm_view_get_current_subview(debug_view *view)
+// debug_view_manager manages all the views
+class debug_view_manager
{
- return disasm_view_get_subview_by_index(disasm_view_get_subview_list(view), disasm_view_get_subview(view));
-}
+public:
+ // construction/destruction
+ debug_view_manager(running_machine &machine);
+ ~debug_view_manager();
+ // view allocation
+ debug_view *alloc_view(debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate);
+ void free_view(debug_view &view);
-/*-------------------------------------------------
- memory_view_get_subview_by_index - return a
- pointer to a memory subview by index
--------------------------------------------------*/
+ // update helpers
+ void update_all(debug_view_type type = DVT_NONE);
+ void flush_osd_updates();
-INLINE const memory_subview_item *memory_view_get_subview_by_index(const memory_subview_item *itemlist, int index)
-{
- for ( ; itemlist != NULL; itemlist = itemlist->next)
- if (itemlist->index == index)
- return itemlist;
- return NULL;
-}
+private:
+ // private helpers
+ debug_view *append(debug_view *view);
+ // internal state
+ running_machine & m_machine; // reference to our machine
+ debug_view * m_viewlist; // list of views
+};
-/*-------------------------------------------------
- memory_view_get_current_subview - return a
- pointer to the current subview of a
- memory view
--------------------------------------------------*/
-INLINE const memory_subview_item *memory_view_get_current_subview(debug_view *view)
+// debug_view_expression is a helper for handling embedded expressions
+class debug_view_expression
{
- return memory_view_get_subview_by_index(memory_view_get_subview_list(view), memory_view_get_subview(view));
-}
+public:
+ // construction/destruction
+ debug_view_expression(running_machine &machine);
+ ~debug_view_expression();
+
+ // getters
+ bool dirty() const { return m_dirty; }
+ UINT64 last_value() const { return m_result; }
+ UINT64 value() { if (m_dirty) recompute(); return m_result; }
+ const char *string() const { return m_string; }
+ symbol_table *context() const { return m_context; }
+
+ // setters
+ void mark_dirty() { m_dirty = true; }
+ void set_string(const char *string);
+ void set_context(symbol_table *context);
+
+private:
+ // internal helpers
+ bool recompute();
+
+ // internal state
+ running_machine & m_machine; // reference to the machine
+ bool m_dirty; // true if the expression needs to be re-evaluated
+ UINT64 m_result; // last result from the expression
+ parsed_expression * m_parsed; // parsed expression data
+ astring m_string; // copy of the expression string
+ symbol_table * m_context; // context we are using
+};
#endif
diff --git a/src/emu/debug/dvdisasm.c b/src/emu/debug/dvdisasm.c
new file mode 100644
index 00000000000..4df4802ca1f
--- /dev/null
+++ b/src/emu/debug/dvdisasm.c
@@ -0,0 +1,710 @@
+/*********************************************************************
+
+ dvdisasm.c
+
+ Disassembly debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugvw.h"
+#include "dvdisasm.h"
+#include "debugcmt.h"
+#include "debugcpu.h"
+
+
+
+//**************************************************************************
+// DEBUG VIEW DISASM SOURCE
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_disasm_source - constructor
+//-------------------------------------------------
+
+debug_view_disasm_source::debug_view_disasm_source(const char *name, device_t &device)
+ : debug_view_source(name, &device),
+ m_device(device),
+ m_disasmintf(dynamic_cast<device_disasm_interface *>(&device)),
+ m_space(dynamic_cast<device_memory_interface *>(&device)->space(AS_PROGRAM))
+{
+}
+
+
+
+//**************************************************************************
+// DEBUG VIEW DISASM
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_disasm - constructor
+//-------------------------------------------------
+
+debug_view_disasm::debug_view_disasm(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view(machine, DVT_DISASSEMBLY, osdupdate, osdprivate),
+ m_right_column(DASM_RIGHTCOL_RAW),
+ m_backwards_steps(3),
+ m_dasm_width(DEFAULT_DASM_WIDTH),
+ m_last_direct_raw(NULL),
+ m_last_direct_decrypted(NULL),
+ m_last_change_count(0),
+ m_last_pcbyte(0),
+ m_divider1(0),
+ m_divider2(0),
+ m_divider3(0),
+ m_expression(machine),
+ m_allocated(0,0),
+ m_byteaddress(NULL),
+ m_dasm(NULL)
+{
+ // fail if no available sources
+ enumerate_sources();
+ if (m_source_list.count() == 0)
+ throw std::bad_alloc();
+
+ // count the number of comments
+ int total_comments = 0;
+ for (const debug_view_source *source = m_source_list.head(); source != NULL; source = source->next())
+ {
+ const debug_view_disasm_source &dasmsource = downcast<const debug_view_disasm_source &>(*source);
+ total_comments += debug_comment_get_count(&dasmsource.m_device);
+ }
+
+ // initialize
+ if (total_comments > 0)
+ m_right_column = DASM_RIGHTCOL_COMMENTS;
+
+ // configure the view
+ m_total.y = DEFAULT_DASM_LINES;
+ m_supports_cursor = true;
+}
+
+
+//-------------------------------------------------
+// ~debug_view_disasm - destructor
+//-------------------------------------------------
+
+debug_view_disasm::~debug_view_disasm()
+{
+ auto_free(&m_machine, m_byteaddress);
+ auto_free(&m_machine, m_dasm);
+}
+
+
+//-------------------------------------------------
+// enumerate_sources - enumerate all possible
+// sources for a disassembly view
+//-------------------------------------------------
+
+void debug_view_disasm::enumerate_sources()
+{
+ // start with an empty list
+ m_source_list.reset();
+
+ // iterate over devices with disassembly interfaces
+ device_disasm_interface *dasm = NULL;
+ astring name;
+ for (bool gotone = m_machine.devicelist.first(dasm); gotone; gotone = dasm->next(dasm))
+ {
+ name.printf("%s '%s'", dasm->device().name(), dasm->device().tag());
+ m_source_list.append(*auto_alloc(&m_machine, debug_view_disasm_source(name, dasm->device())));
+ }
+
+ // reset the source to a known good entry
+ m_source = m_source_list.head();
+}
+
+
+//-------------------------------------------------
+// view_notify - handle notification of updates
+// to cursor changes
+//-------------------------------------------------
+
+void debug_view_disasm::view_notify(debug_view_notification type)
+{
+ if (type == VIEW_NOTIFY_CURSOR_CHANGED)
+ adjust_visible_y_for_cursor();
+
+ else if (type == VIEW_NOTIFY_SOURCE_CHANGED)
+ m_expression.set_context(debug_cpu_get_symtable(&downcast<const debug_view_disasm_source *>(m_source)->device()));
+}
+
+
+//-------------------------------------------------
+// view_char - handle a character typed within
+// the current view
+//-------------------------------------------------
+
+void debug_view_disasm::view_char(int chval)
+{
+ debug_view_xy origcursor = m_cursor;
+ UINT8 end_buffer = 3;
+ INT32 temp;
+
+ switch (chval)
+ {
+ case DCH_UP:
+ if (m_cursor.y > 0)
+ m_cursor.y--;
+ break;
+
+ case DCH_DOWN:
+ if (m_cursor.y < m_total.y - 1)
+ m_cursor.y++;
+ break;
+
+ case DCH_PUP:
+ temp = m_cursor.y - (m_visible.y - end_buffer);
+ if (temp < 0)
+ m_cursor.y = 0;
+ else
+ m_cursor.y = temp;
+ break;
+
+ case DCH_PDOWN:
+ temp = m_cursor.y + (m_visible.y - end_buffer);
+ if (temp > m_total.y - 1)
+ m_cursor.y = m_total.y - 1;
+ else
+ m_cursor.y = temp;
+ break;
+
+ case DCH_HOME: // set the active column to the PC
+ {
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+ offs_t pc = memory_address_to_byte(source.m_space, cpu_get_pc(&source.m_device)) & source.m_space->logbytemask;
+
+ // figure out which row the pc is on
+ for (int curline = 0; curline < m_allocated.y; curline++)
+ if (m_byteaddress[curline] == pc)
+ m_cursor.y = curline;
+ break;
+ }
+
+ case DCH_CTRLHOME:
+ m_cursor.y = 0;
+ break;
+
+ case DCH_CTRLEND:
+ m_cursor.y = m_total.y - 1;
+ break;
+ }
+
+ /* send a cursor changed notification */
+ if (m_cursor.y != origcursor.y)
+ {
+ begin_update();
+ view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
+ m_update_pending = true;
+ end_update();
+ }
+}
+
+
+//-------------------------------------------------
+// find_pc_backwards - back up the specified
+// number of instructions from the given PC
+//-------------------------------------------------
+
+offs_t debug_view_disasm::find_pc_backwards(offs_t targetpc, int numinstrs)
+{
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+
+ // compute the increment
+ int minlen = memory_byte_to_address(source.m_space, source.m_disasmintf->min_opcode_bytes());
+ if (minlen == 0) minlen = 1;
+ int maxlen = memory_byte_to_address(source.m_space, source.m_disasmintf->max_opcode_bytes());
+ if (maxlen == 0) maxlen = 1;
+
+ // start off numinstrs back
+ offs_t curpc = targetpc - minlen * numinstrs;
+ if (curpc > targetpc)
+ curpc = 0;
+
+ /* loop until we find what we are looking for */
+ offs_t targetpcbyte = memory_address_to_byte(source.m_space, targetpc) & source.m_space->logbytemask;
+ offs_t fillpcbyte = targetpcbyte;
+ offs_t lastgoodpc = targetpc;
+ while (1)
+ {
+ // fill the buffer up to the target
+ offs_t curpcbyte = memory_address_to_byte(source.m_space, curpc) & source.m_space->logbytemask;
+ UINT8 opbuf[1024], argbuf[1024];
+ while (curpcbyte < fillpcbyte)
+ {
+ fillpcbyte--;
+ opbuf[1000 + fillpcbyte - targetpcbyte] = debug_read_opcode(source.m_space, fillpcbyte, 1, FALSE);
+ argbuf[1000 + fillpcbyte - targetpcbyte] = debug_read_opcode(source.m_space, fillpcbyte, 1, TRUE);
+ }
+
+ // loop until we get past the target instruction
+ int instcount = 0;
+ int instlen;
+ offs_t scanpc;
+ for (scanpc = curpc; scanpc < targetpc; scanpc += instlen)
+ {
+ offs_t scanpcbyte = memory_address_to_byte(source.m_space, scanpc) & source.m_space->logbytemask;
+ offs_t physpcbyte = scanpcbyte;
+
+ // get the disassembly, but only if mapped
+ instlen = 1;
+ if (debug_cpu_translate(source.m_space, TRANSLATE_FETCH, &physpcbyte))
+ {
+ char dasmbuffer[100];
+ instlen = source.m_disasmintf->disassemble(dasmbuffer, scanpc, &opbuf[1000 + scanpcbyte - targetpcbyte], &argbuf[1000 + scanpcbyte - targetpcbyte]) & DASMFLAG_LENGTHMASK;
+ }
+
+ // count this one
+ instcount++;
+ }
+
+ // if we ended up right on targetpc, this is a good candidate
+ if (scanpc == targetpc && instcount <= numinstrs)
+ lastgoodpc = curpc;
+
+ // we're also done if we go back too far
+ if (targetpc - curpc >= numinstrs * maxlen)
+ break;
+
+ // and if we hit 0, we're done
+ if (curpc == 0)
+ break;
+
+ // back up one more and try again
+ curpc -= minlen;
+ if (curpc > targetpc)
+ curpc = 0;
+ }
+
+ return lastgoodpc;
+}
+
+
+//-------------------------------------------------
+// generate_bytes - generate the opcode byte
+// values
+//-------------------------------------------------
+
+void debug_view_disasm::generate_bytes(offs_t pcbyte, int numbytes, int minbytes, char *string, int maxchars, bool encrypted)
+{
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+
+ // output the first value
+ int offset = 0;
+ if (maxchars >= 2 * minbytes)
+ offset = sprintf(string, "%s", core_i64_hex_format(debug_read_opcode(source.m_space, pcbyte, minbytes, FALSE), minbytes * 2));
+
+ // output subsequent values
+ int byte;
+ for (byte = minbytes; byte < numbytes && offset + 1 + 2 * minbytes < maxchars; byte += minbytes)
+ offset += sprintf(&string[offset], " %s", core_i64_hex_format(debug_read_opcode(source.m_space, pcbyte + byte, minbytes, encrypted), minbytes * 2));
+
+ // if we ran out of room, indicate more
+ string[maxchars - 1] = 0;
+ if (byte < numbytes && maxchars > 3)
+ string[maxchars - 2] = string[maxchars - 3] = string[maxchars - 4] = '.';
+}
+
+
+//-------------------------------------------------
+// recompute - recompute selected info for the
+// disassembly view
+//-------------------------------------------------
+
+bool debug_view_disasm::recompute(offs_t pc, int startline, int lines)
+{
+ bool changed = false;
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+
+ // determine how many characters we need for an address and set the divider
+ m_divider1 = 1 + source.m_space->logaddrchars + 1;
+
+ // assume a fixed number of characters for the disassembly
+ m_divider2 = m_divider1 + 1 + m_dasm_width + 1;
+
+ // determine how many bytes we might need to display
+ int minbytes = source.m_disasmintf->min_opcode_bytes();
+ int maxbytes = source.m_disasmintf->max_opcode_bytes();
+
+ // ensure that the PC is aligned to the minimum opcode size
+ pc &= ~memory_byte_to_address_end(source.m_space, minbytes - 1);
+
+ // set the width of the third column according to display mode
+ if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED)
+ {
+ int maxbytes_clamped = MIN(maxbytes, DASM_MAX_BYTES);
+ m_total.x = m_divider2 + 1 + 2 * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1;
+ }
+ else if (m_right_column == DASM_RIGHTCOL_COMMENTS)
+ m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH
+ else
+ m_total.x = m_divider2 + 1;
+
+ // reallocate memory if we don't have enough
+ if (m_allocated.x < m_total.x || m_allocated.y < m_total.y)
+ {
+ // update our values
+ m_allocated = m_total;
+
+ // allocate address array
+ auto_free(&m_machine, m_byteaddress);
+ m_byteaddress = auto_alloc_array(&m_machine, offs_t, m_allocated.y);
+
+ // allocate disassembly buffer
+ auto_free(&m_machine, m_dasm);
+ m_dasm = auto_alloc_array(&m_machine, char, m_allocated.x * m_allocated.y);
+ }
+
+ // iterate over lines
+ for (int line = 0; line < lines; line++)
+ {
+ // convert PC to a byte offset
+ offs_t pcbyte = memory_address_to_byte(source.m_space, pc) & source.m_space->logbytemask;
+
+ // save a copy of the previous line as a backup if we're only doing one line
+ int instr = startline + line;
+ char *destbuf = &m_dasm[instr * m_allocated.x];
+ char oldbuf[100];
+ if (lines == 1)
+ strncpy(oldbuf, destbuf, MIN(sizeof(oldbuf), m_allocated.x));
+
+ // convert back and set the address of this instruction
+ m_byteaddress[instr] = pcbyte;
+ sprintf(&destbuf[0], " %s ", core_i64_hex_format(memory_byte_to_address(source.m_space, pcbyte), source.m_space->logaddrchars));
+
+ // make sure we can translate the address, and then disassemble the result
+ char buffer[100];
+ int numbytes = 0;
+ offs_t physpcbyte = pcbyte;
+ if (debug_cpu_translate(source.m_space, TRANSLATE_FETCH_DEBUG, &physpcbyte))
+ {
+ UINT8 opbuf[64], argbuf[64];
+
+ // fetch the bytes up to the maximum
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(source.m_space, pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(source.m_space, pcbyte + numbytes, 1, TRUE);
+ }
+
+ // disassemble the result
+ pc += numbytes = source.m_disasmintf->disassemble(buffer, pc & source.m_space->logaddrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ }
+ else
+ strcpy(buffer, "<unmapped>");
+
+ // append the disassembly to the buffer
+ sprintf(&destbuf[m_divider1 + 1], "%-*s ", m_dasm_width, buffer);
+
+ // output the right column
+ if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED)
+ {
+ // get the bytes
+ numbytes = memory_address_to_byte(source.m_space, numbytes) & source.m_space->logbytemask;
+ generate_bytes(pcbyte, numbytes, minbytes, &destbuf[m_divider2], m_allocated.x - m_divider2, m_right_column == DASM_RIGHTCOL_ENCRYPTED);
+ }
+ else if (m_right_column == DASM_RIGHTCOL_COMMENTS)
+ {
+ // get and add the comment, if present
+ offs_t comment_address = memory_byte_to_address(source.m_space, m_byteaddress[instr]);
+ const char *text = debug_comment_get_text(&source.m_device, comment_address, debug_comment_get_opcode_crc32(&source.m_device, comment_address));
+ if (text != NULL)
+ sprintf(&destbuf[m_divider2], "// %.*s", m_allocated.x - m_divider2 - 1, text);
+ }
+
+ // see if the line changed at all
+ if (lines == 1 && strncmp(oldbuf, destbuf, MIN(sizeof(oldbuf), m_allocated.x)) != 0)
+ changed = true;
+ }
+
+ // update opcode base information
+ m_last_direct_decrypted = source.m_space->direct.decrypted;
+ m_last_direct_raw = source.m_space->direct.raw;
+ m_last_change_count = debug_comment_all_change_count(&m_machine);
+
+ // now longer need to recompute
+ m_recompute = false;
+ return changed;
+}
+
+
+//-------------------------------------------------
+// view_update - update the contents of the
+// disassembly view
+//-------------------------------------------------
+
+void debug_view_disasm::view_update()
+{
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+
+ offs_t pc = cpu_get_pc(&source.m_device);
+ offs_t pcbyte = memory_address_to_byte(source.m_space, pc) & source.m_space->logbytemask;
+
+ // update our context; if the expression is dirty, recompute
+ if (m_expression.dirty())
+ m_recompute = true;
+
+ // if we're tracking a value, make sure it is visible
+ if (m_expression.dirty())
+ {
+ UINT64 previous = m_expression.last_value();
+ UINT64 result = m_expression.value();
+ if (result != previous)
+ {
+ offs_t resultbyte = memory_address_to_byte(source.m_space, result) & source.m_space->logbytemask;
+
+ // see if the new result is an address we already have
+ UINT32 row;
+ for (row = 0; row < m_allocated.y; row++)
+ if (m_byteaddress[row] == resultbyte)
+ break;
+
+ // if we didn't find it, or if it's really close to the bottom, recompute
+ if (row == m_allocated.y || row >= m_total.y - m_visible.y)
+ m_recompute = true;
+
+ // otherwise, if it's not visible, adjust the view so it is
+ else if (row < m_topleft.y || row >= m_topleft.y + m_visible.y - 2)
+ m_topleft.y = (row > 3) ? row - 3 : 0;
+ }
+ }
+
+ // if the opcode base has changed, rework things
+ if (source.m_space->direct.decrypted != m_last_direct_decrypted || source.m_space->direct.raw != m_last_direct_raw)
+ m_recompute = true;
+
+ // if the comments have changed, redo it
+ if (m_last_change_count != debug_comment_all_change_count(&m_machine))
+ m_recompute = true;
+
+ // if we need to recompute, do it
+ bool recomputed_this_time = false;
+recompute:
+ if (m_recompute)
+ {
+ // recompute the view
+ if (m_byteaddress != NULL && m_last_change_count != debug_comment_all_change_count(&m_machine))
+ {
+ // smoosh us against the left column, but not the top row
+ m_topleft.x = 0;
+
+ // recompute from where we last recomputed!
+ recompute(memory_byte_to_address(source.m_space, m_byteaddress[0]), 0, m_total.y);
+ }
+ else
+ {
+ // determine the addresses of what we will display
+ offs_t backpc = find_pc_backwards((UINT32)m_expression.value(), m_backwards_steps);
+
+ // put ourselves back in the top left
+ m_topleft.y = 0;
+ m_topleft.x = 0;
+
+ recompute(backpc, 0, m_total.y);
+ }
+ recomputed_this_time = true;
+ }
+
+ // figure out the row where the PC is and recompute the disassembly
+ if (pcbyte != m_last_pcbyte)
+ {
+ // find the row with the PC on it
+ for (UINT32 row = 0; row < m_visible.y; row++)
+ {
+ UINT32 effrow = m_topleft.y + row;
+ if (effrow >= m_allocated.y)
+ break;
+ if (pcbyte == m_byteaddress[effrow])
+ {
+ // see if we changed
+ bool changed = recompute(pc, effrow, 1);
+ if (changed && !recomputed_this_time)
+ {
+ m_recompute = true;
+ goto recompute;
+ }
+
+ // set the effective row and PC
+ m_cursor.y = effrow;
+ view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
+ }
+ }
+ m_last_pcbyte = pcbyte;
+ }
+
+ // loop over visible rows
+ debug_view_char *dest = m_viewdata;
+ for (UINT32 row = 0; row < m_visible.y; row++)
+ {
+ UINT32 effrow = m_topleft.y + row;
+ UINT32 col = 0;
+
+ // if this visible row is valid, add it to the buffer
+ UINT8 attrib = DCA_NORMAL;
+ if (effrow < m_allocated.y)
+ {
+ // if we're on the line with the PC, recompute and hilight it
+ if (pcbyte == m_byteaddress[effrow])
+ attrib = DCA_CURRENT;
+
+ // if we're on a line with a breakpoint, tag it changed
+ else
+ {
+ const cpu_debug_data *cpuinfo = cpu_get_debug_data(&source.m_device);
+ for (debug_cpu_breakpoint *bp = cpuinfo->bplist; bp != NULL; bp = bp->next)
+ if (m_byteaddress[effrow] == (memory_address_to_byte(source.m_space, bp->address) & source.m_space->logbytemask))
+ attrib = DCA_CHANGED;
+ }
+
+ // if we're on the active column and everything is couth, highlight it
+ if (m_cursor_visible && effrow == m_cursor.y)
+ attrib |= DCA_SELECTED;
+
+ // get the effective string
+ const char *data = &m_dasm[effrow * m_allocated.x];
+ UINT32 len = (UINT32)strlen(data);
+
+ // copy data
+ UINT32 effcol = m_topleft.x;
+ while (col < m_visible.x && effcol < len)
+ {
+ dest->byte = data[effcol++];
+ dest->attrib = (effcol <= m_divider1 || effcol >= m_divider2) ? (attrib | DCA_ANCILLARY) : attrib;
+
+ // comments are just green for now - maybe they shouldn't even be this?
+ if (effcol >= m_divider2 && m_right_column == DASM_RIGHTCOL_COMMENTS)
+ attrib |= DCA_COMMENT;
+
+ dest++;
+ col++;
+ }
+ }
+
+ // fill the rest with blanks
+ while (col < m_visible.x)
+ {
+ dest->byte = ' ';
+ dest->attrib = (effrow < m_total.y) ? (attrib | DCA_ANCILLARY) : attrib;
+ dest++;
+ col++;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// selected_address - return the PC of the
+// currently selected address in the view
+//-------------------------------------------------
+
+offs_t debug_view_disasm::selected_address()
+{
+ flush_updates();
+ return memory_byte_to_address(downcast<const debug_view_disasm_source &>(*m_source).m_space, m_byteaddress[m_cursor.y]);
+}
+
+
+//-------------------------------------------------
+// set_sexpression - set the expression string
+// describing the home address
+//-------------------------------------------------
+
+void debug_view_disasm::set_expression(const char *expression)
+{
+ begin_update();
+ m_expression.set_string(expression);
+ m_recompute = m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// set_right_column - set the contents of the
+// right column
+//-------------------------------------------------
+
+void debug_view_disasm::set_right_column(disasm_right_column contents)
+{
+ begin_update();
+ m_right_column = contents;
+ m_recompute = m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// set_backward_steps - set the number of
+// instructions displayed before the home address
+//-------------------------------------------------
+
+void debug_view_disasm::set_backward_steps(UINT32 steps)
+{
+ begin_update();
+ m_backwards_steps = steps;
+ m_recompute = m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// set_disasm_width - set the width in characters
+// of the main disassembly section
+//-------------------------------------------------
+
+void debug_view_disasm::set_disasm_width(UINT32 width)
+{
+ begin_update();
+ m_dasm_width = width;
+ m_recompute = m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// set_selected_address - set the PC of the
+// currently selected address in the view
+//-------------------------------------------------
+
+void debug_view_disasm::set_selected_address(offs_t address)
+{
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+ offs_t byteaddress = memory_address_to_byte(source.m_space, address) & source.m_space->logbytemask;
+ for (int line = 0; line < m_total.y; line++)
+ if (m_byteaddress[line] == byteaddress)
+ {
+ m_cursor.y = line;
+ set_cursor_position(m_cursor);
+ break;
+ }
+}
diff --git a/src/emu/debug/dvdisasm.h b/src/emu/debug/dvdisasm.h
new file mode 100644
index 00000000000..b34c0758e4b
--- /dev/null
+++ b/src/emu/debug/dvdisasm.h
@@ -0,0 +1,146 @@
+/*********************************************************************
+
+ dvdisasm.h
+
+ Disassembly debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef __DVDISASM_H__
+#define __DVDISASM_H__
+
+#include "debugvw.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// selections for what goes into the right-hand column
+enum disasm_right_column
+{
+ DASM_RIGHTCOL_NONE,
+ DASM_RIGHTCOL_RAW,
+ DASM_RIGHTCOL_ENCRYPTED,
+ DASM_RIGHTCOL_COMMENTS
+};
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a disassembly view_source
+class debug_view_disasm_source : public debug_view_source
+{
+ friend class debug_view_disasm;
+
+ // construction/destruction
+ debug_view_disasm_source(const char *name, device_t &device);
+
+public:
+ // getters
+ device_t &device() const { return m_device; }
+ const address_space *space() const { return m_space; }
+
+private:
+ // internal state
+ device_t & m_device; // underlying device
+ device_disasm_interface *m_disasmintf; // disassembly interface
+ const address_space *m_space; // address space to display
+};
+
+
+// debug view for disassembly
+class debug_view_disasm : public debug_view
+{
+ friend resource_pool_object<debug_view_disasm>::~resource_pool_object();
+ friend class debug_view_manager;
+
+ // construction/destruction
+ debug_view_disasm(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+ virtual ~debug_view_disasm();
+
+public:
+ // getters
+ const char *expression() const { return m_expression.string(); }
+ disasm_right_column right_column() const { return m_right_column; }
+ UINT32 backward_steps() const { return m_backwards_steps; }
+ UINT32 disasm_width() const { return m_dasm_width; }
+ offs_t selected_address();
+
+ // setters
+ void set_expression(const char *expression);
+ void set_right_column(disasm_right_column contents);
+ void set_backward_steps(UINT32 steps);
+ void set_disasm_width(UINT32 width);
+ void set_selected_address(offs_t address);
+
+protected:
+ // view overrides
+ virtual void view_update();
+ virtual void view_notify(debug_view_notification type);
+ virtual void view_char(int chval);
+
+private:
+ // internal helpers
+ void enumerate_sources();
+ offs_t find_pc_backwards(offs_t targetpc, int numinstrs);
+ void generate_bytes(offs_t pcbyte, int numbytes, int minbytes, char *string, int maxchars, bool encrypted);
+ bool recompute(offs_t pc, int startline, int lines);
+
+ // internal state
+ disasm_right_column m_right_column; // right column contents
+ UINT32 m_backwards_steps; // number of backwards steps
+ UINT32 m_dasm_width; // width of the disassembly area
+ UINT8 * m_last_direct_raw; // last direct raw value
+ UINT8 * m_last_direct_decrypted;// last direct decrypted value
+ UINT32 m_last_change_count; // last comment change count
+ offs_t m_last_pcbyte; // last PC byte value
+ int m_divider1, m_divider2; // left and right divider columns
+ int m_divider3; // comment divider column
+ debug_view_expression m_expression; // expression-related information
+ debug_view_xy m_allocated; // allocated rows/columns
+ offs_t * m_byteaddress; // addresses of the instructions
+ char * m_dasm; // disassembled instructions
+
+ // constants
+ static const int DEFAULT_DASM_LINES = 1000;
+ static const int DEFAULT_DASM_WIDTH = 50;
+ static const int DASM_MAX_BYTES = 16;
+};
+
+
+#endif
diff --git a/src/emu/debug/dvmemory.c b/src/emu/debug/dvmemory.c
new file mode 100644
index 00000000000..8344c721882
--- /dev/null
+++ b/src/emu/debug/dvmemory.c
@@ -0,0 +1,813 @@
+/*********************************************************************
+
+ dvmemory.c
+
+ Memory debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugvw.h"
+#include "dvmemory.h"
+#include "debugcpu.h"
+#include <ctype.h>
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const debug_view_memory::memory_view_pos debug_view_memory::s_memory_pos_table[9] =
+{
+ /* 0 bytes per chunk: */ { 0, { 0 } },
+ /* 1 byte per chunk: 00 11 22 33 44 55 66 77 */ { 3, { 0x04, 0x00, 0x80 } },
+ /* 2 bytes per chunk: 0011 2233 4455 6677 */ { 6, { 0x8c, 0x0c, 0x08, 0x04, 0x00, 0x80 } },
+ /* 3 bytes per chunk: */ { 0, { 0 } },
+ /* 4 bytes per chunk: 00112233 44556677 */ { 12, { 0x9c, 0x9c, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80 } },
+ /* 5 bytes per chunk: */ { 0, { 0 } },
+ /* 6 bytes per chunk: */ { 0, { 0 } },
+ /* 7 bytes per chunk: */ { 0, { 0 } },
+ /* 8 bytes per chunk: 0011223344556677 */ { 24, { 0xbc, 0xbc, 0xbc, 0xbc, 0x3c, 0x38, 0x34, 0x30, 0x2c, 0x28, 0x24, 0x20, 0x1c, 0x18, 0x14, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80 } }
+};
+
+
+
+//**************************************************************************
+// DEBUG VIEW MEMORY SOURCE
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_memory_source - constructors
+//-------------------------------------------------
+
+debug_view_memory_source::debug_view_memory_source(const char *name, const address_space &space)
+ : debug_view_source(name, space.cpu),
+ m_space(&space),
+ m_memintf(dynamic_cast<device_memory_interface *>(space.cpu)),
+ m_base(NULL),
+ m_length(0),
+ m_offsetxor(0),
+ m_endianness(space.endianness),
+ m_prefsize(space.dbits / 8)
+{
+}
+
+debug_view_memory_source::debug_view_memory_source(const char *name, const region_info &region)
+ : debug_view_source(name),
+ m_space(NULL),
+ m_memintf(NULL),
+ m_base(region),
+ m_length(region.bytes()),
+ m_offsetxor(NATIVE_ENDIAN_VALUE_LE_BE(region.width() - 1, 0)),
+ m_endianness(region.endianness()),
+ m_prefsize(MIN(region.width(), 8))
+{
+}
+
+debug_view_memory_source::debug_view_memory_source(const char *name, void *base, int element_size, int num_elements)
+ : debug_view_source(name),
+ m_space(NULL),
+ m_memintf(NULL),
+ m_base(base),
+ m_length(element_size * num_elements),
+ m_offsetxor(0),
+ m_endianness(ENDIANNESS_NATIVE),
+ m_prefsize(MIN(element_size, 8))
+{
+}
+
+
+
+//**************************************************************************
+// DEBUG VIEW MEMORY
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_memory - constructor
+//-------------------------------------------------
+
+debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view(machine, DVT_MEMORY, osdupdate, osdprivate),
+ m_expression(machine),
+ m_chunks_per_row(16),
+ m_bytes_per_chunk(1),
+ m_reverse_view(false),
+ m_ascii_view(true),
+ m_no_translation(false),
+ m_maxaddr(0),
+ m_bytes_per_row(16),
+ m_byte_offset(0)
+{
+ // fail if no available sources
+ enumerate_sources();
+ if (m_source_list.count() == 0)
+ throw std::bad_alloc();
+
+ // configure the view
+ m_supports_cursor = true;
+}
+
+
+//-------------------------------------------------
+// enumerate_sources - enumerate all possible
+// sources for a memory view
+//-------------------------------------------------
+
+void debug_view_memory::enumerate_sources()
+{
+ // start with an empty list
+ m_source_list.reset();
+ astring name;
+
+ // first add all the devices' address spaces
+ device_memory_interface *memintf = NULL;
+ for (bool gotone = m_machine.devicelist.first(memintf); gotone; gotone = memintf->next(memintf))
+ for (int spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ const address_space *space = memintf->space(spacenum);
+ if (space != NULL)
+ {
+ name.printf("%s '%s' %s space memory", memintf->device().name(), memintf->device().tag(), space->name);
+ m_source_list.append(*auto_alloc(&m_machine, debug_view_memory_source(name, *space)));
+ }
+ }
+
+ // then add all the memory regions
+ for (const region_info *region = m_machine.regionlist.first(); region != NULL; region = region->next())
+ {
+ name.printf("Region '%s'", region->name.cstr());
+ m_source_list.append(*auto_alloc(&m_machine, debug_view_memory_source(name, *region)));
+ }
+
+ // finally add all global array symbols
+ for (int itemnum = 0; itemnum < 10000; itemnum++)
+ {
+ // stop when we run out of items
+ UINT32 valsize, valcount;
+ void *base;
+ const char *itemname = state_save_get_indexed_item(&m_machine, itemnum, &base, &valsize, &valcount);
+ if (itemname == NULL)
+ break;
+
+ // if this is a single-entry global, add it
+ if (valcount > 1 && strstr(itemname, "globals/"))
+ {
+ name.cpy(strrchr(itemname, '/') + 1);
+ m_source_list.append(*auto_alloc(&m_machine, debug_view_memory_source(name, base, valsize, valcount)));
+ }
+ }
+ m_source = m_source_list.head();
+}
+
+
+//-------------------------------------------------
+// view_notify - handle notification of updates
+// to cursor changes
+//-------------------------------------------------
+
+void debug_view_memory::view_notify(debug_view_notification type)
+{
+ if (type == VIEW_NOTIFY_CURSOR_CHANGED)
+ {
+ // normalize the cursor
+ set_cursor_pos(get_cursor_pos());
+ }
+ else if (type == VIEW_NOTIFY_SOURCE_CHANGED)
+ {
+ // update for the new source
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+ m_chunks_per_row = m_bytes_per_chunk * m_chunks_per_row / source.m_prefsize;
+ m_bytes_per_chunk = source.m_prefsize;
+ if (source.m_space != NULL)
+ m_expression.set_context(debug_cpu_get_symtable(source.m_space->cpu));
+ else
+ m_expression.set_context(NULL);
+ }
+}
+
+
+//-------------------------------------------------
+// view_update - update the contents of the
+// memory view
+//-------------------------------------------------
+
+void debug_view_memory::view_update()
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+
+ // if we need to recompute, do it now
+ if (needs_recompute())
+ recompute();
+
+ // get positional data
+ const memory_view_pos &posdata = s_memory_pos_table[m_bytes_per_chunk];
+
+ // loop over visible rows
+ for (UINT32 row = 0; row < m_visible.y; row++)
+ {
+ debug_view_char *destmin = m_viewdata + row * m_visible.x;
+ debug_view_char *destmax = destmin + m_visible.x;
+ debug_view_char *destrow = destmin - m_topleft.x;
+ UINT32 effrow = m_topleft.y + row;
+
+ // reset the line of data; section 1 is normal, others are ancillary, cursor is selected
+ debug_view_char *dest = destmin;
+ for (int ch = 0; ch < m_visible.x; ch++, dest++)
+ {
+ UINT32 effcol = m_topleft.x + ch;
+ dest->byte = ' ';
+ dest->attrib = DCA_ANCILLARY;
+ if (m_section[1].contains(effcol))
+ {
+ dest->attrib = DCA_NORMAL;
+ if (m_cursor_visible && effrow == m_cursor.y && effcol == m_cursor.x)
+ dest->attrib |= DCA_SELECTED;
+ }
+ }
+
+ // if this visible row is valid, add it to the buffer
+ if (effrow < m_total.y)
+ {
+ offs_t addrbyte = m_byte_offset + effrow * m_bytes_per_row;
+ offs_t address = (source.m_space != NULL) ? memory_byte_to_address(source.m_space, addrbyte) : addrbyte;
+ char addrtext[20];
+
+ // generate the address
+ sprintf(addrtext, m_addrformat, address);
+ dest = destrow + m_section[0].m_pos + 1;
+ for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++)
+ if (dest >= destmin && dest < destmax)
+ dest->byte = addrtext[ch];
+
+ // generate the data
+ for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++)
+ {
+ int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum;
+
+ UINT64 chunkdata;
+ bool ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata);
+ dest = destrow + m_section[1].m_pos + 1 + chunkindex * posdata.m_spacing;
+ for (int ch = 0; ch < posdata.m_spacing; ch++, dest++)
+ if (dest >= destmin && dest < destmax)
+ {
+ UINT8 shift = posdata.m_shift[ch];
+ if (shift < 64)
+ dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*';
+ }
+ }
+
+ // generate the ASCII data
+ if (m_section[2].m_width > 0)
+ {
+ dest = destrow + m_section[2].m_pos + 1;
+ for (int ch = 0; ch < m_bytes_per_row; ch++, dest++)
+ if (dest >= destmin && dest < destmax)
+ {
+ UINT64 chval;
+ bool ismapped = read(1, addrbyte + ch, chval);
+ dest->byte = (ismapped && isprint(chval)) ? chval : '.';
+ }
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// view_char - handle a character typed within
+// the current view
+//-------------------------------------------------
+
+void debug_view_memory::view_char(int chval)
+{
+ // get the position
+ cursor_pos pos = get_cursor_pos();
+
+ // handle the incoming key
+ switch (chval)
+ {
+ case DCH_UP:
+ if (pos.m_address >= m_byte_offset + m_bytes_per_row)
+ pos.m_address -= m_bytes_per_row;
+ break;
+
+ case DCH_DOWN:
+ if (pos.m_address <= m_maxaddr - m_bytes_per_row)
+ pos.m_address += m_bytes_per_row;
+ break;
+
+ case DCH_PUP:
+ for (UINT32 delta = (m_visible.y - 2) * m_bytes_per_row; delta > 0; delta -= m_bytes_per_row)
+ if (pos.m_address >= m_byte_offset + delta)
+ {
+ pos.m_address -= delta;
+ break;
+ }
+ break;
+
+ case DCH_PDOWN:
+ for (UINT32 delta = (m_visible.y - 2) * m_bytes_per_row; delta > 0; delta -= m_bytes_per_row)
+ if (pos.m_address <= m_maxaddr - delta)
+ {
+ pos.m_address += delta;
+ break;
+ }
+ break;
+
+ case DCH_HOME:
+ pos.m_address -= pos.m_address % m_bytes_per_row;
+ pos.m_shift = (m_bytes_per_chunk * 8) - 4;
+ break;
+
+ case DCH_CTRLHOME:
+ pos.m_address = m_byte_offset;
+ pos.m_shift = (m_bytes_per_chunk * 8) - 4;
+ break;
+
+ case DCH_END:
+ pos.m_address += (m_bytes_per_row - (pos.m_address % m_bytes_per_row) - 1);
+ pos.m_shift = 0;
+ break;
+
+ case DCH_CTRLEND:
+ pos.m_address = m_maxaddr;
+ pos.m_shift = 0;
+ break;
+
+ case DCH_CTRLLEFT:
+ if (pos.m_address >= m_byte_offset + m_bytes_per_chunk)
+ pos.m_address -= m_bytes_per_chunk;
+ break;
+
+ case DCH_CTRLRIGHT:
+ if (pos.m_address <= m_maxaddr - m_bytes_per_chunk)
+ pos.m_address += m_bytes_per_chunk;
+ break;
+
+ default:
+ {
+ static const char hexvals[] = "0123456789abcdef";
+ char *hexchar = (char *)strchr(hexvals, tolower(chval));
+ if (hexchar == NULL)
+ break;
+
+ UINT64 data;
+ bool ismapped = read(m_bytes_per_chunk, pos.m_address, data);
+ if (!ismapped)
+ break;
+
+ data &= ~((UINT64)0x0f << pos.m_shift);
+ data |= (UINT64)(hexchar - hexvals) << pos.m_shift;
+ write(m_bytes_per_chunk, pos.m_address, data);
+ // fall through...
+ }
+
+ case DCH_RIGHT:
+ if (pos.m_shift == 0 && pos.m_address != m_maxaddr)
+ {
+ pos.m_shift = m_bytes_per_chunk * 8 - 4;
+ pos.m_address += m_bytes_per_chunk;
+ }
+ else
+ pos.m_shift -= 4;
+ break;
+
+ case DCH_LEFT:
+ if (pos.m_shift == m_bytes_per_chunk * 8 - 4 && pos.m_address != m_byte_offset)
+ {
+ pos.m_shift = 0;
+ pos.m_address -= m_bytes_per_chunk;
+ }
+ else
+ pos.m_shift += 4;
+ break;
+ }
+
+ // set a new position
+ begin_update();
+ set_cursor_pos(pos);
+ m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// recompute - recompute the internal data and
+// structure of the memory view
+//-------------------------------------------------
+
+void debug_view_memory::recompute()
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+
+ // get the current cursor position
+ cursor_pos pos = get_cursor_pos();
+
+ // determine the maximum address and address format string from the raw information
+ int addrchars;
+ if (source.m_space != NULL)
+ {
+ m_maxaddr = m_no_translation ? source.m_space->bytemask : source.m_space->logbytemask;
+ addrchars = m_no_translation ? source.m_space->addrchars : source.m_space->logaddrchars;
+ }
+ else
+ {
+ m_maxaddr = source.m_length - 1;
+ addrchars = m_addrformat.printf("%X", m_maxaddr);
+ }
+
+ // generate an 8-byte aligned format for the address
+ if (!m_reverse_view)
+ m_addrformat.printf("%*s%%0%dX", 8 - addrchars, "", addrchars);
+ else
+ m_addrformat.printf("%%0%dX%*s", addrchars, 8 - addrchars, "");
+
+ // if we are viewing a space with a minimum chunk size, clamp the bytes per chunk
+ if (source.m_space != NULL && source.m_space->ashift < 0)
+ {
+ UINT32 min_bytes_per_chunk = 1 << -source.m_space->ashift;
+ while (m_bytes_per_chunk < min_bytes_per_chunk)
+ {
+ m_bytes_per_chunk *= 2;
+ m_chunks_per_row /= 2;
+ }
+ m_chunks_per_row = MAX(1, m_chunks_per_row);
+ }
+
+ // recompute the byte offset based on the most recent expression result
+ m_bytes_per_row = m_bytes_per_chunk * m_chunks_per_row;
+ m_byte_offset = m_expression.value() % m_bytes_per_row;
+
+ // compute the section widths
+ m_section[0].m_width = 1 + 8 + 1;
+ m_section[1].m_width = 1 + 3 * m_bytes_per_row + 1;
+ m_section[2].m_width = m_ascii_view ? (1 + m_bytes_per_row + 1) : 0;
+
+ // compute the section positions
+ if (!m_reverse_view)
+ {
+ m_section[0].m_pos = 0;
+ m_section[1].m_pos = m_section[0].m_pos + m_section[0].m_width;
+ m_section[2].m_pos = m_section[1].m_pos + m_section[1].m_width;
+ m_total.x = m_section[2].m_pos + m_section[2].m_width;
+ }
+ else
+ {
+ m_section[2].m_pos = 0;
+ m_section[1].m_pos = m_section[2].m_pos + m_section[2].m_width;
+ m_section[0].m_pos = m_section[1].m_pos + m_section[1].m_width;
+ m_total.x = m_section[0].m_pos + m_section[0].m_width;
+ }
+
+ // derive total sizes from that
+ m_total.y = ((UINT64)m_maxaddr - (UINT64)m_byte_offset + (UINT64)m_bytes_per_row - 1) / m_bytes_per_row;
+
+ // reset the current cursor position
+ set_cursor_pos(pos);
+}
+
+
+//-------------------------------------------------
+// needs_recompute - determine if anything has
+// changed that requires a recomputation
+//-------------------------------------------------
+
+bool debug_view_memory::needs_recompute()
+{
+ bool recompute = m_recompute;
+
+ // handle expression changes
+ if (m_expression.dirty())
+ {
+ recompute = true;
+ m_topleft.y = (m_expression.value() - m_byte_offset) / m_bytes_per_row;
+ m_topleft.y = MAX(m_topleft.y, 0);
+ m_topleft.y = MIN(m_topleft.y, m_total.y - 1);
+
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+ offs_t resultbyte;
+ if (source.m_space != NULL)
+ resultbyte = memory_address_to_byte(source.m_space, m_expression.value()) & source.m_space->logbytemask;
+ else
+ resultbyte = m_expression.value();
+
+ set_cursor_pos(cursor_pos(resultbyte, m_bytes_per_chunk * 8 - 4));
+ }
+
+ // expression is clean at this point, and future recomputation is not necessary
+ m_recompute = false;
+ return recompute;
+}
+
+
+//-------------------------------------------------
+// get_cursor_pos - return the cursor position as
+// an address and a shift value
+//-------------------------------------------------
+
+debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos()
+{
+ // start with the base address for this row
+ cursor_pos pos;
+ pos.m_address = m_byte_offset + m_cursor.y * m_bytes_per_chunk * m_chunks_per_row;
+
+ // determine the X position within the middle section, clamping as necessary
+ const memory_view_pos &posdata = s_memory_pos_table[m_bytes_per_chunk];
+ int xposition = m_cursor.x - m_section[1].m_pos - 1;
+ if (xposition < 0)
+ xposition = 0;
+ else if (xposition >= posdata.m_spacing * m_chunks_per_row)
+ xposition = posdata.m_spacing * m_chunks_per_row - 1;
+
+ // compute chunk number and offset within that chunk
+ int chunknum = xposition / posdata.m_spacing;
+ int chunkoffs = xposition % posdata.m_spacing;
+
+ // reverse the chunknum if we're reversed
+ if (m_reverse_view)
+ chunknum = m_chunks_per_row - 1 - chunknum;
+
+ // compute the address and shift
+ pos.m_address += chunknum * m_bytes_per_chunk;
+ pos.m_shift = posdata.m_shift[chunkoffs] & 0x7f;
+ return pos;
+}
+
+
+//-------------------------------------------------
+// set_cursor_pos - set the cursor position as a
+// function of an address and a shift value
+//-------------------------------------------------
+
+void debug_view_memory::set_cursor_pos(cursor_pos pos)
+{
+ const memory_view_pos &posdata = s_memory_pos_table[m_bytes_per_chunk];
+
+ // offset the address by the byte offset
+ if (pos.m_address < m_byte_offset)
+ pos.m_address = m_byte_offset;
+ pos.m_address -= m_byte_offset;
+
+ // compute the Y coordinate and chunk index
+ m_cursor.y = pos.m_address / m_bytes_per_row;
+ int chunknum = (pos.m_address % m_bytes_per_row) / m_bytes_per_chunk;
+
+ // reverse the chunknum if we're reversed
+ if (m_reverse_view)
+ chunknum = m_chunks_per_row - 1 - chunknum;
+
+ // scan within the chunk to find the shift
+ for (m_cursor.x = 0; m_cursor.x < posdata.m_spacing; m_cursor.x++)
+ if (posdata.m_shift[m_cursor.x] == pos.m_shift)
+ break;
+
+ // add in the chunk offset and shift to the right of divider1
+ m_cursor.x += m_section[1].m_pos + 1 + posdata.m_spacing * chunknum;
+
+ // clamp to the window bounds
+ m_cursor.x = MIN(m_cursor.x, m_total.x);
+ m_cursor.y = MIN(m_cursor.y, m_total.y);
+
+ // scroll if out of range
+ adjust_visible_x_for_cursor();
+ adjust_visible_y_for_cursor();
+}
+
+
+//-------------------------------------------------
+// read - generic memory view data reader
+//-------------------------------------------------
+
+bool debug_view_memory::read(UINT8 size, offs_t offs, UINT64 &data)
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+
+ // if no raw data, just use the standard debug routines
+ if (source.m_space != NULL)
+ {
+ offs_t dummyaddr = offs;
+
+ bool ismapped = m_no_translation ? true : source.m_memintf->translate(source.m_space->spacenum, TRANSLATE_READ_DEBUG, dummyaddr);
+ data = ~(UINT64)0;
+ if (ismapped)
+ {
+ switch (size)
+ {
+ case 1: data = debug_read_byte(source.m_space, offs, !m_no_translation); break;
+ case 2: data = debug_read_word(source.m_space, offs, !m_no_translation); break;
+ case 4: data = debug_read_dword(source.m_space, offs, !m_no_translation); break;
+ case 8: data = debug_read_qword(source.m_space, offs, !m_no_translation); break;
+ }
+ }
+ return ismapped;
+ }
+
+ // if larger than a byte, reduce by half and recurse
+ if (size > 1)
+ {
+ size /= 2;
+
+ UINT64 data0, data1;
+ bool ismapped = read(size, offs + 0 * size, data0);
+ ismapped |= read(size, offs + 1 * size, data1);
+
+ if (source.m_endianness == ENDIANNESS_LITTLE)
+ data = data0 | (data1 << (size * 8));
+ else
+ data = data1 | (data0 << (size * 8));
+ return ismapped;
+ }
+
+ // all 0xff if out of bounds
+ offs ^= source.m_offsetxor;
+ if (offs >= source.m_length)
+ return false;
+ data = *((UINT8 *)source.m_base + offs);
+ return true;
+}
+
+
+//-------------------------------------------------
+// write - generic memory view data writer
+//-------------------------------------------------
+
+void debug_view_memory::write(UINT8 size, offs_t offs, UINT64 data)
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+
+ // if no raw data, just use the standard debug routines
+ if (source.m_space != NULL)
+ {
+ switch (size)
+ {
+ case 1: debug_write_byte(source.m_space, offs, data, !m_no_translation); break;
+ case 2: debug_write_word(source.m_space, offs, data, !m_no_translation); break;
+ case 4: debug_write_dword(source.m_space, offs, data, !m_no_translation); break;
+ case 8: debug_write_qword(source.m_space, offs, data, !m_no_translation); break;
+ }
+ return;
+ }
+
+ // if larger than a byte, reduce by half and recurse
+ if (size > 1)
+ {
+ size /= 2;
+ if (source.m_endianness == ENDIANNESS_LITTLE)
+ {
+ write(size, offs + 0 * size, data);
+ write(size, offs + 1 * size, data >> (8 * size));
+ }
+ else
+ {
+ write(size, offs + 1 * size, data);
+ write(size, offs + 0 * size, data >> (8 * size));
+ }
+ return;
+ }
+
+ // ignore if out of bounds
+ offs ^= source.m_offsetxor;
+ if (offs >= source.m_length)
+ return;
+ *((UINT8 *)source.m_base + offs) = data;
+
+// hack for FD1094 editing
+#ifdef FD1094_HACK
+ if (source.m_base == *m_machine.region("user2"))
+ {
+ extern void fd1094_regenerate_key(running_machine *machine);
+ fd1094_regenerate_key(&m_machine);
+ }
+#endif
+}
+
+
+//-------------------------------------------------
+// set_expression - set the expression string
+// describing the home address
+//-------------------------------------------------
+
+void debug_view_memory::set_expression(const char *expression)
+{
+ begin_update();
+ m_expression.set_string(expression);
+ m_recompute = m_update_pending = true;
+ end_update();
+}
+
+
+//-------------------------------------------------
+// set_bytes_per_chunk - specify the number of
+// bytes displayed per chunk
+//-------------------------------------------------
+
+void debug_view_memory::set_bytes_per_chunk(UINT8 chunkbytes)
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+
+ cursor_pos pos = begin_update_and_get_cursor_pos();
+ pos.m_address += (pos.m_shift / 8) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1));
+ pos.m_shift %= 8;
+
+ m_bytes_per_chunk = chunkbytes;
+ m_chunks_per_row = m_bytes_per_row / chunkbytes;
+ m_recompute = m_update_pending = true;
+
+ pos.m_shift += 8 * ((pos.m_address % m_bytes_per_chunk) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1)));
+ pos.m_address -= pos.m_address % m_bytes_per_chunk;
+
+ m_recompute = m_update_pending = true;
+ end_update_and_set_cursor_pos(pos);
+}
+
+
+//-------------------------------------------------
+// set_chunks_per_row - specify the number of
+// chunks displayed across a row
+//-------------------------------------------------
+
+void debug_view_memory::set_chunks_per_row(UINT32 rowchunks)
+{
+ if (rowchunks < 1)
+ return;
+
+ cursor_pos pos = begin_update_and_get_cursor_pos();
+ m_chunks_per_row = rowchunks;
+ m_recompute = m_update_pending = true;
+ end_update_and_set_cursor_pos(pos);
+}
+
+
+//-------------------------------------------------
+// set_reverse - specify true if the memory view
+// is displayed reverse
+//-------------------------------------------------
+
+void debug_view_memory::set_reverse(bool reverse)
+{
+ cursor_pos pos = begin_update_and_get_cursor_pos();
+ m_reverse_view = reverse;
+ m_recompute = m_update_pending = true;
+ end_update_and_set_cursor_pos(pos);
+}
+
+
+//-------------------------------------------------
+// set_ascii - specify TRUE if the memory view
+// should display an ASCII representation
+//-------------------------------------------------
+
+void debug_view_memory::set_ascii(bool ascii)
+{
+ cursor_pos pos = begin_update_and_get_cursor_pos();
+ m_ascii_view = ascii;
+ m_recompute = m_update_pending = true;
+ end_update_and_set_cursor_pos(pos);
+}
+
+
+//-------------------------------------------------
+// set_physical - specify true if the memory view
+// should display physical addresses versus
+// logical addresses
+//-------------------------------------------------
+
+void debug_view_memory::set_physical(bool physical)
+{
+ cursor_pos pos = begin_update_and_get_cursor_pos();
+ m_no_translation = physical;
+ m_recompute = m_update_pending = true;
+ end_update_and_set_cursor_pos(pos);
+}
diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h
new file mode 100644
index 00000000000..ee1bfa7080d
--- /dev/null
+++ b/src/emu/debug/dvmemory.h
@@ -0,0 +1,160 @@
+/*********************************************************************
+
+ dvmemory.h
+
+ Memory debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef __DVMEMORY_H__
+#define __DVMEMORY_H__
+
+#include "dvstate.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a memory view_source
+class debug_view_memory_source : public debug_view_source
+{
+ friend class debug_view_memory;
+
+ debug_view_memory_source(const char *name, const address_space &space);
+ debug_view_memory_source(const char *name, const region_info &region);
+ debug_view_memory_source(const char *name, void *base, int element_size, int num_elements);
+
+public:
+ const address_space *space() const { return m_space; }
+
+private:
+ const address_space *m_space; // address space we reference (if any)
+ device_memory_interface *m_memintf; // pointer to the memory interface of the device
+ void * m_base; // pointer to memory base
+ offs_t m_length; // length of memory
+ offs_t m_offsetxor; // XOR to apply to offsets
+ endianness_t m_endianness; // endianness of memory
+ UINT8 m_prefsize; // preferred bytes per chunk
+};
+
+
+// debug view for memory
+class debug_view_memory : public debug_view
+{
+ friend resource_pool_object<debug_view_memory>::~resource_pool_object();
+ friend class debug_view_manager;
+
+ // construction/destruction
+ debug_view_memory(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+
+public:
+ // getters
+ const char *expression() { return m_expression.string(); }
+ UINT8 bytes_per_chunk() { flush_updates(); return m_bytes_per_chunk; }
+ UINT8 chunks_per_row() { flush_updates(); return m_chunks_per_row; }
+ bool reverse() const { return m_reverse_view; }
+ bool ascii() const { return m_ascii_view; }
+ bool physical() const { return m_no_translation; }
+
+ // setters
+ void set_expression(const char *expression);
+ void set_bytes_per_chunk(UINT8 chunkbytes);
+ void set_chunks_per_row(UINT32 rowchunks);
+ void set_reverse(bool reverse);
+ void set_ascii(bool reverse);
+ void set_physical(bool physical);
+
+protected:
+ // view overrides
+ virtual void view_notify(debug_view_notification type);
+ virtual void view_update();
+ virtual void view_char(int chval);
+
+private:
+ struct cursor_pos
+ {
+ cursor_pos(offs_t address = 0, UINT8 shift = 0) : m_address(address), m_shift(shift) { }
+ offs_t m_address;
+ UINT8 m_shift;
+ };
+
+ // internal helpers
+ void enumerate_sources();
+ void recompute();
+ bool needs_recompute();
+
+ // cursor position management
+ cursor_pos get_cursor_pos();
+ void set_cursor_pos(cursor_pos pos);
+ cursor_pos begin_update_and_get_cursor_pos() { begin_update(); return get_cursor_pos(); }
+ void end_update_and_set_cursor_pos(cursor_pos pos) { set_cursor_pos(pos); end_update(); }
+
+ // memory access
+ bool read(UINT8 size, offs_t offs, UINT64 &data);
+ void write(UINT8 size, offs_t offs, UINT64 data);
+
+ // internal state
+ debug_view_expression m_expression; // expression describing the start address
+ UINT32 m_chunks_per_row; // number of chunks displayed per line
+ UINT8 m_bytes_per_chunk; // bytes per chunk
+ bool m_reverse_view; // reverse-endian view?
+ bool m_ascii_view; // display ASCII characters?
+ bool m_no_translation; // don't run addresses through the cpu translation hook
+ offs_t m_maxaddr; // (derived) maximum address to display
+ UINT32 m_bytes_per_row; // (derived) number of bytes displayed per line
+ UINT32 m_byte_offset; // (derived) offset of starting visible byte
+ astring m_addrformat; // (derived) format string to use to print addresses
+
+ struct section
+ {
+ bool contains(int x) const { return x >= m_pos && x < m_pos + m_width; }
+ INT32 m_pos; /* starting position */
+ INT32 m_width; /* width of this section */
+ };
+ section m_section[3]; // (derived) 3 sections to manage
+
+ struct memory_view_pos
+ {
+ UINT8 m_spacing; /* spacing between each entry */
+ UINT8 m_shift[24]; /* shift for each character */
+ };
+ static const memory_view_pos s_memory_pos_table[9]; // table for rendering at different chunk sizes
+
+ // constants
+ static const int MEM_MAX_LINE_WIDTH = 1024;
+};
+
+
+#endif
diff --git a/src/emu/debug/dvstate.c b/src/emu/debug/dvstate.c
new file mode 100644
index 00000000000..332683b23bf
--- /dev/null
+++ b/src/emu/debug/dvstate.c
@@ -0,0 +1,370 @@
+/*********************************************************************
+
+ dvstate.c
+
+ State debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugvw.h"
+#include "dvstate.h"
+
+
+
+//**************************************************************************
+// DEBUG VIEW STATE SOURCE
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_state_source - constructor
+//-------------------------------------------------
+
+debug_view_state_source::debug_view_state_source(const char *name, device_t &device)
+ : debug_view_source(name, &device),
+ m_device(device),
+ m_stateintf(dynamic_cast<device_state_interface *>(&device)),
+ m_execintf(dynamic_cast<device_execute_interface *>(&device))
+{
+}
+
+
+
+//**************************************************************************
+// DEBUG VIEW STATE
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_state - constructor
+//-------------------------------------------------
+
+debug_view_state::debug_view_state(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view(machine, DVT_STATE, osdupdate, osdprivate),
+ m_divider(0),
+ m_last_update(0),
+ m_state_list(NULL)
+{
+ // fail if no available sources
+ enumerate_sources();
+ if (m_source_list.count() == 0)
+ throw std::bad_alloc();
+}
+
+
+//-------------------------------------------------
+// ~debug_view_state - destructor
+//-------------------------------------------------
+
+debug_view_state::~debug_view_state()
+{
+ reset();
+}
+
+
+//-------------------------------------------------
+// enumerate_sources - enumerate all possible
+// sources for a registers view
+//-------------------------------------------------
+
+void debug_view_state::enumerate_sources()
+{
+ // start with an empty list
+ m_source_list.reset();
+
+ // iterate over devices that have state interfaces
+ device_state_interface *state = NULL;
+ astring name;
+ for (bool gotone = m_machine.devicelist.first(state); gotone; gotone = state->next(state))
+ {
+ name.printf("%s '%s'", state->device().name(), state->device().tag());
+ m_source_list.append(*auto_alloc(&m_machine, debug_view_state_source(name, state->device())));
+ }
+
+ // reset the source to a known good entry
+ m_source = m_source_list.head();
+}
+
+
+//-------------------------------------------------
+// reset - delete all of our state items
+//-------------------------------------------------
+
+void debug_view_state::reset()
+{
+ // free all items in the state list
+ while (m_state_list != NULL)
+ {
+ state_item *oldhead = m_state_list;
+ m_state_list = oldhead->m_next;
+ auto_free(&m_machine, oldhead);
+ }
+}
+
+
+//-------------------------------------------------
+// recompute - recompute all info for the
+// registers view
+//-------------------------------------------------
+
+void debug_view_state::recompute()
+{
+ const debug_view_state_source &source = downcast<const debug_view_state_source &>(*m_source);
+
+ // start with a blank list
+ reset();
+
+ // add a cycles entry: cycles:99999999
+ state_item **tailptr = &m_state_list;
+ *tailptr = auto_alloc(&m_machine, state_item(REG_CYCLES, "cycles", 8));
+ tailptr = &(*tailptr)->m_next;
+
+ // add a beam entry: beamx:123
+ *tailptr = auto_alloc(&m_machine, state_item(REG_BEAMX, "beamx", 3));
+ tailptr = &(*tailptr)->m_next;
+
+ // add a beam entry: beamy:456
+ *tailptr = auto_alloc(&m_machine, state_item(REG_BEAMY, "beamy", 3));
+ tailptr = &(*tailptr)->m_next;
+
+ // add a beam entry: frame:123456
+ *tailptr = auto_alloc(&m_machine, state_item(REG_FRAME, "frame", 6));
+ tailptr = &(*tailptr)->m_next;
+
+ // add a flags entry: flags:xxxxxxxx
+ *tailptr = auto_alloc(&m_machine, state_item(STATE_GENFLAGS, "flags", source.m_stateintf->state_string_max_length(STATE_GENFLAGS)));
+ tailptr = &(*tailptr)->m_next;
+
+ // add a divider entry
+ *tailptr = auto_alloc(&m_machine, state_item(REG_DIVIDER, "", 0));
+ tailptr = &(*tailptr)->m_next;
+
+ // add all registers into it
+ for (const device_state_entry *entry = source.m_stateintf->state_first(); entry != NULL; entry = entry->next())
+ if (entry->visible())
+ {
+ *tailptr = auto_alloc(&m_machine, state_item(entry->index(), entry->symbol(), source.m_stateintf->state_string_max_length(entry->index())));
+ tailptr = &(*tailptr)->m_next;
+ }
+
+ // count the entries and determine the maximum tag and value sizes
+ int count = 0;
+ int maxtaglen = 0;
+ int maxvallen = 0;
+ for (state_item *item = m_state_list; item != NULL; item = item->m_next)
+ {
+ count++;
+ maxtaglen = MAX(maxtaglen, item->m_symbol.len());
+ maxvallen = MAX(maxvallen, item->m_vallen);
+ }
+
+ // set the current divider and total cols
+ m_divider = 1 + maxtaglen + 1;
+ m_total.x = 1 + maxtaglen + 2 + maxvallen + 1;
+ m_total.y = count;
+ m_topleft.x = 0;
+ m_topleft.y = 0;
+
+ // no longer need to recompute
+ m_recompute = false;
+}
+
+
+//-------------------------------------------------
+// view_notify - handle notification of updates
+// to cursor changes
+//-------------------------------------------------
+
+void debug_view_state::view_notify(debug_view_notification type)
+{
+ if (type == VIEW_NOTIFY_SOURCE_CHANGED)
+ m_recompute = true;
+}
+
+
+//-------------------------------------------------
+// view_update - update the contents of the
+// register view
+//-------------------------------------------------
+
+void debug_view_state::view_update()
+{
+ // if our assumptions changed, revisit them
+ if (m_recompute)
+ recompute();
+
+ // get cycle count if we have an execute interface
+ const debug_view_state_source &source = downcast<const debug_view_state_source &>(*m_source);
+ UINT64 total_cycles = 0;
+ if (source.m_execintf != NULL)
+ total_cycles = source.m_execintf->total_cycles();
+
+ // find the first entry
+ state_item *curitem = m_state_list;
+ for (int index = 0; curitem != NULL && index < m_topleft.y; index++)
+ curitem = curitem->m_next;
+
+ // loop over visible rows
+ screen_device *screen = m_machine.primary_screen;
+ debug_view_char *dest = m_viewdata;
+ for (UINT32 row = 0; row < m_visible.y; row++)
+ {
+ UINT32 col = 0;
+
+ // if this visible row is valid, add it to the buffer
+ if (curitem != NULL)
+ {
+ UINT32 effcol = m_topleft.x;
+ UINT8 attrib = DCA_NORMAL;
+ UINT32 len = 0;
+ astring valstr;
+
+ // get the effective string
+ if (curitem->m_index >= REG_FRAME && curitem->m_index <= REG_DIVIDER)
+ {
+ curitem->m_lastval = curitem->m_currval;
+ switch (curitem->m_index)
+ {
+ case REG_DIVIDER:
+ curitem->m_vallen = 0;
+ curitem->m_symbol.reset();
+ for (int i = 0; i < m_total.x; i++)
+ curitem->m_symbol.cat("-");
+ break;
+
+ case REG_CYCLES:
+ if (source.m_execintf != NULL)
+ {
+ curitem->m_currval = source.m_execintf->cycles_remaining();
+ valstr.printf("%-8d", (UINT32)curitem->m_currval);
+ }
+ break;
+
+ case REG_BEAMX:
+ if (screen != NULL)
+ {
+ curitem->m_currval = screen->hpos();
+ valstr.printf("%3d", (UINT32)curitem->m_currval);
+ }
+ break;
+
+ case REG_BEAMY:
+ if (screen != NULL)
+ {
+ curitem->m_currval = screen->vpos();
+ valstr.printf("%3d", (UINT32)curitem->m_currval);
+ }
+ break;
+
+ case REG_FRAME:
+ if (screen != NULL)
+ {
+ curitem->m_currval = screen->frame_number();
+ valstr.printf("%3d", (UINT32)curitem->m_currval);
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (m_last_update != total_cycles)
+ curitem->m_lastval = curitem->m_currval;
+ curitem->m_currval = source.m_stateintf->state_value(curitem->m_index);
+ source.m_stateintf->state_string(curitem->m_index, valstr);
+ }
+
+ // see if we changed
+ if (curitem->m_lastval != curitem->m_currval)
+ attrib = DCA_CHANGED;
+
+ // build up a string
+ char temp[256];
+ if (curitem->m_symbol.len() < m_divider - 1)
+ {
+ memset(&temp[len], ' ', m_divider - 1 - curitem->m_symbol.len());
+ len += m_divider - 1 - curitem->m_symbol.len();
+ }
+
+ memcpy(&temp[len], curitem->m_symbol.cstr(), curitem->m_symbol.len());
+ len += curitem->m_symbol.len();
+
+ temp[len++] = ' ';
+ temp[len++] = ' ';
+
+ memcpy(&temp[len], valstr.cstr(), curitem->m_vallen);
+ len += curitem->m_vallen;
+
+ temp[len++] = ' ';
+ temp[len] = 0;
+
+ // copy data
+ while (col < m_visible.x && effcol < len)
+ {
+ dest->byte = temp[effcol++];
+ dest->attrib = attrib | ((effcol <= m_divider) ? DCA_ANCILLARY : DCA_NORMAL);
+ dest++;
+ col++;
+ }
+
+ // advance to the next item
+ curitem = curitem->m_next;
+ }
+
+ // fill the rest with blanks
+ while (col < m_visible.x)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ // remember the last update
+ m_last_update = total_cycles;
+}
+
+
+//-------------------------------------------------
+// state_item - constructor
+//-------------------------------------------------
+
+debug_view_state::state_item::state_item(int index, const char *name, UINT8 valuechars)
+ : m_next(NULL),
+ m_lastval(0),
+ m_currval(0),
+ m_index(index),
+ m_vallen(valuechars),
+ m_symbol(name)
+{
+}
diff --git a/src/emu/debug/dvstate.h b/src/emu/debug/dvstate.h
new file mode 100644
index 00000000000..b30c973728c
--- /dev/null
+++ b/src/emu/debug/dvstate.h
@@ -0,0 +1,117 @@
+/*********************************************************************
+
+ dvstate.h
+
+ State debugger view.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef __DVSTATE_H__
+#define __DVSTATE_H__
+
+#include "debugvw.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// data sources for state views
+class debug_view_state_source : public debug_view_source
+{
+ friend class debug_view_state;
+
+ // construction/destruction
+ debug_view_state_source(const char *name, device_t &device);
+
+public:
+ // getters
+ device_t &device() const { return m_device; }
+
+private:
+ // internal state
+ device_t & m_device; // underlying device
+ device_state_interface *m_stateintf; // state interface
+ device_execute_interface *m_execintf; // execution interface
+};
+
+
+// debug view for state
+class debug_view_state : public debug_view
+{
+ friend resource_pool_object<debug_view_state>::~resource_pool_object();
+ friend class debug_view_manager;
+
+ // construction/destruction
+ debug_view_state(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+ virtual ~debug_view_state();
+
+protected:
+ // view overrides
+ virtual void view_update();
+ virtual void view_notify(debug_view_notification type);
+
+private:
+ struct state_item
+ {
+ state_item(int index, const char *name, UINT8 valuechars);
+
+ state_item * m_next; // next item
+ UINT64 m_lastval; // last value
+ UINT64 m_currval; // current value
+ int m_index; // index
+ UINT8 m_vallen; // number of value chars
+ astring m_symbol; // symbol
+ };
+
+ // internal helpers
+ void enumerate_sources();
+ void reset();
+ void recompute();
+
+ // internal state
+ int m_divider; // dividing column
+ UINT64 m_last_update; // execution counter at last update
+ state_item * m_state_list; // state data
+
+ // constants
+ static const int REG_DIVIDER = -10;
+ static const int REG_CYCLES = -11;
+ static const int REG_BEAMX = -12;
+ static const int REG_BEAMY = -13;
+ static const int REG_FRAME = -14;
+};
+
+
+#endif
diff --git a/src/emu/debug/dvtext.c b/src/emu/debug/dvtext.c
new file mode 100644
index 00000000000..8e42b182f86
--- /dev/null
+++ b/src/emu/debug/dvtext.c
@@ -0,0 +1,184 @@
+/*********************************************************************
+
+ dvtext.c
+
+ Debugger simple text-based views.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugvw.h"
+#include "dvtext.h"
+#include "debugcon.h"
+
+
+
+//**************************************************************************
+// DEBUG VIEW TEXTBUF
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_textbuf - constructor
+//-------------------------------------------------
+
+debug_view_textbuf::debug_view_textbuf(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate, text_buffer &textbuf)
+ : debug_view(machine, type, osdupdate, osdprivate),
+ m_textbuf(textbuf),
+ m_at_bottom(true),
+ m_topseq(0)
+{
+}
+
+
+//-------------------------------------------------
+// ~debug_view_textbuf - destructor
+//-------------------------------------------------
+
+debug_view_textbuf::~debug_view_textbuf()
+{
+}
+
+
+//-------------------------------------------------
+// view_update - update a text buffer-based view
+//-------------------------------------------------
+
+void debug_view_textbuf::view_update()
+{
+ // update the console info
+ m_total.x = text_buffer_max_width(&m_textbuf);
+ m_total.y = text_buffer_num_lines(&m_textbuf);
+ if (m_total.x < 80)
+ m_total.x = 80;
+
+ // determine the starting sequence number
+ UINT32 curseq = 0;
+ if (!m_at_bottom)
+ {
+ curseq = m_topseq;
+ if (!text_buffer_get_seqnum_line(&m_textbuf, curseq))
+ m_at_bottom = true;
+ }
+ if (m_at_bottom)
+ {
+ curseq = text_buffer_line_index_to_seqnum(&m_textbuf, m_total.y - 1);
+ if (m_total.y < m_visible.y)
+ curseq -= m_total.y - 1;
+ else
+ curseq -= m_visible.y - 1;
+ }
+ m_topleft.y = curseq - text_buffer_line_index_to_seqnum(&m_textbuf, 0);
+
+ // loop over visible rows
+ debug_view_char *dest = m_viewdata;
+ for (UINT32 row = 0; row < m_visible.y; row++)
+ {
+ const char *line = text_buffer_get_seqnum_line(&m_textbuf, curseq++);
+ UINT32 col = 0;
+
+ // if this visible row is valid, add it to the buffer
+ if (line != NULL)
+ {
+ size_t len = strlen(line);
+ UINT32 effcol = m_topleft.x;
+
+ // copy data
+ while (col < m_visible.x && effcol < len)
+ {
+ dest->byte = line[effcol++];
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ // fill the rest with blanks
+ while (col < m_visible.x)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// view_notify - handle notification of updates
+// to visible area
+//-------------------------------------------------
+
+void debug_view_textbuf::view_notify(debug_view_notification type)
+{
+ if (type == VIEW_NOTIFY_VISIBLE_CHANGED)
+ {
+ // if the bottom line is visible, just track the bottom
+ m_at_bottom = (m_total.y >= m_topleft.y && m_total.y <= m_topleft.y + m_visible.y);
+
+ /* otherwise, track the seqence number of the top line */
+ if (!m_at_bottom)
+ m_topseq = text_buffer_line_index_to_seqnum(&m_textbuf, m_topleft.y);
+ }
+}
+
+
+
+//**************************************************************************
+// DEBUG VIEW CONSOLE
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_console - constructor
+//-------------------------------------------------
+
+debug_view_console::debug_view_console(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view_textbuf(machine, DVT_CONSOLE, osdupdate, osdprivate, *debug_console_get_textbuf())
+{
+}
+
+
+
+//**************************************************************************
+// DEBUG VIEW LOG
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_view_log - constructor
+//-------------------------------------------------
+
+debug_view_log::debug_view_log(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view_textbuf(machine, DVT_LOG, osdupdate, osdprivate, *debug_errorlog_get_textbuf())
+{
+}
diff --git a/src/emu/debug/dvtext.h b/src/emu/debug/dvtext.h
new file mode 100644
index 00000000000..dcaa02eaa74
--- /dev/null
+++ b/src/emu/debug/dvtext.h
@@ -0,0 +1,90 @@
+/*********************************************************************
+
+ dvtext.h
+
+ Debugger simple text-based views.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#ifndef __DVTEXT_H__
+#define __DVTEXT_H__
+
+#include "debugvw.h"
+#include "textbuf.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// debug_view_textbuf contains data specific to a textbuffer view
+class debug_view_textbuf : public debug_view
+{
+ friend class debug_view_manager;
+
+protected:
+ // construction/destruction
+ debug_view_textbuf(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate, text_buffer &textbuf);
+ virtual ~debug_view_textbuf();
+
+protected:
+ // view overrides
+ virtual void view_update();
+ virtual void view_notify(debug_view_notification type);
+
+private:
+ // internal state
+ text_buffer & m_textbuf; /* pointer to the text buffer */
+ bool m_at_bottom; /* are we tracking new stuff being added? */
+ UINT32 m_topseq; /* sequence number of the top line */
+};
+
+
+// debug_view_console describes a console view
+class debug_view_console : public debug_view_textbuf
+{
+ friend class debug_view_manager;
+ debug_view_console(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+};
+
+
+// debug_view_textbuf describes an error log view
+class debug_view_log : public debug_view_textbuf
+{
+ friend class debug_view_manager;
+ debug_view_log(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+};
+
+
+#endif