summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
author Wilbert Pol <wilbert@jdg.info>2013-03-11 21:29:51 +0000
committer Wilbert Pol <wilbert@jdg.info>2013-03-11 21:29:51 +0000
commitc03729e963eb8d7a2fc49937ed9a594cbebed41c (patch)
treee9100399741d881b36c28fcdb9e5e1752f5af646 /src/emu/debug
parente7e15bca128cdadf20f9d891446008af170a80f4 (diff)
Debugger: [Wilbert Pol]
- Added support for registerpoints. - Added 'exit' as a synonym for 'quit'.
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugcmd.c151
-rw-r--r--src/emu/debug/debugcpu.c175
-rw-r--r--src/emu/debug/debugcpu.h36
-rw-r--r--src/emu/debug/debughlp.c97
4 files changed, 459 insertions, 0 deletions
diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c
index 7e13404ca26..4ceeb684edf 100644
--- a/src/emu/debug/debugcmd.c
+++ b/src/emu/debug/debugcmd.c
@@ -124,6 +124,10 @@ static void execute_wpset(running_machine &machine, int ref, int params, const c
static void execute_wpclear(running_machine &machine, int ref, int params, const char **param);
static void execute_wpdisenable(running_machine &machine, int ref, int params, const char **param);
static void execute_wplist(running_machine &machine, int ref, int params, const char **param);
+static void execute_rpset(running_machine &machine, int ref, int params, const char **param);
+static void execute_rpclear(running_machine &machine, int ref, int params, const char **param);
+static void execute_rpdisenable(running_machine &machine, int ref, int params, const char **param);
+static void execute_rplist(running_machine &machine, int ref, int params, const char **param);
static void execute_hotspot(running_machine &machine, int ref, int params, const char **param);
static void execute_save(running_machine &machine, int ref, int params, const char **param);
static void execute_load(running_machine &machine, int ref, int params, const char **param);
@@ -266,6 +270,7 @@ void debug_command_init(running_machine &machine)
debug_console_register_command(machine, "logerror", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_logerror);
debug_console_register_command(machine, "tracelog", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_tracelog);
debug_console_register_command(machine, "quit", CMDFLAG_NONE, 0, 0, 0, execute_quit);
+ debug_console_register_command(machine, "exit", CMDFLAG_NONE, 0, 0, 0, execute_quit);
debug_console_register_command(machine, "do", CMDFLAG_NONE, 0, 1, 1, execute_do);
debug_console_register_command(machine, "step", CMDFLAG_NONE, 0, 0, 1, execute_step);
debug_console_register_command(machine, "s", CMDFLAG_NONE, 0, 0, 1, execute_step);
@@ -309,6 +314,13 @@ void debug_command_init(running_machine &machine)
debug_console_register_command(machine, "wpenable", CMDFLAG_NONE, 1, 0, 1, execute_wpdisenable);
debug_console_register_command(machine, "wplist", CMDFLAG_NONE, 0, 0, 0, execute_wplist);
+ debug_console_register_command(machine, "rpset", CMDFLAG_NONE, 0, 1, 2, execute_rpset);
+ debug_console_register_command(machine, "rp", CMDFLAG_NONE, 0, 1, 2, execute_rpset);
+ debug_console_register_command(machine, "rpclear", CMDFLAG_NONE, 0, 0, 1, execute_rpclear);
+ debug_console_register_command(machine, "rpdisable", CMDFLAG_NONE, 0, 0, 1, execute_rpdisenable);
+ debug_console_register_command(machine, "rpenable", CMDFLAG_NONE, 1, 0, 1, execute_rpdisenable);
+ debug_console_register_command(machine, "rplist", CMDFLAG_NONE, 0, 0, 0, execute_rplist);
+
debug_console_register_command(machine, "hotspot", CMDFLAG_NONE, 0, 0, 3, execute_hotspot);
debug_console_register_command(machine, "save", CMDFLAG_NONE, AS_PROGRAM, 3, 4, execute_save);
@@ -1488,6 +1500,145 @@ static void execute_wplist(running_machine &machine, int ref, int params, const
/*-------------------------------------------------
+ execute_rpset - execute the registerpoint set
+ command
+-------------------------------------------------*/
+
+static void execute_rpset(running_machine &machine, int ref, int params, const char *param[])
+{
+ device_t *cpu;
+ const char *action = NULL;
+ int bpnum;
+
+ /* CPU is implicit */
+ if (!debug_command_parameter_cpu(machine, NULL, &cpu))
+ return;
+
+ /* param 1 is the condition */
+ parsed_expression condition(&cpu->debug()->symtable());
+ if (!debug_command_parameter_expression(machine, param[0], condition))
+ return;
+
+ /* param 2 is the action */
+ if (!debug_command_parameter_command(machine, action = param[1]))
+ return;
+
+ /* set the breakpoint */
+ bpnum = cpu->debug()->registerpoint_set(condition.original_string(), action);
+ debug_console_printf(machine, "Registerpoint %X set\n", bpnum);
+}
+
+
+/*-------------------------------------------------
+ execute_rpclear - execute the registerpoint
+ clear command
+-------------------------------------------------*/
+
+static void execute_rpclear(running_machine &machine, int ref, int params, const char *param[])
+{
+ UINT64 rpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ device_iterator iter(machine.root_device());
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
+ device->debug()->registerpoint_clear_all();
+ debug_console_printf(machine, "Cleared all registerpoints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(machine, param[0], &rpindex))
+ return;
+ else
+ {
+ device_iterator iter(machine.root_device());
+ bool found = false;
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
+ if (device->debug()->registerpoint_clear(rpindex))
+ found = true;
+ if (found)
+ debug_console_printf(machine, "Registerpoint %X cleared\n", (UINT32)rpindex);
+ else
+ debug_console_printf(machine, "Invalid registerpoint number %X\n", (UINT32)rpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_rpdisenable - execute the registerpoint
+ disable/enable commands
+-------------------------------------------------*/
+
+static void execute_rpdisenable(running_machine &machine, int ref, int params, const char *param[])
+{
+ UINT64 rpindex;
+
+ /* if 0 parameters, clear all */
+ if (params == 0)
+ {
+ device_iterator iter(machine.root_device());
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
+ device->debug()->registerpoint_enable_all(ref);
+ if (ref == 0)
+ debug_console_printf(machine, "Disabled all registerpoints\n");
+ else
+ debug_console_printf(machine, "Enabled all registeroints\n");
+ }
+
+ /* otherwise, clear the specific one */
+ else if (!debug_command_parameter_number(machine, param[0], &rpindex))
+ return;
+ else
+ {
+ device_iterator iter(machine.root_device());
+ bool found = false;
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
+ if (device->debug()->registerpoint_enable(rpindex, ref))
+ found = true;
+ if (found)
+ debug_console_printf(machine, "Registerpoint %X %s\n", (UINT32)rpindex, ref ? "enabled" : "disabled");
+ else
+ debug_console_printf(machine, "Invalid registerpoint number %X\n", (UINT32)rpindex);
+ }
+}
+
+
+/*-------------------------------------------------
+ execute_rplist - execute the registerpoint list
+ command
+-------------------------------------------------*/
+
+static void execute_rplist(running_machine &machine, int ref, int params, const char *param[])
+{
+ int printed = 0;
+ astring buffer;
+
+ /* loop over all CPUs */
+ device_iterator iter(machine.root_device());
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
+ if (device->debug()->registerpoint_first() != NULL)
+ {
+ debug_console_printf(machine, "Device '%s' registerpoints:\n", device->tag());
+
+ /* loop over the breakpoints */
+ for (device_debug::registerpoint *rp = device->debug()->registerpoint_first(); rp != NULL; rp = rp->next())
+ {
+ buffer.printf("%c%4X ", rp->enabled() ? ' ' : 'D', rp->index());
+ buffer.catprintf("if %s", rp->condition());
+ if (rp->action() != NULL)
+ buffer.catprintf(" do %s", rp->action());
+ debug_console_printf(machine, "%s\n", buffer.cstr());
+ printed++;
+ }
+ }
+
+ if (printed == 0)
+ debug_console_printf(machine, "No registerpoints currently installed\n");
+}
+
+
+/*-------------------------------------------------
execute_hotspot - execute the hotspot
command
-------------------------------------------------*/
diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c
index 1e7453649de..27e8305eb1b 100644
--- a/src/emu/debug/debugcpu.c
+++ b/src/emu/debug/debugcpu.c
@@ -91,6 +91,7 @@ struct debugcpu_private
UINT32 bpindex;
UINT32 wpindex;
+ UINT32 rpindex;
UINT64 wpdata;
UINT64 wpaddr;
@@ -150,6 +151,7 @@ void debug_cpu_init(running_machine &machine)
global->execution_state = EXECUTION_STATE_STOPPED;
global->bpindex = 1;
global->wpindex = 1;
+ global->rpindex = 1;
/* create a global symbol table */
global->symtable = global_alloc(symbol_table(&machine));
@@ -1653,6 +1655,7 @@ device_debug::device_debug(device_t &device)
m_last_total_cycles(0),
m_pc_history_index(0),
m_bplist(NULL),
+ m_rplist(NULL),
m_trace(NULL),
m_hotspots(NULL),
m_hotspot_count(0),
@@ -1721,6 +1724,7 @@ device_debug::~device_debug()
// free breakpoints and watchpoints
breakpoint_clear_all();
watchpoint_clear_all();
+ registerpoint_clear_all();
}
@@ -2457,6 +2461,95 @@ void device_debug::watchpoint_enable_all(bool enable)
//-------------------------------------------------
+// registerpoint_set - set a new registerpoint,
+// returning its index
+//-------------------------------------------------
+
+int device_debug::registerpoint_set(const char *condition, const char *action)
+{
+ // allocate a new one
+ registerpoint *rp = auto_alloc(m_device.machine(), registerpoint(m_symtable, m_device.machine().debugcpu_data->rpindex++, condition, action));
+
+ // hook it into our list
+ rp->m_next = m_rplist;
+ m_rplist = rp;
+
+ // update the flags and return the index
+ breakpoint_update_flags();
+ return rp->m_index;
+}
+
+
+//-------------------------------------------------
+// registerpoint_clear - clear a registerpoint by index,
+// returning true if we found it
+//-------------------------------------------------
+
+bool device_debug::registerpoint_clear(int index)
+{
+ // scan the list to see if we own this registerpoint
+ for (registerpoint **rp = &m_rplist; *rp != NULL; rp = &(*rp)->m_next)
+ if ((*rp)->m_index == index)
+ {
+ registerpoint *deleteme = *rp;
+ *rp = deleteme->m_next;
+ auto_free(m_device.machine(), deleteme);
+ breakpoint_update_flags();
+ return true;
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// registerpoint_clear_all - clear all registerpoints
+//-------------------------------------------------
+
+void device_debug::registerpoint_clear_all()
+{
+ // clear the head until we run out
+ while (m_rplist != NULL)
+ registerpoint_clear(m_rplist->index());
+}
+
+
+//-------------------------------------------------
+// registerpoint_enable - enable/disable a registerpoint
+// by index, returning true if we found it
+//-------------------------------------------------
+
+bool device_debug::registerpoint_enable(int index, bool enable)
+{
+ // scan the list to see if we own this conditionpoint
+ for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->next())
+ if (rp->m_index == index)
+ {
+ rp->m_enabled = enable;
+ breakpoint_update_flags();
+ return true;
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// registerpoint_enable_all - enable/disable all
+// registerpoints
+//-------------------------------------------------
+
+void device_debug::registerpoint_enable_all(bool enable)
+{
+ // apply the enable to all registerpoints we own
+ for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->next())
+ registerpoint_enable(rp->index(), enable);
+}
+
+
+//-------------------------------------------------
// hotspot_track - enable/disable tracking of
// hotspots
//-------------------------------------------------
@@ -2824,6 +2917,18 @@ void device_debug::breakpoint_update_flags()
break;
}
+ if ( ! ( m_flags & DEBUG_FLAG_LIVE_BP ) )
+ {
+ // see if there are any enabled registerpoints
+ for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->m_next)
+ {
+ if (rp->m_enabled)
+ {
+ m_flags |= DEBUG_FLAG_LIVE_BP;
+ }
+ }
+ }
+
// push the flags out globally
debugcpu_private *global = m_device.machine().debugcpu_data;
if (global->livecpu != NULL)
@@ -2855,6 +2960,30 @@ void device_debug::breakpoint_check(offs_t pc)
debug_console_printf(m_device.machine(), "Stopped at breakpoint %X\n", bp->m_index);
break;
}
+
+ // see if we have any matching registerpoints
+ for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->m_next)
+ {
+ if (rp->hit())
+ {
+ // halt in the debugger by default
+ debugcpu_private *global = m_device.machine().debugcpu_data;
+ global->execution_state = EXECUTION_STATE_STOPPED;
+
+ // if we hit, evaluate the action
+ if (rp->m_action)
+ {
+ debug_console_execute_command(m_device.machine(), rp->m_action, 0);
+ }
+
+ // print a notification, unless the action made us go again
+ if (global->execution_state == EXECUTION_STATE_STOPPED)
+ {
+ debug_console_printf(m_device.machine(), "Stopped at registerpoint %X\n", rp->m_index);
+ }
+ break;
+ }
+ }
}
@@ -3257,6 +3386,52 @@ bool device_debug::watchpoint::hit(int type, offs_t address, int size)
//**************************************************************************
+// DEBUG REGISTERPOINT
+//**************************************************************************
+
+//-------------------------------------------------
+// registerpoint - constructor
+//-------------------------------------------------
+
+device_debug::registerpoint::registerpoint(symbol_table &symbols, int index, const char *condition, const char *action)
+ : m_next(NULL),
+ m_index(index),
+ m_enabled(true),
+ m_condition(&symbols, (condition != NULL) ? condition : "1"),
+ m_action((action != NULL) ? action : "")
+{
+}
+
+
+//-------------------------------------------------
+// hit - detect a hit
+//-------------------------------------------------
+
+bool device_debug::registerpoint::hit()
+{
+ // don't hit if disabled
+ if (!m_enabled)
+ return false;
+
+ // must satisfy the condition
+ if (!m_condition.is_empty())
+ {
+ try
+ {
+ return (m_condition.execute() != 0);
+ }
+ catch (expression_error &)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+//**************************************************************************
// TRACER
//**************************************************************************
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 377b93ce790..bd2fc5ec0d4 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -136,6 +136,33 @@ public:
astring m_action; // action
};
+ // registerpoint class
+ class registerpoint
+ {
+ friend class device_debug;
+
+ public:
+ // construction/destruction
+ registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = NULL);
+
+ // getters
+ registerpoint *next() const { return m_next; }
+ int index() const { return m_index; }
+ bool enabled() const { return m_enabled; }
+ const char *condition() const { return m_condition.original_string(); }
+ const char *action() const { return m_action; }
+
+ private:
+ // internals
+ bool hit();
+
+ registerpoint * m_next; // next in the list
+ int m_index; // user reported index
+ UINT8 m_enabled; // enabled?
+ parsed_expression m_condition; // condition
+ astring m_action; // action
+ };
+
public:
// construction/destruction
device_debug(device_t &device);
@@ -200,6 +227,14 @@ public:
bool watchpoint_enable(int index, bool enable = true);
void watchpoint_enable_all(bool enable = true);
+ // registerpoints
+ registerpoint *registerpoint_first() const { return m_rplist; }
+ int registerpoint_set(const char *condition, const char *action = NULL);
+ bool registerpoint_clear(int index);
+ void registerpoint_clear_all();
+ bool registerpoint_enable(int index, bool enable = true);
+ void registerpoint_enable_all(bool enable = true );
+
// hotspots
bool hotspot_tracking_enabled() const { return (m_hotspots != NULL); }
void hotspot_track(int numspots, int threshhold);
@@ -286,6 +321,7 @@ private:
// breakpoints and watchpoints
breakpoint * m_bplist; // list of breakpoints
watchpoint * m_wplist[ADDRESS_SPACES]; // watchpoint lists for each address space
+ registerpoint * m_rplist; // list of registerpoints
// tracing
class tracer
diff --git a/src/emu/debug/debughlp.c b/src/emu/debug/debughlp.c
index cf2eedf51a9..5b3d57ca02b 100644
--- a/src/emu/debug/debughlp.c
+++ b/src/emu/debug/debughlp.c
@@ -66,6 +66,7 @@ static const help_item static_help_list[] =
" Execution\n"
" Breakpoints\n"
" Watchpoints\n"
+ " Registerpoints\n"
" Expressions\n"
" Comments\n"
" Cheats\n"
@@ -163,6 +164,18 @@ static const help_item static_help_list[] =
" hotspot [<cpu>,[<depth>[,<hits>]]] -- attempt to find hotspots\n"
},
{
+ "registerpoints",
+ "\n"
+ "Registerpoint Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " rp[set] {<condition>}[,<action>] -- sets a registerpoint to trigger on <condition>\n"
+ " rpclear [<rpnum>] -- clears a given registerpoint or all if no <rpnum> specified\n"
+ " rpdisable [<rpnum>] -- disabled a given registerpoint or all if no <rpnum> specified\n"
+ " rpenable [<rpnum>] -- enables a given registerpoint or all if no <rpnum> specified\n"
+ " rplist -- lists all the registerpoints\n"
+ },
+ {
"expressions",
"\n"
"Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is "
@@ -1006,6 +1019,90 @@ static const help_item static_help_list[] =
"end up with 1000 or more hits.\n"
},
{
+ "rpset",
+ "\n"
+ " rp[set] {<condition>}[,<action>]]\n"
+ "\n"
+ "Sets a new registerpoint which will be triggered when <condition> is met. The condition must "
+ "be specified between curly braces to prevent the condition from being evaluated as an "
+ "assignment.\n"
+ "\n"
+ "The optional <action> parameter provides a command that is executed whenever the registerpoint "
+ "is hit. Note that you may need to embed the action within braces { } in "
+ "order to prevent commas and semicolons from being interpreted as applying to the rpset command "
+ "itself. Each registerpoint that is set is assigned an index which can be used in other "
+ "registerpoint commands to reference this registerpoint.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "rp {PC==0150}\n"
+ " Set a registerpoint that will halt execution whenever the PC register equals 0x150.\n"
+ "\n"
+ "temp0=0; rp {PC==0150},{temp0++; g}\n"
+ " Set a registerpoint that will increment the variable temp0 whenever the PC register "
+ "equals 0x0150.\n"
+ "\n"
+ "rp {temp0==5}\n"
+ " Set a registerpoint that will halt execution whenever the temp0 variable equals 5.\n"
+ },
+ {
+ "rpclear",
+ "\n"
+ " rpclear [<rpnum>]\n"
+ "\n"
+ "The rpclear command clears a registerpoint. If <rpnum> is specified, only the requested "
+ "registerpoint is cleared, otherwise all registerpoints are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "rpclear 3\n"
+ " Clear registerpoint index 3.\n"
+ "\n"
+ "rpclear\n"
+ " Clear all registerpoints.\n"
+ },
+ {
+ "rpdisable",
+ "\n"
+ " rpdisable [<rpnum>]\n"
+ "\n"
+ "The rpdisable command disables a registerpoint. If <rpnum> is specified, only the requested "
+ "registerpoint is disabled, otherwise all registerpoints are disabled. Note that disabling a "
+ "registerpoint does not delete it, it just temporarily marks the registerpoint as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "rpdisable 3\n"
+ " Disable registerpoint index 3.\n"
+ "\n"
+ "rpdisable\n"
+ " Disable all registerpoints.\n"
+ },
+ {
+ "rpenable",
+ "\n"
+ " rpenable [<rpnum>]\n"
+ "\n"
+ "The rpenable command enables a registerpoint. If <rpnum> is specified, only the requested "
+ "registerpoint is enabled, otherwise all registerpoints are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "rpenable 3\n"
+ " Enable registerpoint index 3.\n"
+ "\n"
+ "rpenable\n"
+ " Enable all registerpoints.\n"
+ },
+ {
+ "rplist",
+ "\n"
+ " rplist\n"
+ "\n"
+ "The rplist command lists all the current registerpoints, along with their index and any "
+ "actions attached to them.\n"
+ },
+ {
"map",
"\n"
" map[{d|i}] <address>\n"