diff options
author | 2013-03-11 21:29:51 +0000 | |
---|---|---|
committer | 2013-03-11 21:29:51 +0000 | |
commit | c03729e963eb8d7a2fc49937ed9a594cbebed41c (patch) | |
tree | e9100399741d881b36c28fcdb9e5e1752f5af646 /src/emu/debug | |
parent | e7e15bca128cdadf20f9d891446008af170a80f4 (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.c | 151 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.c | 175 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.h | 36 | ||||
-rw-r--r-- | src/emu/debug/debughlp.c | 97 |
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" |