summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugvw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug/debugvw.c')
-rw-r--r--src/emu/debug/debugvw.c3187
1 files changed, 3187 insertions, 0 deletions
diff --git a/src/emu/debug/debugvw.c b/src/emu/debug/debugvw.c
new file mode 100644
index 00000000000..2814591cba5
--- /dev/null
+++ b/src/emu/debug/debugvw.c
@@ -0,0 +1,3187 @@
+/*********************************************************************
+
+ debugvw.c
+
+ Debugger view engine.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "driver.h"
+#include "debugvw.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)
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* debug_view_callbacks contains calbacks specific to a given view */
+typedef struct _debug_view_callbacks debug_view_callbacks;
+struct _debug_view_callbacks
+{
+ int (*alloc)(debug_view *); /* allocate memory */
+ void (*free)(debug_view *); /* free memory */
+ void (*update)(debug_view *); /* update contents */
+ void (*getprop)(debug_view *, UINT32, debug_property_info *value); /* get property */
+ void (*setprop)(debug_view *, UINT32, debug_property_info value); /* set property */
+};
+
+
+/* debug_view describes a single text-based view */
+/* typedef struct _debug_view debug_view -- defined in debugvw.h */
+struct _debug_view
+{
+ debug_view * next; /* link to the next view */
+ UINT8 type; /* type of view */
+ void * extra_data; /* extra view-specific data */
+ debug_view_callbacks cb; /* callback for this view */
+ void * osd_private_data; /* OSD-managed private data */
+
+ /* visibility info */
+ UINT32 visible_rows; /* number of currently visible rows */
+ UINT32 visible_cols; /* number of currently visible columns */
+ UINT32 total_rows; /* total number of rows */
+ UINT32 total_cols; /* total number of columns */
+ UINT32 top_row; /* current top row */
+ UINT32 left_col; /* current left column */
+ UINT32 supports_cursor; /* does this view support a cursor? */
+ UINT32 cursor_visible; /* is the cursor visible? */
+ UINT32 cursor_row; /* cursor row */
+ UINT32 cursor_col; /* cursor column */
+
+ /* update info */
+ UINT8 update_level; /* update level; updates when this hits 0 */
+ UINT8 update_pending; /* true if there is a pending update */
+ void (*update_func)(debug_view *);/* callback for the 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 */
+ UINT32 regnum; /* index */
+ UINT8 tagstart; /* starting tag char */
+ UINT8 taglen; /* number of tag chars */
+ UINT8 valstart; /* starting value char */
+ UINT8 vallen; /* number of value chars */
+};
+
+
+typedef struct _debug_view_registers debug_view_registers;
+struct _debug_view_registers
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ int divider; /* dividing column */
+ UINT32 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
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ UINT8 right_column; /* right column? */
+ UINT32 backwards_steps; /* number of backwards steps */
+ UINT32 dasm_width; /* width of the disassembly area */
+ UINT8 * last_opcode_base; /* last opcode base */
+ UINT8 * last_opcode_arg_base; /* last opcode arg base */
+ UINT32 last_change_count; /* last comment change count */
+ offs_t last_pcbyte; /* last PC byte value */
+ UINT32 active_address; /* the address cursor_row is pointing to */
+ int divider1, divider2; /* left and right divider columns */
+ int divider3; /* comment divider column */
+ UINT8 live_tracking; /* track the value of the live expression? */
+ UINT64 last_result; /* last result from the expression */
+ parsed_expression *expression; /* expression to compute */
+ char * expression_string; /* copy of the expression string */
+ UINT8 expression_dirty; /* true if the expression needs to be re-evaluated */
+ UINT32 allocated_rows; /* allocated rows */
+ UINT32 allocated_cols; /* allocated columns */
+ offs_t * address; /* 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
+{
+ UINT8 recompute; /* do we need to recompute the layout the next change? */
+ UINT8 cpunum; /* target CPU number */
+ int divider1, divider2; /* left and right divider columns */
+ UINT8 spacenum; /* target address space */
+ UINT8 bytes_per_chunk; /* bytes per unit */
+ UINT16 chunks_displayed; /* number of chunks displayed per line */
+ UINT8 reverse_view; /* reverse-endian view? */
+ UINT8 ascii_view; /* display ASCII characters? */
+ UINT8 live_tracking; /* track the value of the live expression? */
+ UINT8 byte_offset; /* byte offset within each row */
+ UINT8 no_translation; /* don't run addresses through the cpu translation hook */
+ UINT64 last_result; /* last result from the expression */
+ parsed_expression *expression; /* expression to compute */
+ char * expression_string; /* copy of the expression string */
+ UINT8 expression_dirty; /* true if the expression needs to be re-evaluated */
+ void * raw_base; /* base of raw memory view (overrides CPU/space) */
+ UINT32 raw_length; /* length of raw memory view */
+ UINT8 raw_offset_xor; /* xor to apply to offsets */
+ UINT8 raw_little_endian; /* little endian data? */
+};
+
+
+/* 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 */
+};
+
+
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static debug_view *first_view;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int console_alloc(debug_view *view);
+
+static int log_alloc(debug_view *view);
+
+static int registers_alloc(debug_view *view);
+static void registers_free(debug_view *view);
+static void registers_update(debug_view *view);
+static void registers_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void registers_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int disasm_alloc(debug_view *view);
+static void disasm_free(debug_view *view);
+static void disasm_update(debug_view *view);
+static void disasm_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void disasm_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int memory_alloc(debug_view *view);
+static void memory_free(debug_view *view);
+static void memory_update(debug_view *view);
+static void memory_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void memory_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static int textbuf_alloc(debug_view *view, text_buffer *textbuf);
+static void textbuf_free(debug_view *view);
+static void textbuf_update(debug_view *view);
+static void textbuf_getprop(debug_view *view, UINT32 property, debug_property_info *value);
+static void textbuf_setprop(debug_view *view, UINT32 property, debug_property_info value);
+
+static const debug_view_callbacks callback_table[] =
+{
+ { NULL, NULL, NULL, NULL, NULL },
+ { console_alloc, textbuf_free, textbuf_update, textbuf_getprop, textbuf_setprop },
+ { registers_alloc, registers_free, registers_update, registers_getprop, registers_setprop },
+ { disasm_alloc, disasm_free, disasm_update, disasm_getprop, disasm_setprop },
+ { memory_alloc, memory_free, memory_update, memory_getprop, memory_setprop },
+ { log_alloc, textbuf_free, textbuf_update, textbuf_getprop, textbuf_setprop }
+};
+
+
+
+/***************************************************************************
+
+ Initialization and shutdown
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_init - initializes the view system
+-------------------------------------------------*/
+
+void debug_view_init(running_machine *machine)
+{
+ /* reset the initial list */
+ first_view = NULL;
+ add_exit_callback(machine, debug_view_exit);
+}
+
+
+/*-------------------------------------------------
+ debug_view_exit - exits the view system
+-------------------------------------------------*/
+
+void debug_view_exit(running_machine *machine)
+{
+ /* kill all the views */
+ while (first_view != NULL)
+ debug_view_free(first_view);
+}
+
+
+
+/***************************************************************************
+
+ View creation/deletion
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_alloc - allocate a new debug
+ view
+-------------------------------------------------*/
+
+debug_view *debug_view_alloc(int type)
+{
+ debug_view *view;
+
+ /* allocate memory for the view */
+ view = malloc(sizeof(*view));
+ if (!view)
+ return NULL;
+ memset(view, 0, sizeof(*view));
+
+ /* set the view type information */
+ view->type = type;
+ view->cb = callback_table[type];
+
+ /* set up some reasonable defaults */
+ view->visible_rows = 10;
+ view->visible_cols = 10;
+ view->total_rows = 10;
+ view->total_cols = 10;
+
+ /* allocate memory for the buffer */
+ view->viewdata_size = view->visible_rows*view->visible_cols;
+ view->viewdata = malloc(sizeof(view->viewdata[0]) * view->viewdata_size);
+ if (!view->viewdata)
+ {
+ free(view);
+ return NULL;
+ }
+
+ /* allocate extra memory */
+ if (view->cb.alloc && !(*view->cb.alloc)(view))
+ {
+ free(view->viewdata);
+ free(view);
+ return NULL;
+ }
+
+ /* link it in */
+ view->next = first_view;
+ first_view = view;
+
+ return view;
+}
+
+
+/*-------------------------------------------------
+ debug_view_free - free a debug view
+-------------------------------------------------*/
+
+void debug_view_free(debug_view *view)
+{
+ debug_view *curview, *prevview;
+
+ /* find the view */
+ for (prevview = NULL, curview = first_view; curview != NULL; prevview = curview, curview = curview->next)
+ if (curview == view)
+ {
+ /* unlink */
+ if (prevview != NULL)
+ prevview->next = curview->next;
+ else
+ first_view = curview->next;
+
+ /* free memory */
+ if (view->cb.free)
+ (*view->cb.free)(view);
+ if (view->viewdata)
+ free(view->viewdata);
+ free(view);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Property management
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_view_get_property - return the value
+ of a given property
+-------------------------------------------------*/
+
+void debug_view_get_property(debug_view *view, int property, debug_property_info *value)
+{
+ switch (property)
+ {
+ case DVP_VISIBLE_ROWS:
+ value->i = view->visible_rows;
+ break;
+
+ case DVP_VISIBLE_COLS:
+ value->i = view->visible_cols;
+ break;
+
+ case DVP_TOTAL_ROWS:
+ value->i = view->total_rows;
+ break;
+
+ case DVP_TOTAL_COLS:
+ value->i = view->total_cols;
+ break;
+
+ case DVP_TOP_ROW:
+ value->i = view->top_row;
+ break;
+
+ case DVP_LEFT_COL:
+ value->i = view->left_col;
+ break;
+
+ case DVP_UPDATE_CALLBACK:
+ value->f = (genf *) view->update_func;
+ break;
+
+ case DVP_VIEW_DATA:
+ value->p = (void *) view->viewdata;
+ break;
+
+ case DVP_SUPPORTS_CURSOR:
+ value->i = view->supports_cursor;
+ break;
+
+ case DVP_CURSOR_VISIBLE:
+ value->i = view->cursor_visible;
+ break;
+
+ case DVP_CURSOR_ROW:
+ value->i = view->cursor_row;
+ break;
+
+ case DVP_CURSOR_COL:
+ value->i = view->cursor_col;
+ break;
+
+ case DVP_OSD_PRIVATE:
+ value->p = view->osd_private_data;
+ break;
+
+ default:
+ if (view->cb.getprop)
+ (*view->cb.getprop)(view, property, value);
+ else
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_view_set_property - set the value
+ of a given property
+-------------------------------------------------*/
+
+void debug_view_set_property(debug_view *view, int property, debug_property_info value)
+{
+ switch (property)
+ {
+ case DVP_VISIBLE_ROWS:
+ if (value.i != view->visible_rows)
+ {
+ debug_view_begin_update(view);
+ view->visible_rows = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_VISIBLE_COLS:
+ if (value.i != view->visible_cols)
+ {
+ debug_view_begin_update(view);
+ view->visible_cols = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOTAL_ROWS:
+ if (value.i != view->total_rows)
+ {
+ debug_view_begin_update(view);
+ view->total_rows = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOTAL_COLS:
+ if (value.i != view->total_cols)
+ {
+ debug_view_begin_update(view);
+ view->total_cols = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_TOP_ROW:
+ if (value.i != view->top_row)
+ {
+ debug_view_begin_update(view);
+ view->top_row = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_LEFT_COL:
+ if (value.i != view->left_col)
+ {
+ debug_view_begin_update(view);
+ view->left_col = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_UPDATE_CALLBACK:
+ debug_view_begin_update(view);
+ view->update_func = (void (*)(debug_view *)) value.f;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_VIEW_DATA:
+ /* read-only */
+ break;
+
+ case DVP_SUPPORTS_CURSOR:
+ /* read-only */
+ break;
+
+ case DVP_CURSOR_VISIBLE:
+ if (value.i != view->cursor_visible)
+ {
+ debug_view_begin_update(view);
+ view->cursor_visible = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CURSOR_ROW:
+ if (value.i != view->cursor_row)
+ {
+ debug_view_begin_update(view);
+ view->cursor_row = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ if (view->type == DVT_DISASSEMBLY)
+ {
+ debug_view_disasm *dasmdata = view->extra_data;
+ dasmdata->active_address = dasmdata->address[view->cursor_row];
+ }
+ break;
+
+ case DVP_CURSOR_COL:
+ if (value.i != view->cursor_col)
+ {
+ debug_view_begin_update(view);
+ view->cursor_col = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_OSD_PRIVATE:
+ view->osd_private_data = value.p;
+ break;
+
+ default:
+ if (view->cb.setprop)
+ (*view->cb.setprop)(view, property, value);
+ else
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ 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 */
+ view->update_pending = 0;
+
+ /* resize the viewdata if needed */
+ size = view->visible_rows*view->visible_cols;
+ if (size > view->viewdata_size)
+ {
+ view->viewdata_size = size;
+ view->viewdata = realloc(view->viewdata, sizeof(view->viewdata[0]) * view->viewdata_size);
+ }
+
+ /* update the view */
+ if (view->cb.update)
+ (*view->cb.update)(view);
+
+ /* update the owner */
+ if (view->update_func)
+ (*view->update_func)(view);
+ }
+ }
+
+ /* decrement the level */
+ view->update_level--;
+}
+
+
+/*-------------------------------------------------
+ debug_view_update_all - force all views to
+ refresh
+-------------------------------------------------*/
+
+void debug_view_update_all(void)
+{
+ debug_view *view;
+
+ /* loop over each view and force an update */
+ for (view = first_view; 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(int type)
+{
+ debug_view *view;
+
+ /* loop over each view and force an update */
+ for (view = first_view; view != NULL; view = view->next)
+ if (view->type == type)
+ {
+ debug_view_begin_update(view);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Console view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ console_alloc - allocate memory for the log view
+-------------------------------------------------*/
+
+static int console_alloc(debug_view *view)
+{
+ return textbuf_alloc(view, debug_console_get_textbuf());
+}
+
+
+
+/***************************************************************************
+
+ Log view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ log_alloc - allocate memory for the log view
+-------------------------------------------------*/
+
+static int log_alloc(debug_view *view)
+{
+ return textbuf_alloc(view, debug_errorlog_get_textbuf());
+}
+
+
+
+/***************************************************************************
+
+ Generic text buffer view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ textbuf_alloc - allocate memory for a text
+ buffer view
+-------------------------------------------------*/
+
+static int textbuf_alloc(debug_view *view, text_buffer *textbuf)
+{
+ debug_view_textbuf *textdata;
+
+ /* allocate memory */
+ textdata = malloc(sizeof(*textdata));
+ if (!textdata)
+ return 0;
+ memset(textdata, 0, sizeof(*textdata));
+
+ /* by default we track live */
+ textdata->textbuf = textbuf;
+ textdata->at_bottom = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = textdata;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ textbuf_free - free memory for the log view
+-------------------------------------------------*/
+
+static void textbuf_free(debug_view *view)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (textdata)
+ free(textdata);
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ textbuf_update - update the log view
+-------------------------------------------------*/
+
+static void textbuf_update(debug_view *view)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+ debug_view_char *dest = view->viewdata;
+ UINT32 curseq = 0, row;
+
+ /* update the console info */
+ view->total_rows = text_buffer_num_lines(textdata->textbuf);
+ view->total_cols = text_buffer_max_width(textdata->textbuf);
+ if (view->total_cols < 80)
+ view->total_cols = 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_rows - 1);
+ if (view->total_rows < view->visible_rows)
+ curseq -= view->total_rows - 1;
+ else
+ curseq -= view->visible_rows - 1;
+ }
+ view->top_row = curseq - text_buffer_line_index_to_seqnum(textdata->textbuf, 0);
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ 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->left_col;
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = line[effcol++];
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ textbuf_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void textbuf_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_TEXTBUF_LINE_LOCK:
+ value->i = textdata->at_bottom ? (UINT32)-1 : textdata->topseq - text_buffer_line_index_to_seqnum(textdata->textbuf, 0);
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ textbuf_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void textbuf_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_textbuf *textdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_TEXTBUF_LINE_LOCK:
+ if (value.i == (UINT32)-1)
+ {
+ if (!textdata->at_bottom)
+ {
+ debug_view_begin_update(view);
+ textdata->at_bottom = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ }
+ else
+ {
+ UINT32 seq = text_buffer_line_index_to_seqnum(textdata->textbuf, value.i);
+ if (seq != textdata->topseq || textdata->at_bottom)
+ {
+ debug_view_begin_update(view);
+ textdata->topseq = seq;
+ textdata->at_bottom = FALSE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ }
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Registers view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ registers_alloc - allocate memory for the
+ registers view
+-------------------------------------------------*/
+
+static int registers_alloc(debug_view *view)
+{
+ debug_view_registers *regdata;
+
+ /* allocate memory */
+ regdata = malloc(sizeof(*regdata));
+ if (!regdata)
+ return 0;
+ memset(regdata, 0, sizeof(*regdata));
+
+ /* initialize */
+ regdata->recompute = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = regdata;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ registers_free - free memory for the
+ registers view
+-------------------------------------------------*/
+
+static void registers_free(debug_view *view)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (regdata)
+ free(regdata);
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ add_register - adds a register to the
+ registers view
+-------------------------------------------------*/
+
+static void add_register(debug_view *view, int regnum, const char *str)
+{
+ debug_view_registers *regdata = view->extra_data;
+ int tagstart, taglen, valstart, vallen;
+ const char *colon;
+
+ colon = strchr(str, ':');
+
+ /* if no colon, mark everything as tag */
+ if (!colon)
+ {
+ tagstart = 0;
+ taglen = (int)strlen(str);
+ valstart = 0;
+ vallen = 0;
+ }
+
+ /* otherwise, break the string at the colon */
+ else
+ {
+ tagstart = 0;
+ taglen = colon - str;
+ valstart = (colon + 1) - str;
+ vallen = (int)strlen(colon + 1);
+ }
+
+ /* now trim spaces */
+ while (isspace(str[tagstart]) && taglen > 0)
+ tagstart++, taglen--;
+ while (isspace(str[tagstart + taglen - 1]) && taglen > 0)
+ taglen--;
+ while (isspace(str[valstart]) && vallen > 0)
+ valstart++, vallen--;
+ while (isspace(str[valstart + vallen - 1]) && vallen > 0)
+ vallen--;
+ if (str[valstart] == '!')
+ valstart++, vallen--;
+
+ /* note the register number and info */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = cpunum_get_reg(regdata->cpunum, regnum);
+ regdata->reg[view->total_rows].regnum = regnum;
+ regdata->reg[view->total_rows].tagstart = tagstart;
+ regdata->reg[view->total_rows].taglen = taglen;
+ regdata->reg[view->total_rows].valstart = valstart;
+ regdata->reg[view->total_rows].vallen = vallen;
+ view->total_rows++;
+
+ /* adjust the divider and total cols, if necessary */
+ regdata->divider = MAX(regdata->divider, 1 + taglen + 1);
+ view->total_cols = MAX(view->total_cols, 1 + taglen + 2 + vallen + 1);
+}
+
+
+/*-------------------------------------------------
+ registers_recompute - recompute all info
+ for the registers view
+-------------------------------------------------*/
+
+static void registers_recompute(debug_view *view)
+{
+ debug_view_registers *regdata = view->extra_data;
+ const int *list = cpunum_debug_register_list(regdata->cpunum);
+ int regnum, maxtaglen, maxvallen;
+
+ /* reset the view parameters */
+ view->top_row = 0;
+ view->left_col = 0;
+ view->total_rows = 0;
+ view->total_cols = 0;
+ regdata->divider = 0;
+
+ /* add a cycles entry: cycles:99999999 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 1;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 6;
+ regdata->reg[view->total_rows].valstart = 7;
+ regdata->reg[view->total_rows].vallen = 8;
+ maxtaglen = regdata->reg[view->total_rows].taglen;
+ maxvallen = regdata->reg[view->total_rows].vallen;
+ view->total_rows++;
+
+ /* add a beam entry: beamx:123 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 2;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = 3;
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a beam entry: beamy:456 */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 3;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = 3;
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a flags entry: flags:xxxxxxxx */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS + 4;
+ regdata->reg[view->total_rows].tagstart = 0;
+ regdata->reg[view->total_rows].taglen = 5;
+ regdata->reg[view->total_rows].valstart = 6;
+ regdata->reg[view->total_rows].vallen = (UINT32)strlen(cpunum_flags(regdata->cpunum));
+ maxtaglen = MAX(maxtaglen, regdata->reg[view->total_rows].taglen);
+ maxvallen = MAX(maxvallen, regdata->reg[view->total_rows].vallen);
+ view->total_rows++;
+
+ /* add a divider entry */
+ regdata->reg[view->total_rows].lastval =
+ regdata->reg[view->total_rows].currval = 0;
+ regdata->reg[view->total_rows].regnum = MAX_REGS;
+ view->total_rows++;
+
+ /* set the current divider and total cols */
+ regdata->divider = 1 + maxtaglen + 1;
+ view->total_cols = 1 + maxtaglen + 2 + maxvallen + 1;
+
+ /* add all registers into it */
+ for (regnum = 0; regnum < MAX_REGS; regnum++)
+ {
+ const char *str = NULL;
+ int regid;
+
+ /* identify the register id */
+ regid = list ? list[regnum] : regnum;
+ if (regid < 0)
+ break;
+
+ /* retrieve the string for this register */
+ str = cpunum_reg_string(regdata->cpunum, regid);
+
+ /* did we get a string? */
+ if (str && str[0] != '\0' && str[0] != '~')
+ add_register(view, regid, str);
+ }
+
+ /* no longer need to recompute */
+ regdata->recompute = FALSE;
+}
+
+
+/*-------------------------------------------------
+ registers_update - update the contents of
+ the register view
+-------------------------------------------------*/
+
+static void registers_update(debug_view *view)
+{
+ UINT32 execution_counter = debug_get_execution_counter();
+ debug_view_registers *regdata = view->extra_data;
+ debug_view_char *dest = view->viewdata;
+ UINT32 row, i;
+ int scrnum = 0;
+
+ /* cannot update if no active CPU */
+ if (cpu_getactivecpu() < 0)
+ return;
+
+ /* if our assumptions changed, revisit them */
+ if (regdata->recompute)
+ registers_recompute(view);
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (effrow < view->total_rows)
+ {
+ debug_view_register *reg = &regdata->reg[effrow];
+ UINT32 effcol = view->left_col;
+ char temp[256], dummy[100];
+ UINT8 attrib = DCA_NORMAL;
+ UINT32 len = 0;
+ char *data = dummy;
+
+ /* get the effective string */
+ dummy[0] = 0;
+ if (reg->regnum >= MAX_REGS)
+ {
+ reg->lastval = reg->currval;
+ switch (reg->regnum)
+ {
+ case MAX_REGS:
+ reg->tagstart = reg->valstart = reg->vallen = 0;
+ reg->taglen = view->total_cols;
+ for (i = 0; i < view->total_cols; i++)
+ dummy[i] = '-';
+ dummy[i] = 0;
+ break;
+
+ case MAX_REGS + 1:
+ sprintf(dummy, "cycles:%-8d", activecpu_get_icount());
+ reg->currval = activecpu_get_icount();
+ break;
+
+ case MAX_REGS + 2:
+ if (video_screen_exists(scrnum))
+ sprintf(dummy, "beamx:%3d", video_screen_get_hpos(scrnum));
+ break;
+
+ case MAX_REGS + 3:
+ if (video_screen_exists(scrnum))
+ sprintf(dummy, "beamy:%3d", video_screen_get_vpos(scrnum));
+ break;
+
+ case MAX_REGS + 4:
+ sprintf(dummy, "flags:%s", activecpu_flags());
+ break;
+ }
+ }
+ else
+ {
+ data = (char *)cpunum_reg_string(regdata->cpunum, reg->regnum);
+ if (regdata->last_update != execution_counter)
+ reg->lastval = reg->currval;
+ reg->currval = cpunum_get_reg(regdata->cpunum, reg->regnum);
+ }
+
+ /* see if we changed */
+ if (reg->lastval != reg->currval)
+ attrib = DCA_CHANGED;
+
+ /* build up a string */
+ if (reg->taglen < regdata->divider - 1)
+ {
+ memset(&temp[len], ' ', regdata->divider - 1 - reg->taglen);
+ len += regdata->divider - 1 - reg->taglen;
+ }
+
+ memcpy(&temp[len], &data[reg->tagstart], reg->taglen);
+ len += reg->taglen;
+
+ temp[len++] = ' ';
+ temp[len++] = ' ';
+
+ memcpy(&temp[len], &data[reg->valstart], reg->vallen);
+ len += reg->vallen;
+
+ temp[len++] = ' ';
+ temp[len] = 0;
+
+ /* copy data */
+ while (col < view->visible_cols && 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_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ dest++;
+ col++;
+ }
+ }
+
+ /* remember the last update */
+ regdata->last_update = execution_counter;
+}
+
+
+/*-------------------------------------------------
+ registers_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void registers_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_REGS_CPUNUM:
+ value->i = regdata->cpunum;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ registers_getprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void registers_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_registers *regdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_REGS_CPUNUM:
+ if (value.i != regdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ regdata->cpunum = value.i;
+ regdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+
+ Disassembly view
+
+***************************************************************************/
+
+/*-------------------------------------------------
+ disasm_alloc - allocate disasm for the
+ disassembly view
+-------------------------------------------------*/
+
+static int disasm_alloc(debug_view *view)
+{
+ debug_view_disasm *dasmdata;
+ int total_comments = 0;
+ int i;
+
+ /* allocate disasm */
+ dasmdata = malloc(sizeof(*dasmdata));
+ if (!dasmdata)
+ return 0;
+ memset(dasmdata, 0, sizeof(*dasmdata));
+
+ /* count the number of comments */
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ total_comments += debug_comment_get_count(i);
+
+ /* initialize */
+ dasmdata->recompute = TRUE;
+ dasmdata->right_column = (total_comments > 0) ? DVP_DASM_RIGHTCOL_COMMENTS : DVP_DASM_RIGHTCOL_RAW;
+ dasmdata->backwards_steps = 3;
+ dasmdata->dasm_width = DEFAULT_DASM_WIDTH;
+ dasmdata->active_address = 0;
+
+ /* stash the extra data pointer */
+ view->total_rows = DEFAULT_DASM_LINES;
+ view->extra_data = dasmdata;
+
+ /* we support cursors */
+ view->supports_cursor = TRUE;
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ disasm_free - free disasm for the
+ disassembly view
+-------------------------------------------------*/
+
+static void disasm_free(debug_view *view)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ /* free any disasm we callocated */
+ if (dasmdata)
+ {
+ if (dasmdata->expression)
+ expression_free(dasmdata->expression);
+ if (dasmdata->expression_string)
+ free(dasmdata->expression_string);
+ if (dasmdata->address)
+ free(dasmdata->address);
+ if (dasmdata->dasm)
+ free(dasmdata->dasm);
+ free(dasmdata);
+ }
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ disasm_back_up - back up the specified number
+ of instructions from the given PC
+-------------------------------------------------*/
+
+static offs_t disasm_back_up(int cpunum, const debug_cpu_info *cpuinfo, offs_t startpc, int numinstrs)
+{
+ int minlen = BYTE2ADDR(activecpu_min_instruction_bytes(), cpuinfo, ADDRESS_SPACE_PROGRAM);
+ int maxlen = BYTE2ADDR(activecpu_max_instruction_bytes(), cpuinfo, ADDRESS_SPACE_PROGRAM);
+ UINT32 addrmask = cpuinfo->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+ offs_t curpc, lastgoodpc = startpc, temppc;
+ 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 = startpc - minlen * numinstrs;
+ if (curpc > startpc)
+ curpc = 0;
+
+ /* prefetch the opcode bytes */
+ for (temppc = curpc; temppc < startpc; temppc++)
+ {
+ opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE);
+ argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE);
+ }
+
+ /* loop until we hit it */
+ while (1)
+ {
+ offs_t testpc, nextcurpc, instlen, instcount = 0;
+
+ /* loop until we get past the target instruction */
+ for (testpc = curpc; testpc < startpc; testpc += instlen)
+ {
+ /* convert PC to a byte offset */
+ offs_t pcbyte = ADDR2BYTE_MASKED(testpc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* get the disassembly, but only if mapped */
+ instlen = 1;
+ if (!cpuinfo->translate || (*cpuinfo->translate)(ADDRESS_SPACE_PROGRAM, &pcbyte))
+ instlen = activecpu_dasm(dasmbuffer, testpc & addrmask, &opbuf[1000 + testpc - startpc], &argbuf[1000 + testpc - startpc]) & DASMFLAG_LENGTHMASK;
+
+ /* count this one */
+ instcount++;
+ }
+
+ /* if we ended up right on startpc, this is a good candidate */
+ if (testpc == startpc && instcount <= numinstrs)
+ lastgoodpc = curpc;
+
+ /* we're also done if we go back too far */
+ if (startpc - curpc >= numinstrs * maxlen)
+ break;
+
+ /* and if we hit 0, we're done */
+ if (curpc == 0)
+ break;
+
+ /* back up one more and try again */
+ nextcurpc = curpc - minlen;
+ if (nextcurpc > startpc)
+ nextcurpc = 0;
+
+ /* prefetch the opcode bytes */
+ for (temppc = nextcurpc; temppc < curpc; temppc++)
+ {
+ opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE);
+ argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE);
+ }
+
+ /* update curpc once we're done fetching */
+ curpc = nextcurpc;
+ }
+
+ return lastgoodpc;
+}
+
+
+/*-------------------------------------------------
+ disasm_generate_bytes - generate the opcode
+ byte values
+-------------------------------------------------*/
+
+static void disasm_generate_bytes(offs_t pcbyte, int numbytes, const debug_cpu_info *cpuinfo, int minbytes, char *string, int maxchars, int encrypted)
+{
+ int byte, offset = 0;
+ UINT64 val;
+
+ switch (minbytes)
+ {
+ case 1:
+ if (maxchars >= 2)
+ offset = sprintf(string, "%02X", (UINT32)debug_read_opcode(pcbyte, 1, FALSE));
+ for (byte = 1; byte < numbytes && offset + 3 < maxchars; byte++)
+ offset += sprintf(&string[offset], " %02X", (UINT32)debug_read_opcode(pcbyte + byte, 1, encrypted));
+ break;
+
+ case 2:
+ if (maxchars >= 4)
+ offset = sprintf(string, "%04X", (UINT32)debug_read_opcode(pcbyte, 2, FALSE));
+ for (byte = 2; byte < numbytes && offset + 5 < maxchars; byte += 2)
+ offset += sprintf(&string[offset], " %04X", (UINT32)debug_read_opcode(pcbyte + byte, 2, encrypted));
+ break;
+
+ case 4:
+ if (maxchars >= 8)
+ offset = sprintf(string, "%08X", (UINT32)debug_read_opcode(pcbyte, 4, FALSE));
+ for (byte = 4; byte < numbytes && offset + 9 < maxchars; byte += 4)
+ offset += sprintf(&string[offset], " %08X", (UINT32)debug_read_opcode(pcbyte + byte, 4, encrypted));
+ break;
+
+ case 8:
+ val = debug_read_opcode(pcbyte, 8, FALSE);
+ if (maxchars >= 16)
+ offset = sprintf(string, "%08X%08X", (UINT32)(val >> 32), (UINT32)val);
+ for (byte = 8; byte < numbytes && offset + 17 < maxchars; byte += 8)
+ {
+ val = debug_read_opcode(pcbyte + byte, 8, encrypted);
+ offset += sprintf(&string[offset], " %08X%08X", (UINT32)(val >> 32), (UINT32)val);
+ }
+ break;
+
+ default:
+ fatalerror("disasm_generate_bytes: unknown size = %d", minbytes);
+ break;
+ }
+
+ /* 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_recompute - recompute selected info
+ for the disassembly view
+-------------------------------------------------*/
+
+static int disasm_recompute(debug_view *view, offs_t pc, int startline, int lines, int original_cpunum)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ int chunksize, minbytes, maxbytes, maxbytes_clamped;
+ int changed = FALSE;
+ UINT32 addrmask;
+ int line;
+
+ /* switch to the context of the CPU in question */
+ addrmask = cpuinfo->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+
+ /* determine how many characters we need for an address and set the divider */
+ dasmdata->divider1 = 1 + cpuinfo->space[ADDRESS_SPACE_PROGRAM].logchars + 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 */
+ minbytes = activecpu_min_instruction_bytes();
+ maxbytes = activecpu_max_instruction_bytes();
+
+ /* set the width of the third column according to display mode */
+ if (dasmdata->right_column == DVP_DASM_RIGHTCOL_RAW || dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED)
+ {
+ chunksize = activecpu_databus_width(ADDRESS_SPACE_PROGRAM) / 8;
+ maxbytes_clamped = maxbytes;
+ if (maxbytes_clamped > DASM_MAX_BYTES)
+ maxbytes_clamped = DASM_MAX_BYTES;
+ view->total_cols = dasmdata->divider2 + 1 + 2 * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1;
+ }
+ else if (dasmdata->right_column == DVP_DASM_RIGHTCOL_COMMENTS)
+ view->total_cols = dasmdata->divider2 + 1 + 50; /* DEBUG_COMMENT_MAX_LINE_LENGTH */
+ else
+ view->total_cols = dasmdata->divider2 + 1;
+
+ /* reallocate memory if we don't have enough */
+ if (dasmdata->allocated_rows < view->total_rows || dasmdata->allocated_cols < view->total_cols)
+ {
+ /* update our values */
+ dasmdata->allocated_rows = view->total_rows;
+ dasmdata->allocated_cols = view->total_cols;
+
+ /* allocate address array */
+ if (dasmdata->address)
+ free(dasmdata->address);
+ dasmdata->address = malloc_or_die(sizeof(dasmdata->address[0]) * dasmdata->allocated_rows);
+
+ /* allocate disassembly buffer */
+ if (dasmdata->dasm)
+ free(dasmdata->dasm);
+ dasmdata->dasm = malloc_or_die(sizeof(dasmdata->dasm[0]) * dasmdata->allocated_rows * dasmdata->allocated_cols);
+ }
+
+ /* iterate over lines */
+ for (line = 0; line < lines; line++)
+ {
+ offs_t pcbyte, tempaddr;
+ char buffer[100];
+ int numbytes = 0;
+ int instr = startline + line;
+ char oldbuf[100];
+ char *destbuf = &dasmdata->dasm[instr * dasmdata->allocated_cols];
+
+ /* convert PC to a byte offset */
+ pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* 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_cols));
+
+ /* convert back and set the address of this instruction */
+ dasmdata->address[instr] = pcbyte; // ! This might make more sense as the following : BYTE2ADDR(pcbyte, cpuinfo, ADDRESS_SPACE_PROGRAM); !
+ sprintf(&destbuf[0], " %0*X ", cpuinfo->space[ADDRESS_SPACE_PROGRAM].logchars, BYTE2ADDR(pcbyte, cpuinfo, ADDRESS_SPACE_PROGRAM));
+
+ /* make sure we can translate the address */
+ tempaddr = pcbyte;
+ if (!cpuinfo->translate || (*cpuinfo->translate)(ADDRESS_SPACE_PROGRAM, &tempaddr))
+ {
+ UINT8 opbuf[64], argbuf[64];
+
+ /* fetch the bytes up to the maximum */
+ for (numbytes = 0; numbytes < maxbytes; numbytes++)
+ {
+ opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE);
+ argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE);
+ }
+
+ /* disassemble the result */
+ pc += numbytes = activecpu_dasm(buffer, pc & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ }
+ else
+ sprintf(buffer, "<unmapped>");
+
+ sprintf(&destbuf[dasmdata->divider1 + 1], "%-*s ", dasmdata->dasm_width, buffer);
+
+ if (dasmdata->right_column == DVP_DASM_RIGHTCOL_RAW || dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED)
+ {
+ /* get the bytes */
+ numbytes = ADDR2BYTE(numbytes, cpuinfo, ADDRESS_SPACE_PROGRAM);
+ disasm_generate_bytes(pcbyte, numbytes, cpuinfo, minbytes, &destbuf[dasmdata->divider2], dasmdata->allocated_cols - dasmdata->divider2, dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED);
+ }
+ else if (dasmdata->right_column == DVP_DASM_RIGHTCOL_COMMENTS)
+ {
+ offs_t comment_address = BYTE2ADDR(dasmdata->address[instr], cpuinfo, ADDRESS_SPACE_PROGRAM) ;
+
+ /* get and add the comment */
+ if (debug_comment_get_text(cpu_getactivecpu(), comment_address, debug_comment_get_opcode_crc32(comment_address)) != 0x00)
+ {
+ int i ;
+ char bob[DEBUG_COMMENT_MAX_LINE_LENGTH] ;
+ char pre[8] ;
+
+ // Stick in the 'comment' symbol
+ sprintf(pre, "// ") ;
+ for (i = 0; i < strlen(pre); i++)
+ destbuf[dasmdata->divider2+i] = pre[i] ;
+
+ // Stick in the comment itself
+ strcpy(bob, debug_comment_get_text(cpu_getactivecpu(), comment_address, debug_comment_get_opcode_crc32(comment_address))) ;
+ for (i = 0; i < (dasmdata->allocated_cols - dasmdata->divider2 - strlen(pre) - 1); i++)
+ destbuf[dasmdata->divider2+i+strlen(pre)] = bob[i] ;
+ }
+ else
+ sprintf(&destbuf[dasmdata->divider2], " ");
+ }
+
+ /* see if the line changed at all */
+ if (lines == 1 && strncmp(oldbuf, destbuf, MIN(sizeof(oldbuf), dasmdata->allocated_cols)) != 0)
+ changed = TRUE;
+ }
+
+ /* reset the opcode base */
+ if (dasmdata->cpunum == original_cpunum)
+ memory_set_opbase(activecpu_get_physical_pc_byte());
+
+ /* update opcode base information */
+ dasmdata->last_opcode_base = opcode_base;
+ dasmdata->last_opcode_arg_base = opcode_arg_base;
+ dasmdata->last_change_count = debug_comment_all_change_count();
+
+ /* now longer need to recompute */
+ dasmdata->recompute = FALSE;
+ return changed;
+}
+
+
+/*-------------------------------------------------
+ disasm_update - update the contents of
+ the disassembly view
+-------------------------------------------------*/
+
+static void disasm_update(debug_view *view)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ offs_t pc = cpunum_get_reg(dasmdata->cpunum, REG_PC);
+ offs_t pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+ debug_view_char *dest = view->viewdata;
+ int original_cpunum = cpu_getactivecpu();
+ int recomputed_this_time = FALSE;
+ EXPRERR exprerr;
+ UINT32 row;
+
+ /* switch to the CPU's context */
+ cpuintrf_push_context(dasmdata->cpunum);
+
+ /* if our expression is dirty, fix it */
+ if (dasmdata->expression_dirty && dasmdata->expression_string)
+ {
+ parsed_expression *expr;
+
+ /* parse the new expression */
+ exprerr = expression_parse(dasmdata->expression_string, debug_get_cpu_info(dasmdata->cpunum)->symtable, &expr);
+
+ /* if it worked, update the expression */
+ if (exprerr == EXPRERR_NONE)
+ {
+ if (dasmdata->expression)
+ expression_free(dasmdata->expression);
+ dasmdata->expression = expr;
+ }
+ }
+
+ /* if we're tracking a value, make sure it is visible */
+ if (dasmdata->expression && (dasmdata->live_tracking || dasmdata->expression_dirty))
+ {
+ UINT64 result;
+
+ /* recompute the value of the expression */
+ exprerr = expression_execute(dasmdata->expression, &result);
+ if (exprerr == EXPRERR_NONE && result != dasmdata->last_result)
+ {
+ offs_t resultbyte = ADDR2BYTE_MASKED(result, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* update the result */
+ dasmdata->last_result = result;
+
+ /* see if the new result is an address we already have */
+ for (row = 0; row < dasmdata->allocated_rows; row++)
+ if (dasmdata->address[row] == resultbyte)
+ break;
+
+ /* if we didn't find it, or if it's really close to the bottom, recompute */
+ if (row == dasmdata->allocated_rows || row >= view->total_rows - view->visible_rows)
+ dasmdata->recompute = TRUE;
+
+ /* otherwise, if it's not visible, adjust the view so it is */
+ else if (row < view->top_row || row >= view->top_row + view->visible_rows - 2)
+ view->top_row = (row > 3) ? row - 3 : 0;
+ }
+
+ /* no longer dirty */
+ dasmdata->expression_dirty = FALSE;
+ }
+
+ /* if the opcode base has changed, rework things */
+ if (opcode_base != dasmdata->last_opcode_base || opcode_arg_base != dasmdata->last_opcode_arg_base)
+ dasmdata->recompute = TRUE;
+
+ /* if the comments have changed, redo it */
+ if (dasmdata->last_change_count != debug_comment_all_change_count())
+ dasmdata->recompute = TRUE;
+
+ /* if we need to recompute, do it */
+recompute:
+ if (dasmdata->recompute)
+ {
+ /* determine the addresses of what we will display */
+ offs_t backpc = disasm_back_up(dasmdata->cpunum, cpuinfo, (UINT32)dasmdata->last_result, dasmdata->backwards_steps);
+
+ /* recompute the view */
+ if (dasmdata->last_change_count != debug_comment_all_change_count())
+ {
+ /* smoosh us against the left column, but not the top row */
+ view->left_col = 0;
+
+ /* recompute from where we last recomputed! */
+ disasm_recompute(view, BYTE2ADDR(dasmdata->address[0], cpuinfo, ADDRESS_SPACE_PROGRAM), 0, view->total_rows, original_cpunum);
+ }
+ else
+ {
+ /* put ourselves back in the top left */
+ view->top_row = 0;
+ view->left_col = 0;
+
+ disasm_recompute(view, backpc, 0, view->total_rows, original_cpunum);
+ }
+ 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_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ if (effrow >= dasmdata->allocated_rows)
+ break;
+ if (pcbyte == dasmdata->address[effrow])
+ {
+ /* see if we changed */
+ int changed = disasm_recompute(view, pc, effrow, 1, original_cpunum);
+ if (changed && !recomputed_this_time)
+ {
+ dasmdata->recompute = TRUE;
+ goto recompute;
+ }
+
+ /* set the effective row and PC */
+ view->cursor_row = effrow;
+ dasmdata->active_address = pcbyte;
+ }
+ }
+ dasmdata->last_pcbyte = pcbyte;
+ }
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + 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_rows)
+ {
+ const char *data = &dasmdata->dasm[effrow * dasmdata->allocated_cols];
+ UINT32 effcol = view->left_col;
+ UINT32 len = 0;
+
+ /* if we're on the line with the PC, recompute and hilight it */
+ if (pcbyte == dasmdata->address[effrow])
+ attrib = DCA_CURRENT;
+
+ /* if we're on a line with a breakpoint, tag it changed */
+ else
+ {
+ for (bp = cpuinfo->first_bp; bp; bp = bp->next)
+ if (dasmdata->address[effrow] == ADDR2BYTE_MASKED(bp->address, cpuinfo, ADDRESS_SPACE_PROGRAM))
+ attrib = DCA_CHANGED;
+ }
+
+ /* if we're on the active column and everything is couth, highlight it */
+ if (view->cursor_visible && effrow == view->cursor_row)
+ {
+ if (dasmdata->active_address == dasmdata->address[effrow])
+ attrib |= DCA_SELECTED;
+ }
+
+ /* get the effective string */
+ len = (UINT32)strlen(data);
+
+ /* copy data */
+ while (col < view->visible_cols && 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 == DVP_DASM_RIGHTCOL_COMMENTS)
+ attrib |= DCA_COMMENT;
+
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = (effrow < view->total_rows) ? (attrib | DCA_ANCILLARY) : attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* restore the original CPU context */
+ cpuintrf_pop_context();
+}
+
+
+/*-------------------------------------------------
+ disasm_handle_char - handle a character typed
+ within the current view
+-------------------------------------------------*/
+
+static void disasm_handle_char(debug_view *view, char chval)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+ UINT8 end_buffer = 3;
+ INT32 temp;
+
+ switch (chval)
+ {
+ case DCH_UP:
+ if (view->cursor_row > 0)
+ view->cursor_row--;
+ break;
+
+ case DCH_DOWN:
+ if (view->cursor_row < view->total_rows - 1)
+ view->cursor_row++;
+ break;
+
+ case DCH_PUP:
+ temp = view->cursor_row - (view->visible_rows - end_buffer);
+
+ if (temp < 0)
+ view->cursor_row = 0;
+ else
+ view->cursor_row = temp;
+ break;
+
+ case DCH_PDOWN:
+ temp = view->cursor_row + (view->visible_rows - end_buffer);
+
+ if (temp > (view->total_rows - 1))
+ view->cursor_row = (view->total_rows - 1);
+ else
+ view->cursor_row = temp;
+ break;
+
+ case DCH_HOME: /* set the active column to the PC */
+ {
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(dasmdata->cpunum);
+ offs_t pc = cpunum_get_reg(dasmdata->cpunum, REG_PC);
+ int i;
+
+ pc = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM);
+
+ /* figure out which row the pc is on */
+ for (i = 0; i < dasmdata->allocated_rows; i++)
+ {
+ if (dasmdata->address[i] == pc)
+ view->cursor_row = i;
+ }
+ break;
+ }
+
+ case DCH_CTRLHOME:
+ view->cursor_row = 0;
+ break;
+
+ case DCH_CTRLEND:
+ view->cursor_row = view->total_rows - 1;
+ break;
+ }
+
+ /* get the address under the cursor_row */
+ dasmdata->active_address = dasmdata->address[view->cursor_row];
+
+ /* scroll if out of range */
+ if (view->cursor_row < view->top_row)
+ view->top_row = view->cursor_row;
+ if (view->cursor_row >= view->top_row + view->visible_rows - end_buffer)
+ view->top_row = view->cursor_row - view->visible_rows + end_buffer;
+}
+
+
+/*-------------------------------------------------
+ disasm_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void disasm_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_DASM_CPUNUM:
+ value->i = dasmdata->cpunum;
+ break;
+
+ case DVP_DASM_EXPRESSION:
+ value->s = dasmdata->expression_string;
+ break;
+
+ case DVP_DASM_TRACK_LIVE:
+ value->i = dasmdata->live_tracking;
+ break;
+
+ case DVP_DASM_RIGHT_COLUMN:
+ value->i = dasmdata->right_column;
+ break;
+
+ case DVP_DASM_BACKWARD_STEPS:
+ value->i = dasmdata->backwards_steps;
+ break;
+
+ case DVP_DASM_WIDTH:
+ value->i = dasmdata->dasm_width;
+ break;
+
+ case DVP_DASM_ACTIVE_ADDRESS:
+ value->i = dasmdata->active_address;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ disasm_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void disasm_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_disasm *dasmdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_DASM_CPUNUM:
+ if (value.i != dasmdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ dasmdata->cpunum = value.i;
+
+ /* we need to recompute the expression in the context of the new CPU */
+ dasmdata->expression_dirty = TRUE;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_EXPRESSION:
+ debug_view_begin_update(view);
+
+ /* free the old expression string and allocate a new one */
+ if (dasmdata->expression_string)
+ free(dasmdata->expression_string);
+ dasmdata->expression_string = malloc(strlen(value.s) + 1);
+ if (dasmdata->expression_string)
+ strcpy(dasmdata->expression_string, value.s);
+
+ /* update everything as a result */
+ dasmdata->expression_dirty = TRUE;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_DASM_TRACK_LIVE:
+ if (value.i != dasmdata->live_tracking)
+ {
+ debug_view_begin_update(view);
+ dasmdata->live_tracking = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_RIGHT_COLUMN:
+ if (value.i != dasmdata->right_column && value.i >= DVP_DASM_RIGHTCOL_NONE && value.i <= DVP_DASM_RIGHTCOL_COMMENTS)
+ {
+ debug_view_begin_update(view);
+ dasmdata->right_column = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_BACKWARD_STEPS:
+ if (value.i != dasmdata->backwards_steps)
+ {
+ debug_view_begin_update(view);
+ dasmdata->backwards_steps = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_DASM_WIDTH:
+ if (value.i != dasmdata->dasm_width)
+ {
+ debug_view_begin_update(view);
+ dasmdata->dasm_width = value.i;
+ dasmdata->recompute = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CHARACTER:
+ debug_view_begin_update(view);
+ disasm_handle_char(view, value.i);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_DASM_ACTIVE_ADDRESS:
+ debug_view_begin_update(view);
+ dasmdata->active_address = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ debug_disasm_update_all - force all disasm
+ views to update
+-------------------------------------------------*/
+
+void debug_disasm_update_all(void)
+{
+ debug_view *view;
+
+ /* this is brute force */
+ for (view = first_view; view != NULL; view = view->next)
+ if (view->type == DVT_DISASSEMBLY)
+ {
+ debug_view_disasm *dasmdata = view->extra_data;
+ debug_view_begin_update(view);
+ view->update_pending = TRUE;
+ dasmdata->recompute = TRUE;
+ dasmdata->last_pcbyte = ~0;
+ debug_view_end_update(view);
+ }
+}
+
+
+
+/***************************************************************************
+
+ Memory view
+
+***************************************************************************/
+
+/*
+00000000 00 11 22 33 44 55 66 77-88 99 aa bb cc dd ee ff 0123456789abcdef
+00000000 0011 2233 4455 6677- 8899 aabb ccdd eeff 0123456789abcdef
+00000000 00112233 44556677 - 8899aabb ccddeeff 0123456789abcdef
+00000000 0011223344556677 - 8899aabbccddeeff 0123456789abcdef
+*/
+
+/*-------------------------------------------------
+ memory_alloc - allocate memory for the
+ memory view
+-------------------------------------------------*/
+
+static int memory_alloc(debug_view *view)
+{
+ debug_view_memory *memdata;
+
+ /* allocate memory */
+ memdata = malloc(sizeof(*memdata));
+ if (!memdata)
+ return 0;
+ memset(memdata, 0, sizeof(*memdata));
+
+ /* by default we track live */
+ memdata->live_tracking = TRUE;
+ memdata->ascii_view = TRUE;
+
+ /* stash the extra data pointer */
+ view->extra_data = memdata;
+
+ /* we support cursors */
+ view->supports_cursor = TRUE;
+
+ /* start out with 16 bytes in a single column */
+ memdata->chunks_displayed = 16;
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ memory_free - free memory for the
+ memory view
+-------------------------------------------------*/
+
+static void memory_free(debug_view *view)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ /* free any memory we callocated */
+ if (memdata)
+ {
+ if (memdata->expression)
+ expression_free(memdata->expression);
+ if (memdata->expression_string)
+ free(memdata->expression_string);
+ free(memdata);
+ }
+ view->extra_data = NULL;
+}
+
+
+/*-------------------------------------------------
+ memory_get_cursor_pos - return the cursor
+ position as an address and a shift value
+-------------------------------------------------*/
+
+static int memory_get_cursor_pos(debug_view *view, offs_t *address, UINT8 *shift)
+{
+ debug_view_memory *memdata = view->extra_data;
+ int curx = view->cursor_col, cury = view->cursor_row;
+ UINT32 bytes_per_row;
+ int modval;
+
+ /* if not in the middle section, punt */
+ if (curx <= memdata->divider1)
+ curx = memdata->divider1 + 1;
+ if (curx >= memdata->divider2)
+ curx = memdata->divider2 - 1;
+ curx -= memdata->divider1;
+
+ /* compute the base address */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ *address = bytes_per_row * cury + memdata->byte_offset;
+
+ /* the rest depends on the current format */
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ modval = curx % 3;
+ if (modval == 0) modval = 1;
+ modval -= 1;
+ if (!memdata->reverse_view)
+ *address += curx / 3;
+ else
+ *address += 15 - curx / 3;
+ *shift = 8-4 - 4 * modval;
+ break;
+
+ case 2:
+ modval = curx % 6;
+ if (modval <= 1) modval = 2;
+ modval -= 2;
+ if (!memdata->reverse_view)
+ *address += 2 * (curx / 6);
+ else
+ *address += 14 - 2 * (curx / 6);
+ *shift = 16-4 - 4 * modval;
+ break;
+
+ case 4:
+ modval = curx % 12;
+ if (modval <= 2) modval = 3;
+ if (modval == 11) modval = 10;
+ modval -= 3;
+ if (!memdata->reverse_view)
+ *address += 4 * (curx / 12);
+ else
+ *address += 12 - 4 * (curx / 12);
+ *shift = 32-4 - 4 * modval;
+ break;
+
+ case 8:
+ modval = curx % 24;
+ if (modval <= 4) modval = 5;
+ if (modval >= 21) modval = 20;
+ modval -= 5;
+ if (!memdata->reverse_view)
+ *address += 8 * (curx / 24);
+ else
+ *address += 8 - 8 * (curx / 24);
+ *shift = 64-4 - 4 * modval;
+ break;
+ }
+
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ memory_set_cursor_pos - set the cursor
+ position as a function of an address and a
+ shift value
+-------------------------------------------------*/
+
+static void memory_set_cursor_pos(debug_view *view, offs_t address, UINT8 shift)
+{
+ debug_view_memory *memdata = view->extra_data;
+ UINT32 bytes_per_row;
+ int curx, cury;
+ UINT8 end_buffer = 2;
+
+ /* offset the address by the byte offset */
+ address -= memdata->byte_offset;
+
+ /* compute the y coordinate */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ cury = address / bytes_per_row;
+
+ /* the rest depends on the current format */
+
+ /* non-reverse case */
+ if (!memdata->reverse_view)
+ {
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ curx = memdata->divider1 + 1 + 3 * (address % bytes_per_row) + (1 - (shift / 4));
+ break;
+
+ case 2:
+ curx = memdata->divider1 + 2 + 6 * ((address % bytes_per_row) / 2) + (3 - (shift / 4));
+ break;
+
+ case 4:
+ curx = memdata->divider1 + 3 + 12 * ((address % bytes_per_row) / 4) + (7 - (shift / 4));
+ break;
+
+ case 8:
+ curx = memdata->divider1 + 5 + 24 * ((address % bytes_per_row) / 8) + (15 - (shift / 4));
+ break;
+ }
+ }
+ else
+ {
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ curx = memdata->divider1 + 1 + 3 * (15 - address % bytes_per_row) + (1 - (shift / 4));
+ break;
+
+ case 2:
+ curx = memdata->divider1 + 2 + 6 * (7 - (address % bytes_per_row) / 2) + (3 - (shift / 4));
+ break;
+
+ case 4:
+ curx = memdata->divider1 + 3 + 12 * (3 - (address % bytes_per_row) / 4) + (7 - (shift / 4));
+ break;
+
+ case 8:
+ curx = memdata->divider1 + 5 + 24 * (1 - (address % bytes_per_row) / 8) + (15 - (shift / 4));
+ break;
+ }
+ }
+
+ /* set the position, clamping to the window bounds */
+ view->cursor_col = (curx < 0) ? 0 : (curx >= view->total_cols) ? (view->total_cols - end_buffer) : curx;
+ view->cursor_row = (cury < 0) ? 0 : (cury >= view->total_rows) ? (view->total_rows - end_buffer) : cury;
+
+ /* scroll if out of range */
+ if (view->cursor_row < view->top_row)
+ view->top_row = view->cursor_row;
+ if (view->cursor_row >= view->top_row + view->visible_rows - end_buffer)
+ view->top_row = view->cursor_row - view->visible_rows + end_buffer;
+}
+
+
+/*-------------------------------------------------
+ memory_read_byte - generic byte reader
+-------------------------------------------------*/
+
+static UINT8 memory_read_byte(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_byte(memdata->spacenum, offs, apply_translation);
+
+ /* all 0xff if out of bounds */
+ offs ^= memdata->raw_offset_xor;
+ if (offs >= memdata->raw_length)
+ return 0xff;
+ return *((UINT8 *)memdata->raw_base + offs);
+}
+
+
+/*-------------------------------------------------
+ memory_read_word - generic word reader
+-------------------------------------------------*/
+
+static UINT16 memory_read_word(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_word(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into bytes */
+ if (memdata->raw_little_endian)
+ return memory_read_byte(memdata, offs + 0, apply_translation) | (memory_read_byte(memdata, offs + 1, apply_translation) << 8);
+ else
+ return memory_read_byte(memdata, offs + 1, apply_translation) | (memory_read_byte(memdata, offs + 0, apply_translation) << 8);
+}
+
+
+/*-------------------------------------------------
+ memory_read_dword - generic dword reader
+-------------------------------------------------*/
+
+static UINT32 memory_read_dword(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_dword(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into words */
+ if (memdata->raw_little_endian)
+ return memory_read_word(memdata, offs + 0, apply_translation) | (memory_read_word(memdata, offs + 2, apply_translation) << 16);
+ else
+ return memory_read_word(memdata, offs + 2, apply_translation) | (memory_read_word(memdata, offs + 0, apply_translation) << 16);
+}
+
+
+/*-------------------------------------------------
+ memory_read_qword - generic qword reader
+-------------------------------------------------*/
+
+static UINT64 memory_read_qword(debug_view_memory *memdata, offs_t offs, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ return debug_read_qword(memdata->spacenum, offs, apply_translation);
+
+ /* otherwise, decompose into dwords */
+ if (memdata->raw_little_endian)
+ return memory_read_dword(memdata, offs + 0, apply_translation) | ((UINT64)memory_read_dword(memdata, offs + 4, apply_translation) << 32);
+ else
+ return memory_read_dword(memdata, offs + 4, apply_translation) | ((UINT64)memory_read_dword(memdata, offs + 0, apply_translation) << 32);
+}
+
+
+/*-------------------------------------------------
+ memory_write_byte - generic byte writer
+-------------------------------------------------*/
+
+static void memory_write_byte(debug_view_memory *memdata, offs_t offs, UINT8 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_byte(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* ignore if out of bounds */
+ offs ^= memdata->raw_offset_xor;
+ if (offs >= memdata->raw_length)
+ return;
+ *((UINT8 *)memdata->raw_base + offs) = data;
+
+/* hack for FD1094 editing */
+#ifdef FD1094_HACK
+ if (memdata->raw_base == memory_region(REGION_USER2))
+ {
+ extern void fd1094_regenerate_key(void);
+ fd1094_regenerate_key();
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+ memory_write_word - generic word writer
+-------------------------------------------------*/
+
+static void memory_write_word(debug_view_memory *memdata, offs_t offs, UINT16 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_word(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into bytes */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_byte(memdata, offs + 0, data, apply_translation);
+ memory_write_byte(memdata, offs + 1, data >> 8, apply_translation);
+ }
+ else
+ {
+ memory_write_byte(memdata, offs + 1, data, apply_translation);
+ memory_write_byte(memdata, offs + 0, data >> 8, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_write_dword - generic dword writer
+-------------------------------------------------*/
+
+static void memory_write_dword(debug_view_memory *memdata, offs_t offs, UINT32 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_dword(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into words */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_word(memdata, offs + 0, data, apply_translation);
+ memory_write_word(memdata, offs + 2, data >> 16, apply_translation);
+ }
+ else
+ {
+ memory_write_word(memdata, offs + 2, data, apply_translation);
+ memory_write_word(memdata, offs + 0, data >> 16, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_write_qword - generic qword writer
+-------------------------------------------------*/
+
+static void memory_write_qword(debug_view_memory *memdata, offs_t offs, UINT64 data, int apply_translation)
+{
+ /* if no raw data, just use the standard debug routines */
+ if (memdata->raw_base == NULL)
+ {
+ debug_write_qword(memdata->spacenum, offs, data, apply_translation);
+ return;
+ }
+
+ /* otherwise, decompose into dwords */
+ if (memdata->raw_little_endian)
+ {
+ memory_write_dword(memdata, offs + 0, data, apply_translation);
+ memory_write_dword(memdata, offs + 4, data >> 32, apply_translation);
+ }
+ else
+ {
+ memory_write_dword(memdata, offs + 4, data, apply_translation);
+ memory_write_dword(memdata, offs + 0, data >> 32, apply_translation);
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_handle_char - handle a character typed
+ within the current view
+-------------------------------------------------*/
+
+static void memory_handle_char(debug_view *view, char chval)
+{
+ debug_view_memory *memdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(memdata->cpunum);
+ static const char hexvals[] = "0123456789abcdef";
+ char *hexchar = strchr(hexvals, tolower(chval));
+ UINT32 bytes_per_row;
+ UINT32 tempaddr;
+ offs_t maxaddr;
+ offs_t address;
+ UINT8 shift;
+
+ /* determine the max address */
+ maxaddr = memdata->raw_base ? (memdata->raw_length - 1) : cpuinfo->space[memdata->spacenum].logbytemask;
+
+ /* get the position */
+ if (!memory_get_cursor_pos(view, &address, &shift))
+ return;
+
+ /* handle the incoming key */
+ /* up/down work the same regardless */
+ bytes_per_row = memdata->chunks_displayed * memdata->bytes_per_chunk;
+
+ switch (chval)
+ {
+ case DCH_UP:
+ if (view->cursor_row > 0)
+ address -= bytes_per_row;
+ break;
+
+ case DCH_DOWN:
+ if (view->cursor_row < view->total_rows - 1)
+ address += bytes_per_row;
+ break;
+
+ case DCH_PUP:
+ tempaddr = address - (bytes_per_row * (view->visible_rows-2)) ;
+ if (tempaddr > address) /* unsigned wraparound */
+ address = address % bytes_per_row;
+ else
+ address = tempaddr;
+ break;
+
+ case DCH_PDOWN:
+ tempaddr = address + (bytes_per_row * (view->visible_rows-2)) ;
+ if (tempaddr > maxaddr)
+ address = (maxaddr - (bytes_per_row-1)) + (address % bytes_per_row);
+ else
+ address = tempaddr;
+ break;
+
+ case DCH_HOME:
+ address -= address % bytes_per_row;
+ shift = (memdata->bytes_per_chunk * 8) - 1;
+ break;
+
+ case DCH_CTRLHOME:
+ address = 0;
+ shift = (memdata->bytes_per_chunk * 8) - 1;
+ break;
+
+ case DCH_END:
+ address += (bytes_per_row - (address % bytes_per_row) - 1);
+ shift = 0;
+ break;
+
+ case DCH_CTRLEND:
+ address = maxaddr;
+ shift = 0;
+ break;
+
+ case DCH_CTRLRIGHT:
+ if (address < maxaddr-memdata->bytes_per_chunk)
+ address += memdata->bytes_per_chunk;
+ break;
+
+ case DCH_CTRLLEFT:
+ if (address >= memdata->bytes_per_chunk)
+ address -= memdata->bytes_per_chunk;
+ break;
+ }
+
+ /* switch off of the current chunk size */
+ cpuintrf_push_context(memdata->cpunum);
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ if (hexchar)
+ memory_write_byte(memdata, address, (memory_read_byte(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 8-4; if (address != maxaddr) address++; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 8-4) { shift = 0; if (address != 0) address--; }
+ else shift += 4;
+ }
+ break;
+
+ case 2:
+ if (hexchar)
+ memory_write_word(memdata, address, (memory_read_word(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 16-4; if (address != maxaddr) address += 2; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 16-4) { shift = 0; if (address != 0) address -= 2; }
+ else shift += 4;
+ }
+ break;
+
+ case 4:
+ if (hexchar)
+ memory_write_dword(memdata, address, (memory_read_dword(memdata, address, !memdata->no_translation) & ~(0xf << shift)) | ((hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 32-4; if (address != maxaddr) address += 4; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 32-4) { shift = 0; if (address != 0) address -= 4; }
+ else shift += 4;
+ }
+ break;
+
+ case 8:
+ if (hexchar)
+ memory_write_qword(memdata, address, (memory_read_qword(memdata, address, !memdata->no_translation) & ~((UINT64)0xf << shift)) | ((UINT64)(hexchar - hexvals) << shift), !memdata->no_translation);
+ if (hexchar || chval == DCH_RIGHT)
+ {
+ if (shift == 0) { shift = 64-4; if (address != maxaddr) address += 8; }
+ else shift -= 4;
+ }
+ else if (chval == DCH_LEFT)
+ {
+ if (shift == 64-4) { shift = 0; if (address != 0) address -= 8; }
+ else shift += 4;
+ }
+ break;
+ }
+ cpuintrf_pop_context();
+
+ /* set a new position */
+ memory_set_cursor_pos(view, address, shift);
+}
+
+
+/*-------------------------------------------------
+ memory_update - update the contents of
+ the register view
+-------------------------------------------------*/
+
+static void memory_update(debug_view *view)
+{
+ debug_view_memory *memdata = view->extra_data;
+ const debug_cpu_info *cpuinfo = debug_get_cpu_info(memdata->cpunum);
+ debug_view_char *dest = view->viewdata;
+ char addrformat[16];
+ EXPRERR exprerr;
+ UINT8 addrchars;
+ UINT32 maxaddr;
+ offs_t addrmask;
+ UINT32 row;
+ UINT32 memory_display_width;
+ UINT32 bytes_per_line;
+
+ /* switch to the CPU's context */
+ if (memdata->raw_base == NULL)
+ cpuintrf_push_context(memdata->cpunum);
+
+ /* determine maximum address and number of characters for that */
+ if (memdata->raw_base != NULL)
+ {
+ maxaddr = memdata->raw_length - 1;
+ sprintf(addrformat, "%X", maxaddr);
+ addrchars = (UINT8)strlen(addrformat);
+ addrmask = maxaddr;
+ for (row = 0; row < 32; row++)
+ addrmask |= addrmask >> row;
+ }
+ else
+ {
+ maxaddr = cpuinfo->space[memdata->spacenum].logbytemask;
+ addrchars = cpuinfo->space[memdata->spacenum].logchars;
+ addrmask = cpuinfo->space[memdata->spacenum].logbytemask;
+
+ /* clamp the bytes per chunk */
+ if (memdata->bytes_per_chunk < (1 << cpuinfo->space[memdata->spacenum].addr2byte_lshift))
+ memdata->bytes_per_chunk = (1 << cpuinfo->space[memdata->spacenum].addr2byte_lshift);
+ }
+
+ /* determine how many characters we need for an address and set the divider */
+ sprintf(addrformat, " %*s%%0%dX ", 8 - addrchars, "", addrchars);
+
+ /* determine how wide the memory display area is */
+ bytes_per_line = memdata->chunks_displayed * memdata->bytes_per_chunk;
+ memory_display_width = 1 + (bytes_per_line * 3) + 1; /* characters + spaces */
+
+ /* compute total displayed rows and columns */
+ view->total_rows = (maxaddr / bytes_per_line) + 1;
+ view->total_cols = (1 + 8 + 1) + memory_display_width;
+ view->total_cols += memdata->ascii_view ? 1 + bytes_per_line : 0 ; /* +1 ??? */ /* 77 : 59; */
+
+ /* set up the dividers */
+ memdata->divider1 = 1 + 8 + 1;
+ memdata->divider2 = memdata->divider1 + memory_display_width;
+ if (memdata->reverse_view)
+ {
+ int temp = view->total_cols + 1 - memdata->divider2;
+ memdata->divider2 = view->total_cols + 1 - memdata->divider1;
+ memdata->divider1 = temp;
+ }
+
+ /* if our expression is dirty, fix it */
+ if (memdata->expression_dirty && memdata->expression_string)
+ {
+ parsed_expression *expr;
+
+ /* parse the new expression */
+ exprerr = expression_parse(memdata->expression_string, debug_get_cpu_info(memdata->cpunum)->symtable, &expr);
+
+ /* if it worked, update the expression */
+ if (exprerr == EXPRERR_NONE)
+ {
+ if (memdata->expression)
+ expression_free(memdata->expression);
+ memdata->expression = expr;
+ memdata->expression_dirty = FALSE;
+ memdata->recompute = TRUE;
+ }
+ }
+
+ /* if we're tracking a value, make sure it is visible */
+ if (memdata->expression && (memdata->live_tracking || memdata->recompute))
+ {
+ UINT64 result;
+
+ /* recompute the value of the expression */
+ exprerr = expression_execute(memdata->expression, &result);
+
+ /* reset the row number */
+ if (result != memdata->last_result || memdata->expression_dirty || memdata->cpunum != memdata->cpunum)
+ {
+ memdata->last_result = result;
+ if (memdata->raw_base == NULL)
+ result = ADDR2BYTE_MASKED(memdata->last_result, cpuinfo, memdata->spacenum);
+ view->top_row = result / bytes_per_line;
+ memdata->byte_offset = result % bytes_per_line;
+ view->cursor_row = view->top_row;
+ }
+ memdata->recompute = FALSE;
+ }
+
+ /* loop over visible rows */
+ for (row = 0; row < view->visible_rows; row++)
+ {
+ UINT32 effrow = view->top_row + row;
+ offs_t addrbyte = effrow * bytes_per_line + memdata->byte_offset;
+ UINT8 attrib = DCA_NORMAL;
+ UINT32 col = 0;
+
+ /* if this visible row is valid, add it to the buffer */
+ if (effrow < view->total_rows)
+ {
+ UINT32 effcol = view->left_col;
+ UINT32 len = 0;
+ char data[MEM_MAX_LINE_WIDTH];
+ int i;
+
+ /* generate the string */
+ if (!memdata->reverse_view)
+ {
+ len = sprintf(&data[len], addrformat, BYTE2ADDR(addrbyte & addrmask, cpuinfo, memdata->spacenum));
+ len += sprintf(&data[len], " ");
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], "%02X ", memory_read_byte(memdata, addrbyte + i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], "** ");
+ }
+ break;
+
+ case 2:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 2 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %04X ", memory_read_word(memdata, addrbyte + 2 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " **** ");
+ }
+ break;
+
+ case 4:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 4 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %08X ", memory_read_dword(memdata, addrbyte + 4 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " ******** ");
+ }
+ break;
+
+ case 8:
+ for (i = 0; i < memdata->chunks_displayed; i++)
+ {
+ offs_t curaddr = addrbyte + 8 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ {
+ UINT64 qword = memory_read_qword(memdata, addrbyte + 8 * i, !memdata->no_translation);
+ len += sprintf(&data[len], " %08X%08X ", (UINT32)(qword >> 32), (UINT32)qword);
+ }
+ else
+ len += sprintf(&data[len], " **************** ");
+ }
+ break;
+ }
+ len += sprintf(&data[len], " ");
+ if (memdata->ascii_view)
+ {
+ for (i = 0; i < bytes_per_line; i++)
+ {
+ if (addrbyte + i <= maxaddr)
+ {
+ char c = memory_read_byte(memdata, addrbyte + i, !memdata->no_translation);
+ len += sprintf(&data[len], "%c", isprint((UINT8)c) ? c : '.');
+ }
+ else
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ }
+ }
+ else
+ {
+ len = sprintf(&data[len], " ");
+ if (memdata->ascii_view)
+ {
+ for (i = 0; i < bytes_per_line; i++)
+ {
+ if (addrbyte + i <= maxaddr)
+ {
+ char c = memory_read_byte(memdata, addrbyte + i, !memdata->no_translation);
+ len += sprintf(&data[len], "%c", isprint((UINT8)c) ? c : '.');
+ }
+ else
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ }
+ len += sprintf(&data[len], " ");
+ switch (memdata->bytes_per_chunk)
+ {
+ default:
+ case 1:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], "%02X ", memory_read_byte(memdata, addrbyte + i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], "** ");
+ }
+ break;
+
+ case 2:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 2 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %04X ", memory_read_word(memdata, addrbyte + 2 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " **** ");
+ }
+ break;
+
+ case 4:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 4 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ len += sprintf(&data[len], " %08X ", memory_read_dword(memdata, addrbyte + 4 * i, !memdata->no_translation));
+ else
+ len += sprintf(&data[len], " ******** ");
+ }
+ break;
+
+ case 8:
+ for (i = memdata->chunks_displayed - 1; i >= 0; i--)
+ {
+ offs_t curaddr = addrbyte + 8 * i;
+ if (curaddr > maxaddr)
+ len += sprintf(&data[len], " ");
+ else if (memdata->raw_base != NULL || memdata->no_translation ||
+ cpuinfo->translate == NULL || (*cpuinfo->translate)(memdata->spacenum, &curaddr))
+ {
+ UINT64 qword = memory_read_qword(memdata, addrbyte + 8 * i, !memdata->no_translation);
+ len += sprintf(&data[len], " %08X%08X ", (UINT32)(qword >> 32), (UINT32)qword);
+ }
+ else
+ len += sprintf(&data[len], " **************** ");
+ }
+ break;
+ }
+ len += sprintf(&data[len], addrformat, BYTE2ADDR(addrbyte & addrmask, cpuinfo, memdata->spacenum));
+ }
+
+ /* copy data */
+ while (col < view->visible_cols && effcol < len)
+ {
+ dest->byte = data[effcol++];
+ if (effcol <= memdata->divider1 || effcol >= memdata->divider2)
+ dest->attrib = attrib | DCA_ANCILLARY;
+ else if (view->cursor_visible && effcol - 1 == view->cursor_col && effrow == view->cursor_row && dest->byte != ' ')
+ dest->attrib = attrib | DCA_SELECTED;
+ else
+ dest->attrib = attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* fill the rest with blanks */
+ while (col < view->visible_cols)
+ {
+ dest->byte = ' ';
+ dest->attrib = (effrow < view->total_rows) ? (attrib | DCA_ANCILLARY) : attrib;
+ dest++;
+ col++;
+ }
+ }
+
+ /* restore the context */
+ if (memdata->raw_base == NULL)
+ cpuintrf_pop_context();
+}
+
+
+/*-------------------------------------------------
+ memory_getprop - return the value
+ of a given property
+-------------------------------------------------*/
+
+static void memory_getprop(debug_view *view, UINT32 property, debug_property_info *value)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_MEM_EXPRESSION:
+ value->s = memdata->expression_string;
+ break;
+
+ case DVP_MEM_TRACK_LIVE:
+ value->i = memdata->live_tracking;
+ break;
+
+ case DVP_MEM_NO_TRANSLATION:
+ value->i = memdata->no_translation;
+ break;
+
+ case DVP_MEM_CPUNUM:
+ value->i = memdata->cpunum;
+ break;
+
+ case DVP_MEM_SPACENUM:
+ value->i = memdata->spacenum;
+ break;
+
+ case DVP_MEM_BYTES_PER_CHUNK:
+ value->i = memdata->bytes_per_chunk;
+ break;
+
+ case DVP_MEM_REVERSE_VIEW:
+ value->i = memdata->reverse_view;
+ break;
+
+ case DVP_MEM_ASCII_VIEW:
+ value->i = memdata->ascii_view;
+ break;
+
+ case DVP_MEM_RAW_BASE:
+ value->p = memdata->raw_base;
+ break;
+
+ case DVP_MEM_RAW_LENGTH:
+ value->i = memdata->raw_length;
+ break;
+
+ case DVP_MEM_RAW_OFFSET_XOR:
+ value->i = memdata->raw_offset_xor;
+ break;
+
+ case DVP_MEM_RAW_LITTLE_ENDIAN:
+ value->i = memdata->raw_little_endian;
+ break;
+
+ case DVP_MEM_WIDTH:
+ value->i = memdata->chunks_displayed;
+ break;
+
+ default:
+ fatalerror("Attempt to get invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ memory_setprop - set the value
+ of a given property
+-------------------------------------------------*/
+
+static void memory_setprop(debug_view *view, UINT32 property, debug_property_info value)
+{
+ debug_view_memory *memdata = view->extra_data;
+
+ switch (property)
+ {
+ case DVP_MEM_EXPRESSION:
+ debug_view_begin_update(view);
+
+ /* free the old expression and allocate a new copy */
+ if (memdata->expression_string)
+ free(memdata->expression_string);
+ memdata->expression_string = malloc(strlen(value.s) + 1);
+ if (memdata->expression_string)
+ strcpy(memdata->expression_string, value.s);
+
+ memdata->expression_dirty = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_MEM_NO_TRANSLATION:
+ if (value.i != memdata->no_translation)
+ {
+ debug_view_begin_update(view);
+ memdata->no_translation = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_TRACK_LIVE:
+ if (value.i != memdata->live_tracking)
+ {
+ debug_view_begin_update(view);
+ memdata->live_tracking = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_CPUNUM:
+ if (value.i != memdata->cpunum)
+ {
+ debug_view_begin_update(view);
+ memdata->cpunum = value.i;
+ view->update_pending = TRUE;
+ memdata->expression_dirty = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_SPACENUM:
+ if (value.i != memdata->spacenum)
+ {
+ debug_view_begin_update(view);
+ memdata->spacenum = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_BYTES_PER_CHUNK:
+ if (value.i != memdata->bytes_per_chunk)
+ {
+ debug_view_begin_update(view);
+
+ /* Change chunks_displayed based on the new bytes_per_chunk */
+ memdata->chunks_displayed = memdata->chunks_displayed *
+ memdata->bytes_per_chunk / value.i;
+
+ if (memdata->chunks_displayed <= 0)
+ memdata->chunks_displayed = 1;
+
+ memdata->bytes_per_chunk = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_REVERSE_VIEW:
+ if (value.i != memdata->reverse_view)
+ {
+ debug_view_begin_update(view);
+ memdata->reverse_view = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_ASCII_VIEW:
+ if (value.i != memdata->ascii_view)
+ {
+ debug_view_begin_update(view);
+ memdata->ascii_view = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_BASE:
+ if (value.p != memdata->raw_base)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_base = value.p;
+ memdata->expression_dirty = TRUE;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_LENGTH:
+ if (value.i != memdata->raw_length)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_length = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_OFFSET_XOR:
+ if (value.i != memdata->raw_offset_xor)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_offset_xor = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_MEM_RAW_LITTLE_ENDIAN:
+ if (value.i != memdata->raw_little_endian)
+ {
+ debug_view_begin_update(view);
+ memdata->raw_little_endian = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+ case DVP_CHARACTER:
+ debug_view_begin_update(view);
+ memory_handle_char(view, value.i);
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ break;
+
+ case DVP_MEM_WIDTH:
+ if (value.i != memdata->chunks_displayed)
+ {
+ /* lower bounds check - maybe upper bounds check someday? */
+ if (value.i < 1) break;
+
+ debug_view_begin_update(view);
+ memdata->chunks_displayed = value.i;
+ view->update_pending = TRUE;
+ debug_view_end_update(view);
+ }
+ break;
+
+
+ default:
+ fatalerror("Attempt to set invalid property %d on debug view type %d", property, view->type);
+ break;
+ }
+}