summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugcmd.cpp173
-rw-r--r--src/emu/debug/debugcmd.h5
-rw-r--r--src/emu/debug/debugcon.cpp246
-rw-r--r--src/emu/debug/debugcon.h18
-rw-r--r--src/emu/debug/debugcpu.cpp127
-rw-r--r--src/emu/debug/debugcpu.h21
-rw-r--r--src/emu/debug/debughlp.cpp71
-rw-r--r--src/emu/debug/debugvw.cpp4
-rw-r--r--src/emu/debug/dvmemory.cpp67
-rw-r--r--src/emu/debug/dvmemory.h1
-rw-r--r--src/emu/debug/express.cpp16
-rw-r--r--src/emu/debug/express.h9
-rw-r--r--src/emu/debug/points.cpp195
-rw-r--r--src/emu/debug/points.h6
14 files changed, 611 insertions, 348 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index b8de0298432..781ce93e9a5 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -21,6 +21,7 @@
#include "debugger.h"
#include "emuopts.h"
+#include "fileio.h"
#include "natkeyboard.h"
#include "render.h"
#include "screen.h"
@@ -31,6 +32,7 @@
#include <algorithm>
#include <cctype>
#include <fstream>
+#include <sstream>
@@ -232,6 +234,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("gtime", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1));
m_console.register_command("gt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_time, this, _1));
m_console.register_command("gp", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_privilege, this, _1));
+ m_console.register_command("gbt", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, true, _1));
+ m_console.register_command("gbf", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_branch, this, false, _1));
+ m_console.register_command("gni", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_go_next_instruction, this, _1));
m_console.register_command("next", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1));
m_console.register_command("n", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_next, this, _1));
m_console.register_command("focus", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_focus, this, _1));
@@ -240,6 +245,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("suspend", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_suspend, this, _1));
m_console.register_command("resume", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_resume, this, _1));
m_console.register_command("cpulist", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_cpulist, this, _1));
+ m_console.register_command("time", CMDFLAG_NONE, 0, 0, std::bind(&debugger_commands::execute_time, this, _1));
m_console.register_command("comadd", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1));
m_console.register_command("//", CMDFLAG_NONE, 1, 2, std::bind(&debugger_commands::execute_comment_add, this, _1));
@@ -943,53 +949,51 @@ void debugger_commands::execute_print(const std::vector<std::string> &params)
mini_printf - safe printf to a buffer
-------------------------------------------------*/
-int debugger_commands::mini_printf(char *buffer, const char *format, int params, u64 *param)
+bool debugger_commands::mini_printf(std::ostream &stream, std::string_view format, int params, u64 *param)
{
- const char *f = format;
- char *p = buffer;
+ auto f = format.begin();
- /* parse the string looking for % signs */
- for (;;)
+ // parse the string looking for % signs
+ while (f != format.end())
{
char c = *f++;
- if (!c) break;
- /* escape sequences */
+ // escape sequences
if (c == '\\')
{
+ if (f == format.end()) break;
c = *f++;
- if (!c) break;
switch (c)
{
- case '\\': *p++ = c; break;
- case 'n': *p++ = '\n'; break;
+ case '\\': stream << c; break;
+ case 'n': stream << '\n'; break;
default: break;
}
continue;
}
- /* formatting */
+ // formatting
else if (c == '%')
{
int width = 0;
int zerofill = 0;
- /* parse out the width */
- for (;;)
+ // parse out the width
+ while (f != format.end() && *f >= '0' && *f <= '9')
{
c = *f++;
- if (!c || c < '0' || c > '9') break;
if (c == '0' && width == 0)
zerofill = 1;
width = width * 10 + (c - '0');
}
- if (!c) break;
+ if (f == format.end()) break;
- /* get the format */
+ // get the format
+ c = *f++;
switch (c)
{
case '%':
- *p++ = c;
+ stream << c;
break;
case 'X':
@@ -997,13 +1001,13 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
if (params == 0)
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
if (u32(*param >> 32) != 0)
- p += sprintf(p, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, u32(*param >> 32));
+ util::stream_format(stream, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, u32(*param >> 32));
else if (width > 8)
- p += sprintf(p, zerofill ? "%0*X" : "%*X", width - 8, 0);
- p += sprintf(p, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, u32(*param));
+ util::stream_format(stream, zerofill ? "%0*X" : "%*X", width - 8, 0);
+ util::stream_format(stream, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, u32(*param));
param++;
params--;
break;
@@ -1013,23 +1017,23 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
if (params == 0)
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
if (u32(*param >> 60) != 0)
{
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 20) ? 1 : width - 20, u32(*param >> 60));
- p += sprintf(p, "%0*o", 10, u32(BIT(*param, 30, 30)));
+ util::stream_format(stream, zerofill ? "%0*o" : "%*o", (width <= 20) ? 1 : width - 20, u32(*param >> 60));
+ util::stream_format(stream, "%0*o", 10, u32(BIT(*param, 30, 30)));
}
else
{
if (width > 20)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 20, 0);
+ util::stream_format(stream, zerofill ? "%0*o" : "%*o", width - 20, 0);
if (u32(BIT(*param, 30, 30)) != 0)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width <= 10) ? 1 : width - 10, u32(BIT(*param, 30, 30)));
+ util::stream_format(stream, zerofill ? "%0*o" : "%*o", (width <= 10) ? 1 : width - 10, u32(BIT(*param, 30, 30)));
else if (width > 10)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 10, 0);
+ util::stream_format(stream, zerofill ? "%0*o" : "%*o", width - 10, 0);
}
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width < 10) ? width : 10, u32(BIT(*param, 0, 30)));
+ util::stream_format(stream, zerofill ? "%0*o" : "%*o", (width < 10) ? width : 10, u32(BIT(*param, 0, 30)));
param++;
params--;
break;
@@ -1039,9 +1043,9 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
if (params == 0)
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, zerofill ? "%0*d" : "%*d", width, u32(*param));
+ util::stream_format(stream, zerofill ? "%0*d" : "%*d", width, u32(*param));
param++;
params--;
break;
@@ -1050,9 +1054,9 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
if (params == 0)
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, "%c", char(*param));
+ stream << char(*param);
param++;
params--;
break;
@@ -1060,14 +1064,12 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
}
}
- /* normal stuff */
+ // normal stuff
else
- *p++ = c;
+ stream << c;
}
- /* NULL-terminate and exit */
- *p = 0;
- return 1;
+ return true;
}
@@ -1115,9 +1117,9 @@ void debugger_commands::execute_printf(const std::vector<std::string> &params)
return;
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_console.printf("%s\n", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ m_console.printf("%s\n", std::move(buffer).str());
}
@@ -1134,9 +1136,9 @@ void debugger_commands::execute_logerror(const std::vector<std::string> &params)
return;
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_machine.logerror("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ m_machine.logerror("%s", std::move(buffer).str());
}
@@ -1153,9 +1155,9 @@ void debugger_commands::execute_tracelog(const std::vector<std::string> &params)
return;
/* then do a printf */
- char buffer[1024];
- if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1]))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str().c_str());
}
@@ -1189,9 +1191,9 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
}
// then do a printf
- char buffer[1024];
- if (mini_printf(buffer, format.str().c_str(), params.size(), values))
- m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer);
+ std::ostringstream buffer;
+ if (mini_printf(buffer, format.str(), params.size(), values))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str().c_str());
}
@@ -1358,6 +1360,62 @@ void debugger_commands::execute_go_privilege(const std::vector<std::string> &par
m_console.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string());
}
+
+/*-------------------------------------------------
+ execute_go_branch - execute gbt or gbf command
+-------------------------------------------------*/
+
+void debugger_commands::execute_go_branch(bool sense, const std::vector<std::string> &params)
+{
+ parsed_expression condition(m_console.visible_symtable());
+ if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
+ return;
+
+ m_console.get_visible_cpu()->debug()->go_branch(sense, (condition.is_empty()) ? "1" : condition.original_string());
+}
+
+
+/*-------------------------------------------------
+ execute_go_next_instruction - execute gni command
+-------------------------------------------------*/
+
+void debugger_commands::execute_go_next_instruction(const std::vector<std::string> &params)
+{
+ u64 count = 1;
+ static constexpr u64 MAX_COUNT = 512;
+
+ // if we have a parameter, use it instead */
+ if (params.size() > 0 && !validate_number_parameter(params[0], count))
+ return;
+ if (count == 0)
+ return;
+ if (count > MAX_COUNT)
+ {
+ m_console.printf("Too many instructions (must be %d or fewer)\n", MAX_COUNT);
+ return;
+ }
+
+ device_state_interface *stateintf;
+ device_t *cpu = m_machine.debugger().console().get_visible_cpu();
+ if (!cpu->interface(stateintf))
+ {
+ m_console.printf("No state interface available for %s\n", cpu->name());
+ return;
+ }
+ u32 pc = stateintf->pcbase();
+
+ debug_disasm_buffer buffer(*cpu);
+ while (count-- != 0)
+ {
+ // disassemble the current instruction and get the length
+ u32 result = buffer.disassemble_info(pc);
+ pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK);
+ }
+
+ cpu->debug()->go(pc);
+}
+
+
/*-------------------------------------------------
execute_next - execute the next command
-------------------------------------------------*/
@@ -1620,6 +1678,15 @@ void debugger_commands::execute_cpulist(const std::vector<std::string> &params)
}
}
+//-------------------------------------------------
+// execute_time - execute the time command
+//-------------------------------------------------
+
+void debugger_commands::execute_time(const std::vector<std::string> &params)
+{
+ m_console.printf("%s\n", m_machine.time().as_string());
+}
+
/*-------------------------------------------------
execute_comment - add a comment to a line
-------------------------------------------------*/
@@ -2191,8 +2258,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
void debugger_commands::execute_statesave(const std::vector<std::string> &params)
{
- const std::string &filename(params[0]);
- m_machine.immediate_save(filename.c_str());
+ m_machine.immediate_save(params[0]);
m_console.printf("State save attempted. Please refer to window message popup for results.\n");
}
@@ -2203,8 +2269,7 @@ void debugger_commands::execute_statesave(const std::vector<std::string> &params
void debugger_commands::execute_stateload(const std::vector<std::string> &params)
{
- const std::string &filename(params[0]);
- m_machine.immediate_load(filename.c_str());
+ m_machine.immediate_load(params[0]);
// clear all PC & memory tracks
for (device_t &device : device_enumerator(m_machine.root_device()))
@@ -4259,7 +4324,7 @@ void debugger_commands::execute_unmount(const std::vector<std::string> &params)
void debugger_commands::execute_input(const std::vector<std::string> &params)
{
- m_machine.natkeyboard().post_coded(params[0].c_str());
+ m_machine.natkeyboard().post_coded(params[0]);
}
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index fd0bcea673a..f93276d5d8d 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -99,7 +99,7 @@ private:
u64 global_get(global_entry *global);
void global_set(global_entry *global, u64 value);
- int mini_printf(char *buffer, const char *format, int params, u64 *param);
+ bool mini_printf(std::ostream &stream, std::string_view format, int params, u64 *param);
template <typename T>
void execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message);
@@ -121,6 +121,8 @@ private:
void execute_go_exception(const std::vector<std::string> &params);
void execute_go_time(const std::vector<std::string> &params);
void execute_go_privilege(const std::vector<std::string> &params);
+ void execute_go_branch(bool sense, const std::vector<std::string> &params);
+ void execute_go_next_instruction(const std::vector<std::string> &params);
void execute_focus(const std::vector<std::string> &params);
void execute_ignore(const std::vector<std::string> &params);
void execute_observe(const std::vector<std::string> &params);
@@ -128,6 +130,7 @@ private:
void execute_resume(const std::vector<std::string> &params);
void execute_next(const std::vector<std::string> &params);
void execute_cpulist(const std::vector<std::string> &params);
+ void execute_time(const std::vector<std::string> &params);
void execute_comment_add(const std::vector<std::string> &params);
void execute_comment_del(const std::vector<std::string> &params);
void execute_comment_save(const std::vector<std::string> &params);
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index 32a4888c285..508c2377f54 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -16,6 +16,7 @@
#include "textbuf.h"
#include "debugger.h"
+#include "fileio.h"
#include "corestr.h"
@@ -86,10 +87,14 @@ debugger_console::debugger_console(running_machine &machine)
}
}
+debugger_console::~debugger_console()
+{
+}
-/*-------------------------------------------------
- exit - frees the console system
--------------------------------------------------*/
+
+//-------------------------------------------------
+// exit - frees the console system
+//-------------------------------------------------
void debugger_console::exit()
{
@@ -114,41 +119,39 @@ void debugger_console::exit()
inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const debug_command &b) const
{
- return core_stricmp(a.command.c_str(), b.command.c_str()) < 0;
+ return a.command < b.command;
}
inline bool debugger_console::debug_command::compare::operator()(const char *a, const debug_command &b) const
{
- return core_stricmp(a, b.command.c_str()) < 0;
+ return strcmp(a, b.command.c_str()) < 0;
}
inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const char *b) const
{
- return core_stricmp(a.command.c_str(), b) < 0;
+ return strcmp(a.command.c_str(), b) < 0;
}
-debugger_console::debug_command::debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler)
+debugger_console::debug_command::debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler)
: command(_command), params(nullptr), help(nullptr), handler(std::move(_handler)), flags(_flags), minparams(_minparams), maxparams(_maxparams)
{
}
-/*------------------------------------------------------------
- execute_help_custom - execute the helpcustom command
-------------------------------------------------------------*/
+//------------------------------------------------------------
+// execute_help_custom - execute the helpcustom command
+//------------------------------------------------------------
void debugger_console::execute_help_custom(const std::vector<std::string> &params)
{
- char buf[64];
for (const debug_command &cmd : m_commandlist)
{
if (cmd.flags & CMDFLAG_CUSTOM_HELP)
{
- snprintf(buf, 63, "%s help", cmd.command.c_str());
- buf[63] = 0;
- char *temp_params[1] = { buf };
- internal_execute_command(true, 1, &temp_params[0]);
+ std::string buf = cmd.command + " help";
+ std::vector<std::string_view> temp_params = { buf };
+ internal_execute_command(true, temp_params);
}
}
}
@@ -202,159 +205,145 @@ symbol_table &debugger_console::visible_symtable()
-/*-------------------------------------------------
- trim_parameter - executes a
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// trim_parameter - trim spaces and quotes around
+// a command parameter
+//-------------------------------------------------
-void debugger_console::trim_parameter(char **paramptr, bool keep_quotes)
+std::string_view debugger_console::trim_parameter(std::string_view param, bool keep_quotes)
{
- char *param = *paramptr;
- size_t len = strlen(param);
+ std::string_view::size_type len = param.length();
bool repeat;
- /* loop until all adornments are gone */
+ // loop until all adornments are gone
do
{
repeat = false;
- /* check for begin/end quotes */
+ // check for begin/end quotes
if (len >= 2 && param[0] == '"' && param[len - 1] == '"')
{
if (!keep_quotes)
{
- param[len - 1] = 0;
- param++;
+ param = param.substr(1, len - 2);
len -= 2;
}
}
- /* check for start/end braces */
+ // check for start/end braces
else if (len >= 2 && param[0] == '{' && param[len - 1] == '}')
{
- param[len - 1] = 0;
- param++;
+ param = param.substr(1, len - 2);
len -= 2;
repeat = true;
}
- /* check for leading spaces */
+ // check for leading spaces
else if (len >= 1 && param[0] == ' ')
{
- param++;
+ param.remove_prefix(1);
len--;
repeat = true;
}
- /* check for trailing spaces */
+ // check for trailing spaces
else if (len >= 1 && param[len - 1] == ' ')
{
- param[len - 1] = 0;
+ param.remove_suffix(1);
len--;
repeat = true;
}
} while (repeat);
- *paramptr = param;
+ return param;
}
-/*-------------------------------------------------
- internal_execute_command - executes a
- command
--------------------------------------------------*/
+//-------------------------------------------------
+// internal_execute_command - executes a
+// command
+//-------------------------------------------------
-CMDERR debugger_console::internal_execute_command(bool execute, int params, char **param)
+CMDERR debugger_console::internal_execute_command(bool execute, std::vector<std::string_view> &params)
{
// no params is an error
- if (params == 0)
+ if (params.empty())
return CMDERR::none();
// the first parameter has the command and the real first parameter; separate them
- char *p, *command;
- for (p = param[0]; *p && isspace(u8(*p)); p++) { }
- for (command = p; *p && !isspace(u8(*p)); p++) { }
- if (*p != 0)
- {
- *p++ = 0;
- for ( ; *p && isspace(u8(*p)); p++) { }
- if (*p != 0)
- param[0] = p;
- else
- params = 0;
- }
+ std::string_view command_param = params[0];
+ std::string_view::size_type pos = 0;
+ while (pos < command_param.length() && !isspace(u8(command_param[pos])))
+ pos++;
+ const std::string command(strmakelower(command_param.substr(0, pos)));
+ while (pos < command_param.length() && isspace(u8(command_param[pos])))
+ pos++;
+ if (pos == command_param.length() && params.size() == 1)
+ params.clear();
else
- {
- params = 0;
- param[0] = nullptr;
- }
+ params[0].remove_prefix(pos);
// search the command list
- size_t const len = strlen(command);
- auto const found = m_commandlist.lower_bound(command);
+ auto const found = m_commandlist.lower_bound(command.c_str());
// error if not found
- if ((m_commandlist.end() == found) || core_strnicmp(command, found->command.c_str(), len))
+ if (m_commandlist.end() == found || std::string_view(command) != std::string_view(found->command).substr(0, command.length()))
return CMDERR::unknown_command(0);
- if (found->command.length() > len)
+ if (found->command.length() > command.length())
{
auto const next = std::next(found);
- if ((m_commandlist.end() != next) && !core_strnicmp(command, next->command.c_str(), len))
+ if (m_commandlist.end() != next && std::string_view(command) == std::string_view(next->command).substr(0, command.length()))
return CMDERR::ambiguous_command(0);
}
- // NUL-terminate and trim space around all the parameters
- for (int i = 1; i < params; i++)
- *param[i]++ = 0;
-
// now go back and trim quotes and braces and any spaces they reveal
- for (int i = 0; i < params; i++)
- trim_parameter(&param[i], found->flags & CMDFLAG_KEEP_QUOTES);
+ for (std::string_view &param : params)
+ param = trim_parameter(param, found->flags & CMDFLAG_KEEP_QUOTES);
// see if we have the right number of parameters
- if (params < found->minparams)
+ if (params.size() < found->minparams)
return CMDERR::not_enough_params(0);
- if (params > found->maxparams)
+ if (params.size() > found->maxparams)
return CMDERR::too_many_params(0);
// execute the handler
if (execute)
{
- std::vector<std::string> params_vec(param, param + params);
+ std::vector<std::string> params_vec(params.begin(), params.end());
found->handler(params_vec);
}
return CMDERR::none();
}
-/*-------------------------------------------------
- internal_parse_command - parses a command
- and either executes or just validates it
--------------------------------------------------*/
+//-------------------------------------------------
+// internal_parse_command - parses a command
+// and either executes or just validates it
+//-------------------------------------------------
-CMDERR debugger_console::internal_parse_command(const std::string &original_command, bool execute)
+CMDERR debugger_console::internal_parse_command(std::string_view command, bool execute)
{
- char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH];
- char *params[MAX_COMMAND_PARAMS] = { nullptr };
- char *command_start;
- char *p, c = 0;
+ std::string_view::size_type pos = 0;
+ std::string_view::size_type len = command.length();
- /* make a copy of the command */
- strcpy(command, original_command.c_str());
-
- /* loop over all semicolon-separated stuff */
- for (p = command; *p != 0; )
+ while (pos < len)
{
- int paramcount = 0, parendex = 0;
+ std::string parens;
+ std::vector<std::string_view> params;
bool foundend = false, instring = false, isexpr = false;
- /* find a semicolon or the end */
- for (params[paramcount++] = p; !foundend; p++)
+ // skip leading spaces
+ while (pos < len && isspace(u8(command[pos])))
+ pos++;
+ std::string_view::size_type startpos = pos;
+
+ // find a semicolon or the end
+ for (params.push_back(command.substr(pos)); !foundend && pos < len; pos++)
{
- c = *p;
+ char c = command[pos];
if (instring)
{
- if (c == '"' && p[-1] != '\\')
+ if (c == '"' && command[pos - 1] != '\\')
instring = false;
}
else
@@ -364,47 +353,42 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
case '"': instring = true; break;
case '(':
case '[':
- case '{': parens[parendex++] = c; break;
- case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break;
- case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break;
- case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break;
- case ',': if (parendex == 0) params[paramcount++] = p; break;
- case ';': if (parendex == 0) foundend = true; break;
- case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break;
- case '+': if (parendex == 0 && paramcount == 1 && p[1] == '+') isexpr = true; *p = c; break;
- case '=': if (parendex == 0 && paramcount == 1) isexpr = true; *p = c; break;
- case 0: foundend = true; break;
- default: *p = c; break;
+ case '{': parens.push_back(c); break;
+ case ')': if (parens.empty() || parens.back() != '(') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case ']': if (parens.empty() || parens.back() != '[') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case '}': if (parens.empty() || parens.back() != '{') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break;
+ case ',': if (parens.empty()) { params.back().remove_suffix(len - pos); params.push_back(command.substr(pos + 1)); } break;
+ case ';': if (parens.empty()) { params.back().remove_suffix(len - pos); foundend = true; } break;
+ case '-': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '-') isexpr = true; break;
+ case '+': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '+') isexpr = true; break;
+ case '=': if (parens.empty() && params.size() == 1) isexpr = true; break;
+ default: break;
}
}
}
- /* check for unbalanced parentheses or quotes */
+ // check for unbalanced parentheses or quotes
if (instring)
- return CMDERR::unbalanced_quotes(p - command);
- if (parendex != 0)
- return CMDERR::unbalanced_parens(p - command);
+ return CMDERR::unbalanced_quotes(pos);
+ if (!parens.empty())
+ return CMDERR::unbalanced_parens(pos);
- /* NULL-terminate if we ended in a semicolon */
- p--;
- if (c == ';') *p++ = 0;
+ // process the command
+ std::string_view command_or_expr = params[0];
- /* process the command */
- command_start = params[0];
-
- /* allow for "do" commands */
- if (tolower(u8(command_start[0])) == 'd' && tolower(u8(command_start[1])) == 'o' && isspace(u8(command_start[2])))
+ // allow for "do" commands
+ if (command_or_expr.length() > 3 && tolower(u8(command_or_expr[0])) == 'd' && tolower(u8(command_or_expr[1])) == 'o' && isspace(u8(command_or_expr[2])))
{
isexpr = true;
- command_start += 3;
+ command_or_expr.remove_prefix(3);
}
- /* if it smells like an assignment expression, treat it as such */
- if (isexpr && paramcount == 1)
+ // if it smells like an assignment expression, treat it as such
+ if (isexpr && params.size() == 1)
{
try
{
- parsed_expression(visible_symtable(), command_start).execute();
+ parsed_expression(visible_symtable(), command_or_expr).execute();
}
catch (expression_error &err)
{
@@ -413,29 +397,29 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
}
else
{
- const CMDERR result = internal_execute_command(execute, paramcount, &params[0]);
+ const CMDERR result = internal_execute_command(execute, params);
if (result.error_class() != CMDERR::NONE)
- return CMDERR(result.error_class(), command_start - command);
+ return CMDERR(result.error_class(), startpos);
}
}
return CMDERR::none();
}
-/*-------------------------------------------------
- execute_command - execute a command string
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_command - execute a command string
+//-------------------------------------------------
-CMDERR debugger_console::execute_command(const std::string &command, bool echo)
+CMDERR debugger_console::execute_command(std::string_view command, bool echo)
{
- /* echo if requested */
+ // echo if requested
if (echo)
printf(">%s\n", command);
- /* parse and execute */
+ // parse and execute
const CMDERR result = internal_parse_command(command, true);
- /* display errors */
+ // display errors
if (result.error_class() != CMDERR::NONE)
{
if (!echo)
@@ -444,7 +428,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
printf("%s\n", cmderr_to_string(result));
}
- /* update all views */
+ // update all views
if (echo)
{
m_machine.debug_view().update_all();
@@ -454,11 +438,11 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
}
-/*-------------------------------------------------
- validate_command - validate a command string
--------------------------------------------------*/
+//-------------------------------------------------
+// validate_command - validate a command string
+//-------------------------------------------------
-CMDERR debugger_console::validate_command(const char *command)
+CMDERR debugger_console::validate_command(std::string_view command)
{
return internal_parse_command(command, false);
}
@@ -468,7 +452,7 @@ CMDERR debugger_console::validate_command(const char *command)
register_command - register a command handler
-------------------------------------------------*/
-void debugger_console::register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler)
+void debugger_console::register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler)
{
if (m_machine.phase() != machine_phase::INIT)
throw emu_fatalerror("Can only call debugger_console::register_command() at init time!");
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 5271b0e5ae5..974a43e656a 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -23,8 +23,7 @@
CONSTANTS
***************************************************************************/
-#define MAX_COMMAND_LENGTH 4096
-#define MAX_COMMAND_PARAMS 128
+constexpr int MAX_COMMAND_PARAMS = 128;
// flags for command parsing
constexpr u32 CMDFLAG_NONE = 0x0000;
@@ -79,11 +78,12 @@ class debugger_console
{
public:
debugger_console(running_machine &machine);
+ ~debugger_console();
// command handling
- CMDERR execute_command(const std::string &command, bool echo);
- CMDERR validate_command(const char *command);
- void register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler);
+ CMDERR execute_command(std::string_view command, bool echo);
+ CMDERR validate_command(std::string_view command);
+ void register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler);
void source_script(const char *file);
void process_source_file();
@@ -122,16 +122,16 @@ private:
void execute_help_custom(const std::vector<std::string> &params);
void execute_condump(const std::vector<std::string>& params);
- void trim_parameter(char **paramptr, bool keep_quotes);
- CMDERR internal_execute_command(bool execute, int params, char **param);
- CMDERR internal_parse_command(const std::string &original_command, bool execute);
+ [[nodiscard]] static std::string_view trim_parameter(std::string_view param, bool keep_quotes);
+ CMDERR internal_execute_command(bool execute, std::vector<std::string_view> &params);
+ CMDERR internal_parse_command(std::string_view command, bool execute);
void print_core(std::string_view text); // core text output
void print_core_wrap(std::string_view text, int wrapcol); // core text output
struct debug_command
{
- debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler);
+ debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler);
struct compare
{
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 403d0b104ee..820d9e72688 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -19,6 +19,7 @@
#include "debugger.h"
#include "emuopts.h"
+#include "fileio.h"
#include "screen.h"
#include "uiinput.h"
@@ -426,6 +427,7 @@ device_debug::device_debug(device_t &device)
, m_instrhook(nullptr)
, m_stepaddr(0)
, m_stepsleft(0)
+ , m_delay_steps(0)
, m_stopaddr(0)
, m_stoptime(attotime::zero)
, m_stopirq(0)
@@ -458,14 +460,14 @@ device_debug::device_debug(device_t &device)
// set up notifiers and clear the passthrough handlers
if (m_memory) {
int count = m_memory->max_space_count();
- m_phw.resize(count, nullptr);
+ m_phw.resize(count);
for (int i=0; i != count; i++)
if (m_memory->has_space(i)) {
address_space &space = m_memory->space(i);
- m_notifiers.push_back(space.add_change_notifier([this, &space](read_or_write mode) { reinstall(space, mode); }));
+ m_notifiers.emplace_back(space.add_change_notifier([this, &space] (read_or_write mode) { reinstall(space, mode); }));
}
else
- m_notifiers.push_back(-1);
+ m_notifiers.emplace_back();
}
// set up state-related stuff
@@ -562,15 +564,14 @@ void device_debug::reinstall(address_space &space, read_or_write mode)
int id = space.spacenum();
if (u32(mode) & u32(read_or_write::WRITE))
{
- if (m_phw[id])
- m_phw[id]->remove();
+ m_phw[id].remove();
if (m_track_mem)
switch (space.data_width())
{
- case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, m_phw[id]); break;
- case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space](offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, m_phw[id]); break;
+ case 8: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u8 &data, u8 ) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 16: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u16 &data, u16) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 32: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u32 &data, u32) { write_tracking(space, address, data); }, &m_phw[id]); break;
+ case 64: m_phw[id] = space.install_write_tap(0, space.addrmask(), "track_mem", [this, &space] (offs_t address, u64 &data, u64) { write_tracking(space, address, data); }, &m_phw[id]); break;
}
}
}
@@ -688,11 +689,11 @@ void device_debug::privilege_hook()
if ((m_flags & DEBUG_FLAG_STOP_PRIVILEGE) != 0)
{
bool matched = true;
- if (m_privilege_condition && !m_privilege_condition->is_empty())
+ if (m_stop_condition && !m_stop_condition->is_empty())
{
try
{
- matched = m_privilege_condition->execute();
+ matched = m_stop_condition->execute();
}
catch (expression_error &)
{
@@ -750,19 +751,53 @@ void device_debug::instruction_hook(offs_t curpc)
// handle single stepping
if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_STEPPING_ANY) != 0)
{
+ bool do_step = true;
+ if ((m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) != 0)
+ {
+ if (curpc == m_stepaddr)
+ {
+ if ((~m_flags & (DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0)
+ {
+ debugcpu.set_execution_stopped();
+ do_step = false;
+ }
+
+ // reset the breakpoint
+ m_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
+ m_delay_steps = 0;
+ }
+ else if (m_delay_steps != 0)
+ {
+ m_delay_steps--;
+ if (m_delay_steps == 0)
+ {
+ // branch taken or subroutine entered (TODO: interrupt acknowledgment or interleaved multithreading can falsely trigger this)
+ if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0)
+ {
+ debugcpu.set_execution_stopped();
+ do_step = false;
+ }
+ if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) != 0)
+ do_step = false;
+ m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS;
+ }
+ }
+ else
+ do_step = false;
+ }
+
// is this an actual step?
- if (m_stepaddr == ~0 || curpc == m_stepaddr)
+ if (do_step)
{
- // decrement the count and reset the breakpoint
+ // decrement the count
m_stepsleft--;
- m_stepaddr = ~0;
// if we hit 0, stop
if (m_stepsleft == 0)
debugcpu.set_execution_stopped();
// update every 100 steps until we are within 200 of the end
- else if ((m_flags & DEBUG_FLAG_STEPPING_OUT) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0))
+ else if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0))
{
machine.debug_view().update_all();
machine.debug_view().flush_osd_updates();
@@ -849,7 +884,7 @@ void device_debug::instruction_hook(offs_t curpc)
}
// handle step out/over on the instruction we are about to execute
- if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT)) != 0 && m_stepaddr == ~0)
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0 && (m_flags & (DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS)) == 0)
prepare_for_step_overout(m_state->pcbase());
// no longer in debugger code
@@ -928,7 +963,7 @@ void device_debug::single_step(int numsteps)
m_device.machine().rewind_capture();
m_stepsleft = numsteps;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING;
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -945,7 +980,7 @@ void device_debug::single_step_over(int numsteps)
m_device.machine().rewind_capture();
m_stepsleft = numsteps;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING_OVER;
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -961,8 +996,9 @@ void device_debug::single_step_out()
assert(m_exec != nullptr);
m_device.machine().rewind_capture();
+ m_stop_condition.reset();
m_stepsleft = 100;
- m_stepaddr = ~0;
+ m_delay_steps = 0;
m_flags |= DEBUG_FLAG_STEPPING_OUT;
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -1060,13 +1096,30 @@ void device_debug::go_privilege(const char *condition)
{
assert(m_exec != nullptr);
m_device.machine().rewind_invalidate();
- m_privilege_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
+ m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
m_flags |= DEBUG_FLAG_STOP_PRIVILEGE;
m_device.machine().debugger().cpu().set_execution_running();
}
//-------------------------------------------------
+// go_branch - execute until branch taken or
+// not taken
+//-------------------------------------------------
+
+void device_debug::go_branch(bool sense, const char *condition)
+{
+ assert(m_exec != nullptr);
+ m_device.machine().rewind_invalidate();
+ m_stop_condition = std::make_unique<parsed_expression>(*m_symtable, condition);
+ m_stepsleft = 100;
+ m_delay_steps = 0;
+ m_flags |= sense ? DEBUG_FLAG_STEPPING_BRANCH_TRUE : DEBUG_FLAG_STEPPING_BRANCH_FALSE;
+ m_device.machine().debugger().cpu().set_execution_running();
+}
+
+
+//-------------------------------------------------
// halt_on_next_instruction_impl - halt in the
// debugger on the next instruction, internal
// implementation which is necessary solely due
@@ -1385,7 +1438,6 @@ void device_debug::set_track_pc(bool value)
// track_pc_visited - returns a boolean stating
// if this PC has been visited or not. CRC32 is
// done in this function on currently active CPU.
-// TODO: Take a CPU context as input
//-------------------------------------------------
bool device_debug::track_pc_visited(offs_t pc) const
@@ -1399,7 +1451,6 @@ bool device_debug::track_pc_visited(offs_t pc) const
//-------------------------------------------------
// set_track_pc_visited - set this pc as visited.
-// TODO: Take a CPU context as input
//-------------------------------------------------
void device_debug::set_track_pc_visited(offs_t pc)
@@ -1625,12 +1676,32 @@ void device_debug::prepare_for_step_overout(offs_t pc)
// disassemble the current instruction and get the flags
u32 dasmresult = buffer.disassemble_info(pc);
+ if ((dasmresult & util::disasm_interface::SUPPORTED) == 0)
+ return;
+
+ bool step_out = (m_flags & DEBUG_FLAG_STEPPING_OUT) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) != 0;
+ bool test_cond = (dasmresult & util::disasm_interface::STEP_COND) != 0 && ((m_flags & (DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0 || step_out);
+ if (test_cond && m_stop_condition && !m_stop_condition->is_empty())
+ {
+ try
+ {
+ test_cond = m_stop_condition->execute();
+ }
+ catch (expression_error &)
+ {
+ test_cond = false;
+ }
+ }
// if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction
- if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
+ // (TODO: this completely fails for subroutines that consume inline operands or use alternate returns)
+ if ((dasmresult & util::disasm_interface::STEP_OVER) != 0 || test_cond)
{
int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT;
pc = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK);
+ m_delay_steps = extraskip + 1;
+ if (m_stepsleft < m_delay_steps)
+ m_stepsleft = m_delay_steps;
// if we need to skip additional instructions, advance as requested
while (extraskip-- > 0) {
@@ -1638,13 +1709,17 @@ void device_debug::prepare_for_step_overout(offs_t pc)
pc = buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK);
}
m_stepaddr = pc;
+ if ((dasmresult & util::disasm_interface::STEP_OVER) != 0)
+ m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS;
+ if (test_cond)
+ m_flags |= DEBUG_FLAG_TEST_IN_PROGRESS;
}
// if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number
- // (TODO: this doesn't work with conditional return instructions)
- if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0)
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE)) != 0)
{
- if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) == 0)
+ // make sure to also reset the number of steps for conditionals that may be single-instruction loops
+ if (test_cond || !step_out)
m_stepsleft = 100;
else
{
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 9e3d23d8d7f..d9fc3f64eae 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -82,6 +82,7 @@ public:
void go_exception(int exception, const char *condition);
void go_milliseconds(u64 milliseconds);
void go_privilege(const char *condition);
+ void go_branch(bool sense, const char *condition);
void go_next_device();
template <typename Format, typename... Params>
@@ -184,15 +185,16 @@ private:
debug_instruction_hook_func m_instrhook; // per-instruction callback hook
// stepping information
- offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER
+ offs_t m_stepaddr; // step target address for DEBUG_FLAG_STEPPING_OVER or DEBUG_FLAG_STEPPING_BRANCH
int m_stepsleft; // number of steps left until done
+ int m_delay_steps; // number of steps until target address check
// execution information
offs_t m_stopaddr; // stop address for DEBUG_FLAG_STOP_PC
attotime m_stoptime; // stop time for DEBUG_FLAG_STOP_TIME
int m_stopirq; // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT
int m_stopexception; // stop exception number for DEBUG_FLAG_STOP_EXCEPTION
- std::unique_ptr<parsed_expression> m_privilege_condition; // expression to evaluate on privilege change
+ std::unique_ptr<parsed_expression> m_stop_condition; // expression to evaluate on privilege change
std::unique_ptr<parsed_expression> m_exception_condition; // expression to evaluate on exception hit
attotime m_endexectime; // ending time of the current execution
u64 m_total_cycles; // current total cycles
@@ -239,10 +241,10 @@ private:
// (0 = not tracing over,
// ~0 = not currently tracing over)
};
- std::unique_ptr<tracer> m_trace; // tracer state
+ std::unique_ptr<tracer> m_trace; // tracer state
- std::vector<memory_passthrough_handler *> m_phw; // passthrough handler reference for each space, write mode
- std::vector<int> m_notifiers; // notifiers for each space
+ std::vector<memory_passthrough_handler> m_phw; // passthrough handler reference for each space, write mode
+ std::vector<util::notifier_subscription> m_notifiers; // notifiers for each space
// pc tracking
class dasm_pc_tag
@@ -322,12 +324,17 @@ private:
static constexpr u32 DEBUG_FLAG_SUSPENDED = 0x00004000; // CPU currently suspended
static constexpr u32 DEBUG_FLAG_LIVE_BP = 0x00010000; // there are live breakpoints for this CPU
static constexpr u32 DEBUG_FLAG_STOP_PRIVILEGE = 0x00020000; // run until execution level changes
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_TRUE = 0x0040000; // run until true branch
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH_FALSE = 0x0080000; // run until false branch
+ static constexpr u32 DEBUG_FLAG_CALL_IN_PROGRESS = 0x01000000; // CPU is in the middle of a subroutine call
+ static constexpr u32 DEBUG_FLAG_TEST_IN_PROGRESS = 0x02000000; // CPU is performing a conditional test and branch
- static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT;
+ static constexpr u32 DEBUG_FLAG_STEPPING_BRANCH = DEBUG_FLAG_STEPPING_BRANCH_TRUE | DEBUG_FLAG_STEPPING_BRANCH_FALSE;
+ static constexpr u32 DEBUG_FLAG_STEPPING_ANY = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH;
static constexpr u32 DEBUG_FLAG_TRACING_ANY = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER;
static constexpr u32 DEBUG_FLAG_TRANSIENT = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC |
DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK |
- DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE;
+ DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PRIVILEGE | DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS;
};
//**************************************************************************
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index 87bf8f0f18f..a62704c5472 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -81,6 +81,7 @@ const help_item f_static_help_list[] =
" stateload[sl] <filename> -- load a state file for the current driver\n"
" snap [<filename>] -- save a screen snapshot.\n"
" source <filename> -- reads commands from <filename> and executes them one by one\n"
+ " time -- prints current machine time to the console\n"
" cls -- clears the console text buffer\n"
" quit -- exits MAME and the debugger\n"
},
@@ -132,6 +133,9 @@ const help_item f_static_help_list[] =
" o[ver] [<count>=1] -- single steps over <count> instructions (F10)\n"
" out -- single steps until the current subroutine/exception handler is exited (Shift-F11)\n"
" g[o] [<address>] -- resumes execution, sets temp breakpoint at <address> (F5)\n"
+ " gbf [<condition>] -- resumes execution until next false branch\n"
+ " gbt [<condition>] -- resumes execution until next true branch\n"
+ " gn[i] [<count>] -- resumes execution, sets temp breakpoint <count> instructions ahead\n"
" ge[x] [<exception>[,<condition>]] -- resumes execution, setting temp breakpoint if <exception> is raised\n"
" gi[nt] [<irqline>] -- resumes execution, setting temp breakpoint if <irqline> is taken (F7)\n"
" gt[ime] <milliseconds> -- resumes execution until the given delay has elapsed\n"
@@ -578,6 +582,13 @@ const help_item f_static_help_list[] =
" Reads in debugger commands from break_and_trace.cmd and executes them.\n"
},
{
+ "time",
+ "\n"
+ " time\n"
+ "\n"
+ "The time command prints the current machine time to the console.\n"
+ },
+ {
"quit",
"\n"
" quit\n"
@@ -920,6 +931,66 @@ const help_item f_static_help_list[] =
" Resume execution, stopping at address 1234 unless something else stops us first.\n"
},
{
+ "gbf",
+ "\n"
+ " gbf [<condition>]\n"
+ "\n"
+ "The gbf command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a conditional branch or skip instruction tests false and falls through to the "
+ "next instruction, or the instruction that follows its delay slot. The optional conditional "
+ "expression, if provided, will be evaluated at (not after) each conditional branch; execution "
+ "will not halt regardless of consequent program flow unless its result is true (non-zero).\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gbf\n"
+ " Resume execution until the next break/watchpoint or until the next false branch.\n"
+ "\n"
+ "gbf {pc != 1234}\n"
+ " Resume execution until the next false branch, disregarding the instruction at address 1234.\n"
+ },
+ {
+ "gbt",
+ "\n"
+ " gbt [<condition>]\n"
+ "\n"
+ "The gbt command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a conditional branch or skip instruction tests true and program flow transfers "
+ "to any instruction other than the next one following the delay slot (if any). The optional "
+ "conditional expression, if provided, will be evaluated at (not after) each conditional "
+ "branch; execution will not halt regardless of consequent program flow unless its result is "
+ "true (non-zero).\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gbt\n"
+ " Resume execution until the next break/watchpoint or until the next true branch.\n"
+ "\n"
+ "gbt {pc != 1234}\n"
+ " Resume execution until the next true branch, disregarding the instruction at address 1234.\n"
+ },
+ {
+ "gni",
+ "\n"
+ " gn[i] [<count>]\n"
+ "\n"
+ "The gni command resumes execution of the current code. Control will not be returned to the "
+ "debugger until a breakpoint or watchpoint is hit, or until you manually break in using the "
+ "assigned key. Before executing, the gni command sets a temporary unconditional breakpoint "
+ "<count> instructions sequentially past the current one, which is automatically removed when "
+ "hit. If <count> is omitted, its default value is 1. If <count> is specified as zero, the "
+ "command does nothing. <count> is not permitted to exceed 512 decimal."
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gni\n"
+ " Resume execution, stopping at the address of the next instruction unless something else "
+ "stops us first.\n"
+ "\n"
+ "gni 2\n"
+ " Resume execution, stopping at two instructions past the current one.\n"
+ },
+ {
"gex",
"\n"
" ge[x] [<exception>,[<condition>]]\n"
diff --git a/src/emu/debug/debugvw.cpp b/src/emu/debug/debugvw.cpp
index 5bcc3d057b8..54fe57ecf5a 100644
--- a/src/emu/debug/debugvw.cpp
+++ b/src/emu/debug/debugvw.cpp
@@ -503,11 +503,11 @@ bool debug_view_expression::recompute()
std::string oldstring(m_parsed.original_string());
try
{
- m_parsed.parse(m_string.c_str());
+ m_parsed.parse(m_string);
}
catch (expression_error &)
{
- m_parsed.parse(oldstring.c_str());
+ m_parsed.parse(oldstring);
}
}
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index 02fcde9cbc3..1f1adcb138d 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -20,6 +20,20 @@
//**************************************************************************
+// HELPER FUNCTIONS
+//**************************************************************************
+
+namespace {
+
+constexpr u8 sanitise_character(u8 ch)
+{
+ // assume ISO-8859-1 (low 256 Unicode codepoints) - tab, soft hyphen, C0 and C1 cause problems
+ return ('\t' == ch) ? ' ' : (0xadU == ch) ? '-' : ((' ' > ch) || (('~' < ch) && (0xa0U > ch))) ? '.' : ch;
+}
+
+} // anonymous namespace
+
+//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -301,7 +315,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
if (dest >= destmin && dest < destmax)
dest->byte = addrtext[ch];
- // generate the data and the ascii string
+ // generate the data and the ASCII string
std::string chunkascii;
if (m_shift_bits != 0)
{
@@ -323,7 +337,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
for (int i = 0; i < m_bytes_per_chunk; i++)
{
u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
- chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ chunkascii += char(ismapped ? sanitise_character(chval) : '.');
}
}
}
@@ -380,7 +394,7 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
for (int i = 0; i < m_bytes_per_chunk; i++)
{
u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1));
- chunkascii += char((ismapped && isprint(chval)) ? chval : '.');
+ chunkascii += char(ismapped ? sanitise_character(chval) : '.');
}
}
}
@@ -526,16 +540,8 @@ void debug_view_memory::view_char(int chval)
if (hexchar == nullptr || (m_shift_bits == 3 && chval >= '8'))
break;
- const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
- offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(pos.m_address) : pos.m_address;
- u64 data;
- bool ismapped = read(m_bytes_per_chunk, address, data);
- if (!ismapped)
- break;
-
- data &= ~(util::make_bitmask<u64>(m_shift_bits) << pos.m_shift);
- data |= u64(hexchar - hexvals) << pos.m_shift;
- write(m_bytes_per_chunk, address, data);
+ if (!write_digit(pos.m_address, pos.m_shift, hexchar - hexvals))
+ break; // TODO: alert OSD?
}
// fall through to the right-arrow press
[[fallthrough]];
@@ -984,6 +990,41 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data)
//-------------------------------------------------
+// write_digit - write one hex or octal digit
+// at the given address and bit position
+//-------------------------------------------------
+
+bool debug_view_memory::write_digit(offs_t offs, u8 pos, u8 digit)
+{
+ const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
+ offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(offs) : offs;
+ u64 data;
+ bool ismapped = read(m_bytes_per_chunk, address, data);
+ if (!ismapped)
+ return false;
+
+ // clamp to chunk size
+ if (m_bytes_per_chunk * 8 < pos + m_shift_bits)
+ {
+ assert(m_bytes_per_chunk * 8 > pos);
+ digit &= util::make_bitmask<u8>(m_bytes_per_chunk * 8 - pos);
+ }
+
+ u64 write_data = (data & ~(util::make_bitmask<u64>(m_shift_bits) << pos)) | (u64(digit) << pos);
+ write(m_bytes_per_chunk, address, write_data);
+
+ // verify that data reads back as it was written
+ if (source.m_space != nullptr)
+ {
+ read(m_bytes_per_chunk, address, data);
+ return data == write_data;
+ }
+ else
+ return true;
+}
+
+
+//-------------------------------------------------
// set_expression - set the expression string
// describing the home address
//-------------------------------------------------
diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h
index f2c738a6ff4..6f1ffab4e9e 100644
--- a/src/emu/debug/dvmemory.h
+++ b/src/emu/debug/dvmemory.h
@@ -127,6 +127,7 @@ private:
// memory access
bool read(u8 size, offs_t offs, u64 &data);
void write(u8 size, offs_t offs, u64 data);
+ bool write_digit(offs_t offs, u8 pos, u8 digit);
bool read(u8 size, offs_t offs, extFloat80_t &data);
bool read_chunk(offs_t address, int chunknum, u64 &chunkdata);
void generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address);
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index 8363928e5cb..f9074147b7b 100644
--- a/src/emu/debug/express.cpp
+++ b/src/emu/debug/express.cpp
@@ -387,10 +387,10 @@ void symbol_table::set_memory_modified_func(memory_modified_func modified)
// add - add a new u64 pointer symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, read_write rw, u64 *ptr)
+symbol_entry &symbol_table::add(const char *name, read_write rw, u64 *ptr)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, rw, ptr)).first->second;
}
@@ -398,10 +398,10 @@ void symbol_table::add(const char *name, read_write rw, u64 *ptr)
// add - add a new value symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, u64 value)
+symbol_entry &symbol_table::add(const char *name, u64 value)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, value)).first->second;
}
@@ -409,10 +409,10 @@ void symbol_table::add(const char *name, u64 value)
// add - add a new register symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
+symbol_entry &symbol_table::add(const char *name, getter_func getter, setter_func setter, const std::string &format_string)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string));
+ return *m_symlist.emplace(name, std::make_unique<integer_symbol_entry>(*this, name, getter, setter, format_string)).first->second;
}
@@ -420,10 +420,10 @@ void symbol_table::add(const char *name, getter_func getter, setter_func setter,
// add - add a new function symbol
//-------------------------------------------------
-void symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
+symbol_entry &symbol_table::add(const char *name, int minparams, int maxparams, execute_func execute)
{
m_symlist.erase(name);
- m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute));
+ return *m_symlist.emplace(name, std::make_unique<function_symbol_entry>(*this, name, minparams, maxparams, execute)).first->second;
}
diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h
index 23284193f47..74b52710959 100644
--- a/src/emu/debug/express.h
+++ b/src/emu/debug/express.h
@@ -175,15 +175,16 @@ public:
// getters
const std::unordered_map<std::string, std::unique_ptr<symbol_entry>> &entries() const { return m_symlist; }
symbol_table *parent() const { return m_parent; }
+ running_machine &machine() { return m_machine; }
// setters
void set_memory_modified_func(memory_modified_func modified);
// symbol access
- void add(const char *name, read_write rw, u64 *ptr = nullptr);
- void add(const char *name, u64 constvalue);
- void add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = "");
- void add(const char *name, int minparams, int maxparams, execute_func execute);
+ symbol_entry &add(const char *name, read_write rw, u64 *ptr = nullptr);
+ symbol_entry &add(const char *name, u64 constvalue);
+ symbol_entry &add(const char *name, getter_func getter, setter_func setter = nullptr, const std::string &format_string = "");
+ symbol_entry &add(const char *name, int minparams, int maxparams, execute_func execute);
symbol_entry *find(const char *name) const { if (name) { auto search = m_symlist.find(name); if (search != m_symlist.end()) return search->second.get(); else return nullptr; } else return nullptr; }
symbol_entry *find_deep(const char *name);
diff --git a/src/emu/debug/points.cpp b/src/emu/debug/points.cpp
index c44bc3f7563..a19f0ab5619 100644
--- a/src/emu/debug/points.cpp
+++ b/src/emu/debug/points.cpp
@@ -22,18 +22,19 @@
// debug_breakpoint - constructor
//-------------------------------------------------
-debug_breakpoint::debug_breakpoint(device_debug* debugInterface,
- symbol_table &symbols,
- int index,
- offs_t address,
- const char *condition,
- const char *action)
- : m_debugInterface(debugInterface),
- m_index(index),
- m_enabled(true),
- m_address(address),
- m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : "")
+debug_breakpoint::debug_breakpoint(
+ device_debug *debugInterface,
+ symbol_table &symbols,
+ int index,
+ offs_t address,
+ const char *condition,
+ const char *action) :
+ m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_address(address),
+ m_condition(symbols, condition ? condition : "1"),
+ m_action(action ? action : "")
{
}
@@ -59,7 +60,7 @@ bool debug_breakpoint::hit(offs_t pc)
{
return (m_condition.execute() != 0);
}
- catch (expression_error &)
+ catch (expression_error const &)
{
return false;
}
@@ -78,27 +79,28 @@ bool debug_breakpoint::hit(offs_t pc)
// debug_watchpoint - constructor
//-------------------------------------------------
-debug_watchpoint::debug_watchpoint(device_debug* debugInterface,
- symbol_table &symbols,
- int index,
- address_space &space,
- read_or_write type,
- offs_t address,
- offs_t length,
- const char *condition,
- const char *action)
- : m_debugInterface(debugInterface),
- m_phr(nullptr),
- m_phw(nullptr),
- m_space(space),
- m_index(index),
- m_enabled(true),
- m_type(type),
- m_address(address & space.addrmask()),
- m_length(length),
- m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : ""),
- m_installing(false)
+debug_watchpoint::debug_watchpoint(
+ device_debug* debugInterface,
+ symbol_table &symbols,
+ int index,
+ address_space &space,
+ read_or_write type,
+ offs_t address,
+ offs_t length,
+ const char *condition,
+ const char *action) :
+ m_debugInterface(debugInterface),
+ m_phr(nullptr),
+ m_phw(nullptr),
+ m_space(space),
+ m_index(index),
+ m_enabled(true),
+ m_type(type),
+ m_address(address & space.addrmask()),
+ m_length(length),
+ m_condition(symbols, condition ? condition : "1"),
+ m_action(action ? action : ""),
+ m_installing(false)
{
std::fill(std::begin(m_start_address), std::end(m_start_address), 0);
std::fill(std::begin(m_end_address), std::end(m_end_address), 0);
@@ -170,21 +172,21 @@ debug_watchpoint::debug_watchpoint(device_debug* debugInterface,
}
install(read_or_write::READWRITE);
- m_notifier = m_space.add_change_notifier([this](read_or_write mode) {
- if (m_enabled)
- {
- install(mode);
- }
- });
+ m_notifier = m_space.add_change_notifier(
+ [this] (read_or_write mode)
+ {
+ if (m_enabled)
+ {
+ install(mode);
+ }
+ });
}
debug_watchpoint::~debug_watchpoint()
{
- m_space.remove_change_notifier(m_notifier);
- if (m_phr)
- m_phr->remove();
- if (m_phw)
- m_phw->remove();
+ m_notifier.reset();
+ m_phr.remove();
+ m_phw.remove();
}
void debug_watchpoint::setEnabled(bool value)
@@ -197,10 +199,8 @@ void debug_watchpoint::setEnabled(bool value)
else
{
m_installing = true;
- if(m_phr)
- m_phr->remove();
- if(m_phw)
- m_phw->remove();
+ m_phr.remove();
+ m_phw.remove();
m_installing = false;
}
}
@@ -211,24 +211,28 @@ void debug_watchpoint::install(read_or_write mode)
if (m_installing)
return;
m_installing = true;
- if ((u32(mode) & u32(read_or_write::READ)) && m_phr)
- m_phr->remove();
- if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw)
- m_phw->remove();
+ if (u32(mode) & u32(read_or_write::READ))
+ m_phr.remove();
+ if (u32(mode) & u32(read_or_write::WRITE))
+ m_phw.remove();
std::string name = util::string_format("wp@%x", m_address);
switch (m_space.data_width())
{
case 8:
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name,
- [this](offs_t offset, u8 &data, u8 mem_mask) {
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[0], m_end_address[0], name,
+ [this](offs_t offset, u8 &data, u8 mem_mask) {
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name,
- [this](offs_t offset, u8 &data, u8 mem_mask) {
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[0], m_end_address[0], name,
+ [this](offs_t offset, u8 &data, u8 mem_mask) {
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
break;
case 16:
@@ -237,17 +241,21 @@ void debug_watchpoint::install(read_or_write mode)
{
u16 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u16 &data, u16 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
@@ -257,17 +265,21 @@ void debug_watchpoint::install(read_or_write mode)
{
u32 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
- m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ m_phw = m_space.install_write_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u32 &data, u32 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
@@ -277,17 +289,20 @@ void debug_watchpoint::install(read_or_write mode)
{
u64 mask = m_masks[i];
if (u32(m_type) & u32(mode) & u32(read_or_write::READ))
- m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::READ, offset, data, mem_mask);
- }, m_phr);
+ m_phr = m_space.install_read_tap(
+ m_start_address[i], m_end_address[i], name,
+ [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::READ, offset, data, mem_mask);
+ },
+ &m_phr);
if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE))
m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name,
- [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
- if (mem_mask & mask)
- triggered(read_or_write::WRITE, offset, data, mem_mask);
- }, m_phw);
+ [this, mask](offs_t offset, u64 &data, u64 mem_mask) {
+ if (mem_mask & mask)
+ triggered(read_or_write::WRITE, offset, data, mem_mask);
+ },
+ &m_phw);
}
break;
}
diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h
index 84cdad7720b..62ad953626c 100644
--- a/src/emu/debug/points.h
+++ b/src/emu/debug/points.h
@@ -102,8 +102,8 @@ private:
void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask);
device_debug * m_debugInterface; // the interface we were created from
- memory_passthrough_handler *m_phr; // passthrough handler reference, read access
- memory_passthrough_handler *m_phw; // passthrough handler reference, write access
+ memory_passthrough_handler m_phr; // passthrough handler reference, read access
+ memory_passthrough_handler m_phw; // passthrough handler reference, write access
address_space & m_space; // address space
int m_index; // user reported index
bool m_enabled; // enabled?
@@ -112,7 +112,7 @@ private:
offs_t m_length; // length of watch area
parsed_expression m_condition; // condition
std::string m_action; // action
- int m_notifier; // address map change notifier id
+ util::notifier_subscription m_notifier; // address map change notifier ID
offs_t m_start_address[3]; // the start addresses of the checks to install
offs_t m_end_address[3]; // the end addresses