summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugbuf.cpp43
-rw-r--r--src/emu/debug/debugcmd.cpp1649
-rw-r--r--src/emu/debug/debugcmd.h191
-rw-r--r--src/emu/debug/debugcon.cpp758
-rw-r--r--src/emu/debug/debugcon.h70
-rw-r--r--src/emu/debug/debugcpu.cpp418
-rw-r--r--src/emu/debug/debugcpu.h73
-rw-r--r--src/emu/debug/debughlp.cpp235
-rw-r--r--src/emu/debug/debughlp.h2
-rw-r--r--src/emu/debug/debugvw.cpp4
-rw-r--r--src/emu/debug/dvbpoints.cpp2
-rw-r--r--src/emu/debug/dvmemory.cpp82
-rw-r--r--src/emu/debug/dvmemory.h1
-rw-r--r--src/emu/debug/dvrpoints.cpp2
-rw-r--r--src/emu/debug/express.cpp42
-rw-r--r--src/emu/debug/express.h25
-rw-r--r--src/emu/debug/points.cpp255
-rw-r--r--src/emu/debug/points.h54
18 files changed, 2397 insertions, 1509 deletions
diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp
index 85ec19d5fb9..616567b398e 100644
--- a/src/emu/debug/debugbuf.cpp
+++ b/src/emu/debug/debugbuf.cpp
@@ -82,6 +82,8 @@ void debug_disasm_buffer::debug_data_buffer::fill(offs_t lstart, offs_t size) co
}
}
+ // FIXME: This buffer tends to hog more memory than necessary for typical disassembly tasks.
+ // If the PC values supplied are far enough apart, the buffer may suddenly increase in size to a gigabyte or more.
if(m_buffer.empty()) {
m_lstart = lstart;
m_lend = lend;
@@ -209,8 +211,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = get_ptr<u16>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = m_intf.pc_linear_to_real(lpc);
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -220,14 +223,13 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
m_do_fill = [this](offs_t lstart, offs_t lend) {
auto dis = m_space->device().machine().disable_side_effects();
u8 *dest = get_ptr<u8>(lstart);
- u32 steps = 0;
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = m_intf.pc_linear_to_real(lpc);
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_byte(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_byte(tpc);
else
*dest++ = 0;
- steps++;
}
};
break;
@@ -241,8 +243,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u64 *dest = get_ptr<u64>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_qword(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_qword(tpc);
else
*dest++ = 0;
}
@@ -255,8 +258,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u32 *dest = get_ptr<u32>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_dword(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_dword(tpc);
else
*dest++ = 0;
}
@@ -269,8 +273,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = get_ptr<u16>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -283,8 +288,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u8 *dest = get_ptr<u8>(lstart);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_byte(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_byte(tpc);
else
*dest++ = 0;
}
@@ -297,8 +303,9 @@ void debug_disasm_buffer::debug_data_buffer::setup_methods()
u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4);
for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) {
offs_t tpc = lpc;
- if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
- *dest++ = m_space->read_word(tpc);
+ address_space *space;
+ if (m_space->device().memory().translate(m_space->spacenum(), device_memory_interface::TR_FETCH, tpc, space))
+ *dest++ = space->read_word(tpc);
else
*dest++ = 0;
}
@@ -1390,7 +1397,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) :
// pc to string conversion
int aw = pspace.logaddr_width();
bool is_octal = pspace.is_octal();
- if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) {
+ if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL && aw > (m_dintf.page_address_bits() + m_dintf.page2_address_bits())) {
int bits1 = m_dintf.page_address_bits();
int bits2 = m_dintf.page2_address_bits();
int bits3 = aw - bits1 - bits2;
@@ -1421,7 +1428,7 @@ debug_disasm_buffer::debug_disasm_buffer(device_t &device) :
};
}
- } else if(m_flags & util::disasm_interface::PAGED) {
+ } else if((m_flags & util::disasm_interface::PAGED) && aw > m_dintf.page_address_bits()) {
int bits1 = m_dintf.page_address_bits();
int bits2 = aw - bits1;
offs_t sm1 = (1 << bits1) - 1;
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index b8de0298432..ad463ace500 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,35 +32,7 @@
#include <algorithm>
#include <cctype>
#include <fstream>
-
-
-
-namespace {
-
-template <typename T>
-inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim)
-{
- unsigned parens = 0;
- for (std::string_view::size_type i = 0; str.length() > i; ++i)
- {
- if (str[i] == '(')
- {
- ++parens;
- }
- else if (parens)
- {
- if (str[i] == ')')
- --parens;
- }
- else if (is_delim(str[i]))
- {
- return i;
- }
- }
- return std::string_view::npos;
-}
-
-} // anonymous namespace
+#include <sstream>
@@ -80,7 +53,8 @@ const size_t debugger_commands::MAX_GLOBALS = 1000;
bool debugger_commands::cheat_address_is_valid(address_space &space, offs_t address)
{
- return space.device().memory().translate(space.spacenum(), TRANSLATE_READ, address) && (space.get_write_ptr(address) != nullptr);
+ address_space *tspace;
+ return space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace) && (tspace->get_write_ptr(address) != nullptr);
}
@@ -131,14 +105,15 @@ u64 debugger_commands::cheat_system::read_extended(offs_t address) const
{
address &= space->logaddrmask();
u64 value = space->unmap();
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
{
switch (width)
{
- case 1: value = space->read_byte(address); break;
- case 2: value = space->read_word_unaligned(address); break;
- case 4: value = space->read_dword_unaligned(address); break;
- case 8: value = space->read_qword_unaligned(address); break;
+ case 1: value = tspace->read_byte(address); break;
+ case 2: value = tspace->read_word_unaligned(address); break;
+ case 4: value = tspace->read_dword_unaligned(address); break;
+ case 8: value = tspace->read_qword_unaligned(address); break;
}
}
return sign_extend(byte_swap(value));
@@ -195,7 +170,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
if ((valcount == 1) && (blockcount == 1) && strstr(name, "/globals/"))
{
char symname[100];
- sprintf(symname, ".%s", strrchr(name, '/') + 1);
+ snprintf(symname, 100, ".%s", strrchr(name, '/') + 1);
m_global_array[itemnum].base = base;
m_global_array[itemnum].size = valsize;
symtable.add(
@@ -232,6 +207,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 +218,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));
@@ -276,6 +255,13 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_console.register_command("rpenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_rpdisenable, this, true, _1));
m_console.register_command("rplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_rplist, this, _1));
+ m_console.register_command("epset", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("ep", CMDFLAG_NONE, 1, 3, std::bind(&debugger_commands::execute_epset, this, _1));
+ m_console.register_command("epclear", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epclear, this, _1));
+ m_console.register_command("epdisable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, false, _1));
+ m_console.register_command("epenable", CMDFLAG_NONE, 0, MAX_COMMAND_PARAMS, std::bind(&debugger_commands::execute_epdisenable, this, true, _1));
+ m_console.register_command("eplist", CMDFLAG_NONE, 0, 1, std::bind(&debugger_commands::execute_eplist, this, _1));
+
m_console.register_command("statesave", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("ss", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_statesave, this, _1));
m_console.register_command("stateload", CMDFLAG_NONE, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1));
@@ -443,475 +429,15 @@ void debugger_commands::global_set(global_entry *global, u64 value)
-/***************************************************************************
- PARAMETER VALIDATION HELPERS
-***************************************************************************/
-
-/// \brief Validate parameter as a Boolean value
-///
-/// Validates a parameter as a Boolean value. Fixed strings and
-/// expressions evaluating to numeric values are recognised. The result
-/// is unchanged for an empty string.
-/// \param [in] param The parameter string.
-/// \param [in,out] result The default value on entry, and the value of
-/// the parameter interpreted as a Boolean on success. Unchanged if
-/// the parameter is an empty string.
-/// \return true if the parameter is a valid Boolean value or an empty
-/// string, or false otherwise.
-bool debugger_commands::validate_boolean_parameter(const std::string &param, bool &result)
-{
- // nullptr parameter does nothing and returns no error
- if (param.empty())
- return true;
-
- // evaluate the expression; success if no error
- bool const is_true = !core_stricmp(param.c_str(), "true");
- bool const is_false = !core_stricmp(param.c_str(), "false");
-
- if (is_true || is_false)
- {
- result = is_true;
- return true;
- }
-
- // try to evaluate as a number
- u64 val;
- if (!validate_number_parameter(param, val))
- return false;
-
- result = val != 0;
- return true;
-}
-
-
-/// \brief Validate parameter as a numeric value
-///
-/// Parses the parameter as an expression and evaluates it as a number.
-/// \param [in] param The parameter string.
-/// \param [out] result The numeric value of the expression on success.
-/// Unchanged on failure.
-/// \return true if the parameter is a valid expression that evaluates
-/// to a numeric value, or false otherwise.
-bool debugger_commands::validate_number_parameter(std::string_view param, u64 &result)
-{
- // evaluate the expression; success if no error
- try
- {
- result = parsed_expression(m_console.visible_symtable(), param).execute();
- return true;
- }
- catch (expression_error const &error)
- {
- // print an error pointing to the character that caused it
- m_console.printf("Error in expression: %s\n", param);
- m_console.printf(" %*s^", error.offset(), "");
- m_console.printf("%s\n", error.code_string());
- return false;
- }
-}
-
-
-/// \brief Validate parameter as a device
-///
-/// Validates a parameter as a device identifier and retrieves the
-/// device on success. A string corresponding to the tag of a device
-/// refers to that device; an empty string refers to the current CPU
-/// with debugger focus; any other string is parsed as an expression
-/// and treated as an index of a device implementing
-/// #device_execute_interface and #device_state_interface, and exposing
-/// a generic PC base value.
-/// \param [in] param The parameter string.
-/// \param [out] result A pointer to the device on success, or unchanged
-/// on failure.
-/// \return true if the parameter refers to a device in the current
-/// system, or false otherwise.
-bool debugger_commands::validate_device_parameter(std::string_view param, device_t *&result)
-{
- // if no parameter, use the visible CPU
- if (param.empty())
- {
- device_t *const current = m_console.get_visible_cpu();
- if (current)
- {
- result = current;
- return true;
- }
- else
- {
- m_console.printf("No valid CPU is currently selected\n");
- return false;
- }
- }
-
- // next look for a tag match
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- device_t *device = base.subdevice(strmakelower(relative));
- if (device)
- {
- result = device;
- return true;
- }
-
- // then evaluate as an expression; on an error assume it was a tag
- u64 cpunum;
- try
- {
- cpunum = parsed_expression(m_console.visible_symtable(), param).execute();
- }
- catch (expression_error &)
- {
- m_console.printf("Unable to find device '%s'\n", param);
- return false;
- }
-
- // attempt to find by numerical index
- device = get_cpu_by_index(cpunum);
- if (device)
- {
- result = device;
- return true;
- }
- else
- {
- // if out of range, complain
- m_console.printf("Invalid CPU index %u\n", cpunum);
- return false;
- }
-}
-
-
-/// \brief Validate a parameter as a CPU
-///
-/// Validates a parameter as a CPU identifier. Uses the same rules as
-/// #validate_device_parameter to identify devices, but additionally
-/// checks that the device is a "CPU" for the debugger's purposes.
-/// \param [in] The parameter string.
-/// \param [out] result The device on success, or unchanged on failure.
-/// \return true if the parameter refers to a CPU-like device in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_cpu_parameter(std::string_view param, device_t *&result)
-{
- // first do the standard device thing
- device_t *device;
- if (!validate_device_parameter(param, device))
- return false;
-
- // check that it's a "CPU" for the debugger's purposes
- device_execute_interface const *execute;
- if (device->interface(execute))
- {
- result = device;
- return true;
- }
-
- m_console.printf("Device %s is not a CPU\n", device->name());
- return false;
-}
-
-
-/// \brief Validate a parameter as an address space identifier
-///
-/// Validates a parameter as an address space identifier. Uses the same
-/// rules as #validate_device_parameter to identify devices. If the
-/// default address space number is negative, the first address space
-/// exposed by the device will be used as the default.
-/// \param [in] The parameter string.
-/// \param [in] spacenum The default address space index. If negative,
-/// the first address space exposed by the device (i.e. the address
-/// space with the lowest index) will be used as the default.
-/// \param [out] result The address space on success, or unchanged on
-/// failure.
-/// \return true if the parameter refers to an address space in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result)
-{
- device_t *device;
- std::string spacename;
- if (param.empty())
- {
- // if no parameter, use the visible CPU
- device = m_console.get_visible_cpu();
- if (!device)
- {
- m_console.printf("No valid CPU is currently selected\n");
- return false;
- }
- }
- else
- {
- // look for a tag match on the whole parameter value
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- device = base.subdevice(strmakelower(relative));
-
- // if that failed, treat the last component as an address space
- if (!device)
- {
- auto const delimiter = relative.find_last_of(":^");
- bool const found = std::string_view::npos != delimiter;
- if (!found || (':' == relative[delimiter]))
- {
- spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0));
- relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
- if (!relative.empty())
- device = base.subdevice(strmakelower(relative));
- else if (m_console.get_visible_cpu())
- device = m_console.get_visible_cpu();
- else
- device = &m_machine.root_device();
- }
- }
- }
-
- // if still no device found, evaluate as an expression
- if (!device)
- {
- u64 cpunum;
- try
- {
- cpunum = parsed_expression(m_console.visible_symtable(), param).execute();
- }
- catch (expression_error const &)
- {
- // parsing failed - assume it was a tag
- m_console.printf("Unable to find device '%s'\n", param);
- return false;
- }
-
- // attempt to find by numerical index
- device = get_cpu_by_index(cpunum);
- if (!device)
- {
- // if out of range, complain
- m_console.printf("Invalid CPU index %u\n", cpunum);
- return false;
- }
- }
-
- // ensure the device implements the memory interface
- device_memory_interface *memory;
- if (!device->interface(memory))
- {
- m_console.printf("No memory interface found for device %s\n", device->name());
- return false;
- }
-
- // fall back to supplied default space if appropriate
- if (spacename.empty() && (0 <= spacenum))
- {
- if (memory->has_space(spacenum))
- {
- result = &memory->space(spacenum);
- return true;
- }
- else
- {
- m_console.printf("No matching memory space found for device '%s'\n", device->tag());
- return false;
- }
- }
-
- // otherwise find the specified space or fall back to the first populated space
- for (int i = 0; memory->max_space_count() > i; ++i)
- {
- if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename)))
- {
- result = &memory->space(i);
- return true;
- }
- }
-
- // report appropriate error message
- if (spacename.empty())
- m_console.printf("No memory spaces found for device '%s'\n", device->tag());
- else
- m_console.printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag());
- return false;
-}
-
-
-/// \brief Validate a parameter as a target address
-///
-/// Validates a parameter as an numeric expression to use as an address
-/// optionally followed by a colon and a device identifier. If the
-/// device identifier is not presnt, the current CPU with debugger focus
-/// is assumed. See #validate_device_parameter for information on how
-/// device parametersare interpreted.
-/// \param [in] The parameter string.
-/// \param [in] spacenum The default address space index. If negative,
-/// the first address space exposed by the device (i.e. the address
-/// space with the lowest index) will be used as the default.
-/// \param [out] space The address space on success, or unchanged on
-/// failure.
-/// \param [out] addr The address on success, or unchanged on failure.
-/// \return true if the address is a valid expression evaluating to a
-/// number and the address space is found, or false otherwise.
-bool debugger_commands::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr)
-{
- // check for the device delimiter
- std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; });
- std::string_view device;
- if (devdelim != std::string::npos)
- device = param.substr(devdelim + 1);
-
- // parse the address first
- u64 addrval;
- if (!validate_number_parameter(param.substr(0, devdelim), addrval))
- return false;
-
- // find the address space
- if (!validate_device_space_parameter(device, spacenum, space))
- return false;
-
- // set the address now that we have the space
- addr = addrval;
- return true;
-}
-
-
-/// \brief Validate a parameter as a memory region
-///
-/// Validates a parameter as a memory region tag and retrieves the
-/// specified memory region.
-/// \param [in] The parameter string.
-/// \param [out] result The memory region on success, or unchanged on
-/// failure.
-/// \return true if the parameter refers to a memory region in the
-/// current system, or false otherwise.
-bool debugger_commands::validate_memory_region_parameter(std::string_view param, memory_region *&result)
-{
- auto const &regions = m_machine.memory().regions();
- std::string_view relative = param;
- device_t &base = get_device_search_base(relative);
- auto const iter = regions.find(base.subtag(strmakelower(relative)));
- if (regions.end() != iter)
- {
- result = iter->second.get();
- return true;
- }
- else
- {
- m_console.printf("No matching memory region found for '%s'\n", param);
- return false;
- }
-}
-
-
-/// \brief Get search base for device or address space parameter
-///
-/// Handles prefix prefixes used to indicate that a device tag should be
-/// interpreted relative to the selected CPU. Removes the recognised
-/// prefixes from the parameter value.
-/// \param [in,out] param The parameter string. Recognised prefixes
-/// affecting the search base are removed, leaving a tag relative to
-/// the base device.
-/// \return A reference to the base device that the tag should be
-/// interpreted relative to.
-device_t &debugger_commands::get_device_search_base(std::string_view &param)
-{
- if (!param.empty())
- {
- // handle ".:" or ".^" prefix for tag relative to current CPU if any
- if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1])))
- {
- param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1);
- device_t *const current = m_console.get_visible_cpu();
- return current ? *current : m_machine.root_device();
- }
-
- // a sibling path makes most sense relative to current CPU
- if ('^' == param[0])
- {
- device_t *const current = m_console.get_visible_cpu();
- return current ? *current : m_machine.root_device();
- }
- }
-
-
- // default to root device
- return m_machine.root_device();
-}
-
-
-/// \brief Get CPU by index
-///
-/// Looks up a CPU by the number the debugger assigns it based on its
-/// position in the device tree relative to other CPUs.
-/// \param [in] cpunum Zero-based index of the CPU to find.
-/// \return A pointer to the CPU if found, or \c nullptr if no CPU has
-/// the specified index.
-device_t *debugger_commands::get_cpu_by_index(u64 cpunum)
-{
- unsigned index = 0;
- for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
- {
- // real CPUs should have pcbase
- device_state_interface const *state;
- if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE))
- {
- if (index++ == cpunum)
- {
- return &exec.device();
- }
- }
- }
- return nullptr;
-}
-
-
-/*-------------------------------------------------
- debug_command_parameter_expression - validates
- an expression parameter
--------------------------------------------------*/
-
-bool debugger_commands::debug_command_parameter_expression(std::string_view param, parsed_expression &result)
-{
- try
- {
- // parse the expression; success if no error
- result.parse(param);
- return true;
- }
- catch (expression_error const &err)
- {
- // output an error
- m_console.printf("Error in expression: %s\n", param);
- m_console.printf(" %*s^", err.offset(), "");
- m_console.printf("%s\n", err.code_string());
- return false;
- }
-}
-
-
-/*-------------------------------------------------
- debug_command_parameter_command - validates a
- command parameter
--------------------------------------------------*/
-
-bool debugger_commands::debug_command_parameter_command(const char *param)
-{
- /* nullptr parameter does nothing and returns no error */
- if (param == nullptr)
- return true;
-
- /* validate the comment; success if no error */
- CMDERR err = m_console.validate_command(param);
- if (err.error_class() == CMDERR::NONE)
- return true;
-
- /* output an error */
- m_console.printf("Error in command: %s\n", param);
- m_console.printf(" %*s^", err.error_offset(), "");
- m_console.printf("%s\n", debugger_console::cmderr_to_string(err));
- return 0;
-}
+//**************************************************************************
+// COMMAND IMPLEMENTATIONS
+//**************************************************************************
/*-------------------------------------------------
execute_help - execute the help command
-------------------------------------------------*/
-void debugger_commands::execute_help(const std::vector<std::string> &params)
+void debugger_commands::execute_help(const std::vector<std::string_view> &params)
{
if (params.size() == 0)
m_console.printf_wrap(80, "%s\n", debug_get_help(std::string_view()));
@@ -924,12 +450,12 @@ void debugger_commands::execute_help(const std::vector<std::string> &params)
execute_print - execute the print command
-------------------------------------------------*/
-void debugger_commands::execute_print(const std::vector<std::string> &params)
+void debugger_commands::execute_print(const std::vector<std::string_view> &params)
{
/* validate the other parameters */
u64 values[MAX_COMMAND_PARAMS];
for (int i = 0; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
+ if (!m_console.validate_number_parameter(params[i], values[i]))
return;
/* then print each one */
@@ -943,131 +469,177 @@ 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, const std::vector<std::string_view> &params)
{
- const char *f = format;
- char *p = buffer;
+ std::string_view const format(params[0]);
+ auto f = format.begin();
+
+ int param = 1;
+ u64 number;
- /* 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 == '%')
{
+ bool left_justify = false;
+ bool zero_fill = false;
int width = 0;
- int zerofill = 0;
+ int precision = 0;
- /* parse out the width */
- for (;;)
+ // parse optional left justification flag
+ if (f != format.end() && *f == '-')
{
- c = *f++;
- if (!c || c < '0' || c > '9') break;
- if (c == '0' && width == 0)
- zerofill = 1;
- width = width * 10 + (c - '0');
+ left_justify = true;
+ f++;
+ }
+
+ // parse optional zero fill flag
+ if (f != format.end() && *f == '0')
+ {
+ zero_fill = true;
+ f++;
+ }
+
+ // parse optional width
+ while (f != format.end() && isdigit(*f))
+ width = width * 10 + (*f++ - '0');
+ if (f == format.end())
+ break;
+
+ // apply left justification
+ if (left_justify)
+ width = -width;
+
+ if ((c = *f++) == '.')
+ {
+ // parse optional precision
+ while (f != format.end() && isdigit(*f))
+ precision = precision * 10 + (*f++ - '0');
+
+ // get the format
+ if (f != format.end())
+ c = *f++;
+ else
+ break;
}
- if (!c) break;
- /* get the format */
switch (c)
{
case '%':
- *p++ = c;
+ stream << c;
break;
case 'X':
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*X" : "%*X", width, number);
+ else
+ {
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
+ }
+ break;
case 'x':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*x" : "%*x", width, number);
+ else
{
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));
- 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));
- param++;
- params--;
break;
case 'O':
case 'o':
- if (params == 0)
- {
- m_console.printf("Not enough parameters for format!\n");
- return 0;
- }
- 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)));
- }
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number);
else
{
- if (width > 20)
- p += sprintf(p, 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)));
- else if (width > 10)
- p += sprintf(p, zerofill ? "%0*o" : "%*o", width - 10, 0);
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
}
- p += sprintf(p, zerofill ? "%0*o" : "%*o", (width < 10) ? width : 10, u32(BIT(*param, 0, 30)));
- param++;
- params--;
break;
case 'D':
case 'd':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*d" : "%*d", width, number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, zerofill ? "%0*d" : "%*d", width, u32(*param));
- param++;
- params--;
break;
+
case 'C':
case 'c':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ stream << char(number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
- return 0;
+ return false;
}
- p += sprintf(p, "%c", char(*param));
- param++;
- params--;
break;
+ case 's':
+ {
+ address_space *space;
+ if (param < params.size() && m_console.validate_target_address_parameter(params[param++], -1, space, number))
+ {
+ address_space *tspace;
+ std::string s;
+
+ for (u32 address = u32(number), taddress; space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, taddress = address, tspace); address++)
+ {
+ u8 const data = tspace->read_byte(taddress);
+
+ if (!data)
+ break;
+
+ s += data;
+
+ if (precision == 1)
+ break;
+ else if (precision)
+ precision--;
+ }
+
+ util::stream_format(stream, "%*s", width, s);
+ }
+ else
+ {
+ m_console.printf("Not enough parameters for format!\n");
+ return false;
+ }
+ }
+ break;
}
}
- /* normal stuff */
+ // normal stuff
else
- *p++ = c;
+ stream << c;
}
- /* NULL-terminate and exit */
- *p = 0;
- return 1;
+ return true;
}
@@ -1077,12 +649,12 @@ int debugger_commands::mini_printf(char *buffer, const char *format, int params,
-------------------------------------------------*/
template <typename T>
-void debugger_commands::execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message)
+void debugger_commands::execute_index_command(std::vector<std::string_view> const &params, T &&apply, char const *unused_message)
{
std::vector<u64> index(params.size());
for (int paramnum = 0; paramnum < params.size(); paramnum++)
{
- if (!validate_number_parameter(params[paramnum], index[paramnum]))
+ if (!m_console.validate_number_parameter(params[paramnum], index[paramnum]))
return;
}
@@ -1106,18 +678,12 @@ void debugger_commands::execute_index_command(std::vector<std::string> const &pa
execute_printf - execute the printf command
-------------------------------------------------*/
-void debugger_commands::execute_printf(const std::vector<std::string> &params)
+void debugger_commands::execute_printf(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- 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))
+ m_console.printf("%s\n", std::move(buffer).str());
}
@@ -1125,18 +691,12 @@ void debugger_commands::execute_printf(const std::vector<std::string> &params)
execute_logerror - execute the logerror command
-------------------------------------------------*/
-void debugger_commands::execute_logerror(const std::vector<std::string> &params)
+void debugger_commands::execute_logerror(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- 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))
+ m_machine.logerror("%s", std::move(buffer).str());
}
@@ -1144,18 +704,12 @@ void debugger_commands::execute_logerror(const std::vector<std::string> &params)
execute_tracelog - execute the tracelog command
-------------------------------------------------*/
-void debugger_commands::execute_tracelog(const std::vector<std::string> &params)
+void debugger_commands::execute_tracelog(const std::vector<std::string_view> &params)
{
- /* validate the other parameters */
- u64 values[MAX_COMMAND_PARAMS];
- for (int i = 1; i < params.size(); i++)
- if (!validate_number_parameter(params[i], values[i]))
- 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))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1163,11 +717,10 @@ void debugger_commands::execute_tracelog(const std::vector<std::string> &params)
execute_tracesym - execute the tracesym command
-------------------------------------------------*/
-void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
+void debugger_commands::execute_tracesym(const std::vector<std::string_view> &params)
{
// build a format string appropriate for the parameters and validate them
std::stringstream format;
- u64 values[MAX_COMMAND_PARAMS];
for (int i = 0; i < params.size(); i++)
{
// find this symbol
@@ -1182,16 +735,16 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
util::stream_format(format, "%s=%s ",
params[i],
sym->format().empty() ? "%16X" : sym->format());
-
- // validate the parameter
- if (!validate_number_parameter(params[i], values[i]))
- return;
}
+ // build parameters for printf
+ std::vector<std::string_view> printf_params(params);
+ printf_params.insert(printf_params.begin(), format.str());
+
// 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, printf_params))
+ m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -1199,7 +752,7 @@ void debugger_commands::execute_tracesym(const std::vector<std::string> &params)
execute_cls - execute the cls command
-------------------------------------------------*/
-void debugger_commands::execute_cls(const std::vector<std::string> &params)
+void debugger_commands::execute_cls(const std::vector<std::string_view> &params)
{
text_buffer_clear(m_console.get_console_textbuf());
}
@@ -1209,7 +762,7 @@ void debugger_commands::execute_cls(const std::vector<std::string> &params)
execute_quit - execute the quit command
-------------------------------------------------*/
-void debugger_commands::execute_quit(const std::vector<std::string> &params)
+void debugger_commands::execute_quit(const std::vector<std::string_view> &params)
{
osd_printf_warning("Exited via the debugger\n");
m_machine.schedule_exit();
@@ -1220,10 +773,10 @@ void debugger_commands::execute_quit(const std::vector<std::string> &params)
execute_do - execute the do command
-------------------------------------------------*/
-void debugger_commands::execute_do(const std::vector<std::string> &params)
+void debugger_commands::execute_do(const std::vector<std::string_view> &params)
{
u64 dummy;
- validate_number_parameter(params[0], dummy);
+ m_console.validate_number_parameter(params[0], dummy);
}
@@ -1231,11 +784,11 @@ void debugger_commands::execute_do(const std::vector<std::string> &params)
execute_step - execute the step command
-------------------------------------------------*/
-void debugger_commands::execute_step(const std::vector<std::string> &params)
+void debugger_commands::execute_step(const std::vector<std::string_view> &params)
{
/* if we have a parameter, use it */
u64 steps = 1;
- if (params.size() > 0 && !validate_number_parameter(params[0], steps))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps))
return;
m_console.get_visible_cpu()->debug()->single_step(steps);
@@ -1246,11 +799,11 @@ void debugger_commands::execute_step(const std::vector<std::string> &params)
execute_over - execute the over command
-------------------------------------------------*/
-void debugger_commands::execute_over(const std::vector<std::string> &params)
+void debugger_commands::execute_over(const std::vector<std::string_view> &params)
{
/* if we have a parameter, use it */
u64 steps = 1;
- if (params.size() > 0 && !validate_number_parameter(params[0], steps))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], steps))
return;
m_console.get_visible_cpu()->debug()->single_step_over(steps);
@@ -1261,7 +814,7 @@ void debugger_commands::execute_over(const std::vector<std::string> &params)
execute_out - execute the out command
-------------------------------------------------*/
-void debugger_commands::execute_out(const std::vector<std::string> &params)
+void debugger_commands::execute_out(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->single_step_out();
}
@@ -1271,12 +824,12 @@ void debugger_commands::execute_out(const std::vector<std::string> &params)
execute_go - execute the go command
-------------------------------------------------*/
-void debugger_commands::execute_go(const std::vector<std::string> &params)
+void debugger_commands::execute_go(const std::vector<std::string_view> &params)
{
u64 addr = ~0;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], addr))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], addr))
return;
m_console.get_visible_cpu()->debug()->go(addr);
@@ -1288,7 +841,7 @@ void debugger_commands::execute_go(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_go_vblank(const std::vector<std::string> &params)
+void debugger_commands::execute_go_vblank(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->go_vblank();
}
@@ -1298,12 +851,12 @@ void debugger_commands::execute_go_vblank(const std::vector<std::string> &params
execute_go_interrupt - execute the goint command
-------------------------------------------------*/
-void debugger_commands::execute_go_interrupt(const std::vector<std::string> &params)
+void debugger_commands::execute_go_interrupt(const std::vector<std::string_view> &params)
{
u64 irqline = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], irqline))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], irqline))
return;
m_console.get_visible_cpu()->debug()->go_interrupt(irqline);
@@ -1313,16 +866,16 @@ void debugger_commands::execute_go_interrupt(const std::vector<std::string> &par
execute_go_exception - execute the goex command
-------------------------------------------------*/
-void debugger_commands::execute_go_exception(const std::vector<std::string> &params)
+void debugger_commands::execute_go_exception(const std::vector<std::string_view> &params)
{
u64 exception = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], exception))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], exception))
return;
parsed_expression condition(m_console.visible_symtable());
- if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition))
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
return;
m_console.get_visible_cpu()->debug()->go_exception(exception, condition.is_empty() ? "1" : condition.original_string());
@@ -1333,12 +886,12 @@ void debugger_commands::execute_go_exception(const std::vector<std::string> &par
execute_go_time - execute the gtime command
-------------------------------------------------*/
-void debugger_commands::execute_go_time(const std::vector<std::string> &params)
+void debugger_commands::execute_go_time(const std::vector<std::string_view> &params)
{
u64 milliseconds = -1;
/* if we have a parameter, use it instead */
- if (params.size() > 0 && !validate_number_parameter(params[0], milliseconds))
+ if (params.size() > 0 && !m_console.validate_number_parameter(params[0], milliseconds))
return;
m_console.get_visible_cpu()->debug()->go_milliseconds(milliseconds);
@@ -1349,20 +902,76 @@ void debugger_commands::execute_go_time(const std::vector<std::string> &params)
/*-------------------------------------------------
execute_go_privilege - execute the gp command
-------------------------------------------------*/
-void debugger_commands::execute_go_privilege(const std::vector<std::string> &params)
+void debugger_commands::execute_go_privilege(const std::vector<std::string_view> &params)
{
parsed_expression condition(m_console.visible_symtable());
- if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
+ if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition))
return;
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_view> &params)
+{
+ parsed_expression condition(m_console.visible_symtable());
+ if (params.size() > 0 && !m_console.validate_expression_parameter(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_view> &params)
+{
+ u64 count = 1;
+ static constexpr u64 MAX_COUNT = 512;
+
+ // if we have a parameter, use it instead */
+ if (params.size() > 0 && !m_console.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_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
-------------------------------------------------*/
-void debugger_commands::execute_next(const std::vector<std::string> &params)
+void debugger_commands::execute_next(const std::vector<std::string_view> &params)
{
m_console.get_visible_cpu()->debug()->go_next_device();
}
@@ -1372,11 +981,11 @@ void debugger_commands::execute_next(const std::vector<std::string> &params)
execute_focus - execute the focus command
-------------------------------------------------*/
-void debugger_commands::execute_focus(const std::vector<std::string> &params)
+void debugger_commands::execute_focus(const std::vector<std::string_view> &params)
{
// validate params
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
// first clear the ignore flag on the focused CPU
@@ -1394,7 +1003,7 @@ void debugger_commands::execute_focus(const std::vector<std::string> &params)
execute_ignore - execute the ignore command
-------------------------------------------------*/
-void debugger_commands::execute_ignore(const std::vector<std::string> &params)
+void debugger_commands::execute_ignore(const std::vector<std::string_view> &params)
{
if (params.empty())
{
@@ -1426,7 +1035,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
// set the ignore flags
@@ -1457,7 +1066,7 @@ void debugger_commands::execute_ignore(const std::vector<std::string> &params)
execute_observe - execute the observe command
-------------------------------------------------*/
-void debugger_commands::execute_observe(const std::vector<std::string> &params)
+void debugger_commands::execute_observe(const std::vector<std::string_view> &params)
{
if (params.empty())
{
@@ -1489,7 +1098,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
// clear the ignore flags
@@ -1505,7 +1114,7 @@ void debugger_commands::execute_observe(const std::vector<std::string> &params)
execute_suspend - suspend execution on cpu
-------------------------------------------------*/
-void debugger_commands::execute_suspend(const std::vector<std::string> &params)
+void debugger_commands::execute_suspend(const std::vector<std::string_view> &params)
{
// if there are no parameters, dump the ignore list
if (params.empty())
@@ -1535,7 +1144,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
for (int paramnum = 0; paramnum < params.size(); paramnum++)
@@ -1564,7 +1173,7 @@ void debugger_commands::execute_suspend(const std::vector<std::string> &params)
execute_resume - Resume execution on CPU
-------------------------------------------------*/
-void debugger_commands::execute_resume(const std::vector<std::string> &params)
+void debugger_commands::execute_resume(const std::vector<std::string_view> &params)
{
// if there are no parameters, dump the ignore list
if (params.empty())
@@ -1594,7 +1203,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> &params)
// validate parameters
for (int paramnum = 0; paramnum < params.size(); paramnum++)
- if (!validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
+ if (!m_console.validate_cpu_parameter(params[paramnum], devicelist[paramnum]))
return;
for (int paramnum = 0; paramnum < params.size(); paramnum++)
@@ -1609,7 +1218,7 @@ void debugger_commands::execute_resume(const std::vector<std::string> &params)
// execute_cpulist - list all CPUs
//-------------------------------------------------
-void debugger_commands::execute_cpulist(const std::vector<std::string> &params)
+void debugger_commands::execute_cpulist(const std::vector<std::string_view> &params)
{
int index = 0;
for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
@@ -1620,20 +1229,29 @@ 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_view> &params)
+{
+ m_console.printf("%s\n", m_machine.time().as_string());
+}
+
/*-------------------------------------------------
execute_comment - add a comment to a line
-------------------------------------------------*/
-void debugger_commands::execute_comment_add(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_add(const std::vector<std::string_view> &params)
{
// param 1 is the address for the comment
u64 address;
- if (!validate_number_parameter(params[0], address))
+ if (!m_console.validate_number_parameter(params[0], address))
return;
// CPU parameter is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// make sure param 2 exists
@@ -1644,7 +1262,8 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> &para
}
// Now try adding the comment
- cpu->debug()->comment_add(address, params[1].c_str(), 0x00ff0000);
+ std::string const text(params[1]);
+ cpu->debug()->comment_add(address, text.c_str(), 0x00ff0000);
cpu->machine().debug_view().update_all(DVT_DISASSEMBLY);
}
@@ -1653,16 +1272,16 @@ void debugger_commands::execute_comment_add(const std::vector<std::string> &para
execute_comment_del - remove a comment from an addr
--------------------------------------------------------*/
-void debugger_commands::execute_comment_del(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_del(const std::vector<std::string_view> &params)
{
// param 1 can either be a command or the address for the comment
u64 address;
- if (!validate_number_parameter(params[0], address))
+ if (!m_console.validate_number_parameter(params[0], address))
return;
// CPU parameter is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// If it's a number, it must be an address
@@ -1672,25 +1291,25 @@ void debugger_commands::execute_comment_del(const std::vector<std::string> &para
}
/**
- * @fn void execute_comment_list(const std::vector<std::string> &params)
+ * @fn void execute_comment_list(const std::vector<std::string_view> &params)
* @brief Print current list of comments in debugger
*
*
*/
-void debugger_commands::execute_comment_list(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_list(const std::vector<std::string_view> &params)
{
if (!m_machine.debugger().cpu().comment_load(false))
m_console.printf("Error while parsing XML file\n");
}
/**
- * @fn void execute_comment_commit(const std::vector<std::string> &params)
+ * @fn void execute_comment_commit(const std::vector<std::string_view> &params)
* @brief Add and Save current list of comments in debugger
*
*/
-void debugger_commands::execute_comment_commit(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_commit(const std::vector<std::string_view> &params)
{
execute_comment_add(params);
execute_comment_save(params);
@@ -1700,7 +1319,7 @@ void debugger_commands::execute_comment_commit(const std::vector<std::string> &p
execute_comment - add a comment to a line
-------------------------------------------------*/
-void debugger_commands::execute_comment_save(const std::vector<std::string> &params)
+void debugger_commands::execute_comment_save(const std::vector<std::string_view> &params)
{
if (m_machine.debugger().cpu().comment_save())
m_console.printf("Comment successfully saved\n");
@@ -1710,7 +1329,7 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par
// TODO: add color hex editing capabilities for comments, see below for more info
/**
- * @fn void execute_comment_color(const std::vector<std::string> &params)
+ * @fn void execute_comment_color(const std::vector<std::string_view> &params)
* @brief Modifies comment given at address $xx with given color
* Useful for marking comment with a different color scheme (for example by marking start and end of a given function visually).
* @param[in] "address,color" First is the comment address in the current context, color can be hexadecimal or shorthanded to common 1bpp RGB names.
@@ -1727,12 +1346,12 @@ void debugger_commands::execute_comment_save(const std::vector<std::string> &par
command
-------------------------------------------------*/
-void debugger_commands::execute_bpset(const std::vector<std::string> &params)
+void debugger_commands::execute_bpset(const std::vector<std::string_view> &params)
{
// param 1 is the address/CPU
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], AS_PROGRAM, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], AS_PROGRAM, space, address))
return;
device_execute_interface const *execute;
@@ -1751,12 +1370,12 @@ void debugger_commands::execute_bpset(const std::vector<std::string> &params)
// param 2 is the condition
parsed_expression condition(debug->symtable());
- if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition))
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
return;
// param 3 is the action
- const char *action = nullptr;
- if (params.size() > 2 && !debug_command_parameter_command(action = params[2].c_str()))
+ std::string_view action;
+ if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2]))
return;
// set the breakpoint
@@ -1770,7 +1389,7 @@ void debugger_commands::execute_bpset(const std::vector<std::string> &params)
clear command
-------------------------------------------------*/
-void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_bpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -1799,7 +1418,7 @@ void debugger_commands::execute_bpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -1828,7 +1447,7 @@ void debugger_commands::execute_bpdisenable(bool enable, const std::vector<std::
command
-------------------------------------------------*/
-void debugger_commands::execute_bplist(const std::vector<std::string> &params)
+void debugger_commands::execute_bplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -1857,7 +1476,7 @@ void debugger_commands::execute_bplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -1879,13 +1498,13 @@ void debugger_commands::execute_bplist(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_wpset(int spacenum, const std::vector<std::string_view> &params)
{
u64 address, length;
address_space *space;
// param 1 is the address/CPU
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
device_execute_interface const *execute;
@@ -1897,31 +1516,35 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
device_debug *const debug = space->device().debug();
// param 2 is the length
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// param 3 is the type
read_or_write type;
- if (!core_stricmp(params[2].c_str(), "r"))
- type = read_or_write::READ;
- else if (!core_stricmp(params[2].c_str(), "w"))
- type = read_or_write::WRITE;
- else if (!core_stricmp(params[2].c_str(), "rw") || !core_stricmp(params[2].c_str(), "wr"))
- type = read_or_write::READWRITE;
- else
{
- m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[2], "r"sv))
+ type = read_or_write::READ;
+ else if (streqlower(params[2], "w"sv))
+ type = read_or_write::WRITE;
+ else if (streqlower(params[2], "rw"sv) || streqlower(params[2], "wr"sv))
+ type = read_or_write::READWRITE;
+ else
+ {
+ m_console.printf("Invalid watchpoint type: expected r, w, or rw\n");
+ return;
+ }
}
// param 4 is the condition
parsed_expression condition(debug->symtable());
- if (params.size() > 3 && !debug_command_parameter_expression(params[3], condition))
+ if (params.size() > 3 && !m_console.validate_expression_parameter(params[3], condition))
return;
// param 5 is the action
- const char *action = nullptr;
- if (params.size() > 4 && !debug_command_parameter_command(action = params[4].c_str()))
+ std::string_view action;
+ if (params.size() > 4 && !m_console.validate_command_parameter(action = params[4]))
return;
// set the watchpoint
@@ -1935,7 +1558,7 @@ void debugger_commands::execute_wpset(int spacenum, const std::vector<std::strin
clear command
-------------------------------------------------*/
-void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_wpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -1964,7 +1587,7 @@ void debugger_commands::execute_wpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -1993,7 +1616,7 @@ void debugger_commands::execute_wpdisenable(bool enable, const std::vector<std::
command
-------------------------------------------------*/
-void debugger_commands::execute_wplist(const std::vector<std::string> &params)
+void debugger_commands::execute_wplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -2034,7 +1657,7 @@ void debugger_commands::execute_wplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -2056,21 +1679,21 @@ void debugger_commands::execute_wplist(const std::vector<std::string> &params)
command
-------------------------------------------------*/
-void debugger_commands::execute_rpset(const std::vector<std::string> &params)
+void debugger_commands::execute_rpset(const std::vector<std::string_view> &params)
{
// CPU is implicit
device_t *cpu;
- if (!validate_cpu_parameter(std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
return;
// param 1 is the condition
parsed_expression condition(cpu->debug()->symtable());
- if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition))
+ if (params.size() > 0 && !m_console.validate_expression_parameter(params[0], condition))
return;
// param 2 is the action
- const char *action = nullptr;
- if (params.size() > 1 && !debug_command_parameter_command(action = params[1].c_str()))
+ std::string_view action;
+ if (params.size() > 1 && !m_console.validate_command_parameter(action = params[1]))
return;
// set the registerpoint
@@ -2084,7 +1707,7 @@ void debugger_commands::execute_rpset(const std::vector<std::string> &params)
clear command
-------------------------------------------------*/
-void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
+void debugger_commands::execute_rpclear(const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, clear all
{
@@ -2113,7 +1736,7 @@ void debugger_commands::execute_rpclear(const std::vector<std::string> &params)
disable/enable commands
-------------------------------------------------*/
-void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string> &params)
+void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::string_view> &params)
{
if (params.empty()) // if no parameters, disable/enable all
{
@@ -2137,12 +1760,154 @@ void debugger_commands::execute_rpdisenable(bool enable, const std::vector<std::
}
+//-------------------------------------------------
+// execute_epset - execute the exception point
+// set command
+//-------------------------------------------------
+
+void debugger_commands::execute_epset(const std::vector<std::string_view> &params)
+{
+ // CPU is implicit
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(std::string_view(), cpu))
+ return;
+
+ // param 1 is the exception type
+ u64 type;
+ if (!m_console.validate_number_parameter(params[0], type))
+ return;
+
+ // param 2 is the condition
+ parsed_expression condition(cpu->debug()->symtable());
+ if (params.size() > 1 && !m_console.validate_expression_parameter(params[1], condition))
+ return;
+
+ // param 3 is the action
+ std::string_view action;
+ if (params.size() > 2 && !m_console.validate_command_parameter(action = params[2]))
+ return;
+
+ // set the exception point
+ int epnum = cpu->debug()->exceptionpoint_set(type, (condition.is_empty()) ? nullptr : condition.original_string(), action);
+ m_console.printf("Exception point %X set\n", epnum);
+}
+
+
+//-------------------------------------------------
+// execute_epclear - execute the exception point
+// clear command
+//-------------------------------------------------
+
+void debugger_commands::execute_epclear(const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, clear all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_clear_all();
+ m_console.printf("Cleared all exception points\n");
+ }
+ else // otherwise, clear the specific ones
+ {
+ execute_index_command(
+ params,
+ [this] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_clear(param))
+ return false;
+ m_console.printf("Exception point %X cleared\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_epdisenable - execute the exception
+// point disable/enable commands
+//-------------------------------------------------
+
+void debugger_commands::execute_epdisenable(bool enable, const std::vector<std::string_view> &params)
+{
+ if (params.empty()) // if no parameters, disable/enable all
+ {
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ device.debug()->exceptionpoint_enable_all(enable);
+ m_console.printf(enable ? "Enabled all exception points\n" : "Disabled all exception points\n");
+ }
+ else // otherwise, disable/enable the specific ones
+ {
+ execute_index_command(
+ params,
+ [this, enable] (device_t &device, u64 param) -> bool
+ {
+ if (!device.debug()->exceptionpoint_enable(param, enable))
+ return false;
+ m_console.printf(enable ? "Exception point %X enabled\n" : "Exception point %X disabled\n", param);
+ return true;
+ },
+ "Invalid exception point number %X\n");
+ }
+}
+
+
+//-------------------------------------------------
+// execute_eplist - execute the exception point
+// list command
+//-------------------------------------------------
+
+void debugger_commands::execute_eplist(const std::vector<std::string_view> &params)
+{
+ int printed = 0;
+ std::string buffer;
+ auto const apply =
+ [this, &printed, &buffer] (device_t &device)
+ {
+ if (!device.debug()->exceptionpoint_list().empty())
+ {
+ m_console.printf("Device '%s' exception points:\n", device.tag());
+
+ // loop over the exception points
+ for (const auto &epp : device.debug()->exceptionpoint_list())
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ buffer = string_format("%c%4X : %X", ep.enabled() ? ' ' : 'D', ep.index(), ep.type());
+ if (std::string(ep.condition()).compare("1") != 0)
+ buffer.append(string_format(" if %s", ep.condition()));
+ if (!ep.action().empty())
+ buffer.append(string_format(" do %s", ep.action()));
+ m_console.printf("%s\n", buffer);
+ printed++;
+ }
+ }
+ };
+
+ if (!params.empty())
+ {
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
+ return;
+ apply(*cpu);
+ if (!printed)
+ m_console.printf("No exception points currently installed for CPU %s\n", cpu->tag());
+ }
+ else
+ {
+ // loop over all CPUs
+ for (device_t &device : device_enumerator(m_machine.root_device()))
+ apply(device);
+ if (!printed)
+ m_console.printf("No exception points currently installed\n");
+ }
+}
+
+
/*-------------------------------------------------
execute_rplist - execute the registerpoint list
command
-------------------------------------------------*/
-void debugger_commands::execute_rplist(const std::vector<std::string> &params)
+void debugger_commands::execute_rplist(const std::vector<std::string_view> &params)
{
int printed = 0;
std::string buffer;
@@ -2157,7 +1922,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
for (const auto &rp : device.debug()->registerpoint_list())
{
buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition());
- if (rp.action() && *rp.action())
+ if (!rp.action().empty())
buffer.append(string_format(" do %s", rp.action()));
m_console.printf("%s\n", buffer);
printed++;
@@ -2168,7 +1933,7 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
if (!params.empty())
{
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
apply(*cpu);
if (!printed)
@@ -2189,10 +1954,9 @@ void debugger_commands::execute_rplist(const std::vector<std::string> &params)
execute_statesave - execute the statesave command
-------------------------------------------------*/
-void debugger_commands::execute_statesave(const std::vector<std::string> &params)
+void debugger_commands::execute_statesave(const std::vector<std::string_view> &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");
}
@@ -2201,10 +1965,9 @@ void debugger_commands::execute_statesave(const std::vector<std::string> &params
execute_stateload - execute the stateload command
-------------------------------------------------*/
-void debugger_commands::execute_stateload(const std::vector<std::string> &params)
+void debugger_commands::execute_stateload(const std::vector<std::string_view> &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()))
@@ -2220,7 +1983,7 @@ void debugger_commands::execute_stateload(const std::vector<std::string> &params
execute_rewind - execute the rewind command
-------------------------------------------------*/
-void debugger_commands::execute_rewind(const std::vector<std::string> &params)
+void debugger_commands::execute_rewind(const std::vector<std::string_view> &params)
{
bool success = m_machine.rewind_step();
if (success)
@@ -2239,15 +2002,15 @@ void debugger_commands::execute_rewind(const std::vector<std::string> &params)
execute_save - execute the save command
-------------------------------------------------*/
-void debugger_commands::execute_save(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_save(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, endoffset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
// determine the addresses to write
@@ -2256,7 +2019,8 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
endoffset++;
// open the file
- FILE *const f = fopen(params[0].c_str(), "wb");
+ std::string const filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "wb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2271,8 +2035,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u64 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_qword(curaddr) : space->unmap();
+ address_space *tspace;
+ u64 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_qword(curaddr) : space->unmap();
fwrite(&data, 8, 1, f);
}
break;
@@ -2280,8 +2045,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u32 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_dword(curaddr) : space->unmap();
+ address_space *tspace;
+ u32 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_dword(curaddr) : space->unmap();
fwrite(&data, 4, 1, f);
}
break;
@@ -2289,8 +2055,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_word(curaddr) : space->unmap();
+ address_space *tspace;
+ u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_word(curaddr) : space->unmap();
fwrite(&data, 2, 1, f);
}
break;
@@ -2298,8 +2065,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i++)
{
offs_t curaddr = i;
- u8 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_byte(curaddr) : space->unmap();
+ address_space *tspace;
+ u8 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_byte(curaddr) : space->unmap();
fwrite(&data, 1, 1, f);
}
break;
@@ -2309,8 +2077,9 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
for (u64 i = offset; i != endoffset; i+=16)
{
offs_t curaddr = i;
- u16 data = space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr) ?
- space->read_word(curaddr) : space->unmap();
+ address_space *tspace;
+ u16 data = space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace) ?
+ tspace->read_word(curaddr) : space->unmap();
fwrite(&data, 2, 1, f);
}
break;
@@ -2326,17 +2095,17 @@ void debugger_commands::execute_save(int spacenum, const std::vector<std::string
execute_saveregion - execute the save command on region memory
-------------------------------------------------*/
-void debugger_commands::execute_saveregion(const std::vector<std::string> &params)
+void debugger_commands::execute_saveregion(const std::vector<std::string_view> &params)
{
u64 offset, length;
memory_region *region;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (!validate_memory_region_parameter(params[3], region))
+ if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes())
@@ -2348,7 +2117,8 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> &param
length = region->bytes() - offset;
/* open the file */
- FILE *f = fopen(params[0].c_str(), "wb");
+ std::string const filename(params[0]);
+ FILE *f = fopen(filename.c_str(), "wb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2365,20 +2135,21 @@ void debugger_commands::execute_saveregion(const std::vector<std::string> &param
execute_load - execute the load command
-------------------------------------------------*/
-void debugger_commands::execute_load(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_load(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, endoffset, length = 0;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
- if (params.size() > 2 && !validate_number_parameter(params[2], length))
+ if (params.size() > 2 && !m_console.validate_number_parameter(params[2], length))
return;
// open the file
std::ifstream f;
- f.open(params[0], std::ifstream::in | std::ifstream::binary);
+ std::string const fname(params[0]);
+ f.open(fname, std::ifstream::in | std::ifstream::binary);
if (f.fail())
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2412,8 +2183,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u64 data;
f.read((char *)&data, 8);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_qword(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_qword(curaddr, data);
}
break;
case -2:
@@ -2422,8 +2194,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u32 data;
f.read((char *)&data, 4);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_dword(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_dword(curaddr, data);
}
break;
case -1:
@@ -2432,8 +2205,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u16 data;
f.read((char *)&data, 2);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_word(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_word(curaddr, data);
}
break;
case 0:
@@ -2442,8 +2216,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u8 data;
f.read((char *)&data, 1);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_byte(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_byte(curaddr, data);
}
break;
case 3:
@@ -2454,8 +2229,9 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
offs_t curaddr = i;
u16 data;
f.read((char *)&data, 2);
- if (f && space->device().memory().translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, curaddr))
- space->write_word(curaddr, data);
+ address_space *tspace;
+ if (f && space->device().memory().translate(space->spacenum(), device_memory_interface::TR_WRITE, curaddr, tspace))
+ tspace->write_word(curaddr, data);
}
break;
}
@@ -2473,17 +2249,17 @@ void debugger_commands::execute_load(int spacenum, const std::vector<std::string
execute_loadregion - execute the load command on region memory
-------------------------------------------------*/
-void debugger_commands::execute_loadregion(const std::vector<std::string> &params)
+void debugger_commands::execute_loadregion(const std::vector<std::string_view> &params)
{
u64 offset, length;
memory_region *region;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (!validate_memory_region_parameter(params[3], region))
+ if (!m_console.validate_memory_region_parameter(params[3], region))
return;
if (offset >= region->bytes())
@@ -2495,7 +2271,8 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> &param
length = region->bytes() - offset;
// open the file
- FILE *const f = fopen(params[0].c_str(), "rb");
+ std::string filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "rb");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2521,28 +2298,28 @@ void debugger_commands::execute_loadregion(const std::vector<std::string> &param
execute_dump - execute the dump command
-------------------------------------------------*/
-void debugger_commands::execute_dump(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_dump(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
address_space *space;
u64 offset;
- if (!validate_target_address_parameter(params[1], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[1], spacenum, space, offset))
return;
u64 length;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
u64 width = 0;
- if (params.size() > 3 && !validate_number_parameter(params[3], width))
+ if (params.size() > 3 && !m_console.validate_number_parameter(params[3], width))
return;
bool ascii = true;
- if (params.size() > 4 && !validate_boolean_parameter(params[4], ascii))
+ if (params.size() > 4 && !m_console.validate_boolean_parameter(params[4], ascii))
return;
u64 rowsize = space->byte_to_address(16);
- if (params.size() > 5 && !validate_number_parameter(params[5], rowsize))
+ if (params.size() > 5 && !m_console.validate_number_parameter(params[5], rowsize))
return;
int shift = space->addr_shift();
@@ -2573,7 +2350,8 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
offset = offset & space->addrmask();
// open the file
- FILE *const f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ FILE *const f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2603,21 +2381,22 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
if (i + j <= endoffset)
{
offs_t curaddr = i + j;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
switch (width)
{
case 8:
- util::stream_format(output, " %016X", space->read_qword_unaligned(i+j));
+ util::stream_format(output, " %016X", tspace->read_qword_unaligned(i+j));
break;
case 4:
- util::stream_format(output, " %08X", space->read_dword_unaligned(i+j));
+ util::stream_format(output, " %08X", tspace->read_dword_unaligned(i+j));
break;
case 2:
- util::stream_format(output, " %04X", space->read_word_unaligned(i+j));
+ util::stream_format(output, " %04X", tspace->read_word_unaligned(i+j));
break;
case 1:
- util::stream_format(output, " %02X", space->read_byte(i+j));
+ util::stream_format(output, " %02X", tspace->read_byte(i+j));
break;
}
}
@@ -2637,22 +2416,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
for (u64 j = 0; j < rowsize && (i + j) <= endoffset; j += delta)
{
offs_t curaddr = i + j;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
u64 data = 0;
switch (width)
{
case 8:
- data = space->read_qword_unaligned(i+j);
+ data = tspace->read_qword_unaligned(i+j);
break;
case 4:
- data = space->read_dword_unaligned(i+j);
+ data = tspace->read_dword_unaligned(i+j);
break;
case 2:
- data = space->read_word_unaligned(i+j);
+ data = tspace->read_word_unaligned(i+j);
break;
case 1:
- data = space->read_byte(i+j);
+ data = tspace->read_byte(i+j);
break;
}
for (unsigned int b = 0; b != width; b++) {
@@ -2682,23 +2462,23 @@ void debugger_commands::execute_dump(int spacenum, const std::vector<std::string
// execute_strdump - execute the strdump command
//-------------------------------------------------
-void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_strdump(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
u64 offset;
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
u64 length;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
u64 term = 0;
- if (params.size() > 3 && !validate_number_parameter(params[3], term))
+ if (params.size() > 3 && !m_console.validate_number_parameter(params[3], term))
return;
address_space *space;
- if (!validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space))
+ if (!m_console.validate_device_space_parameter((params.size() > 4) ? params[4] : std::string_view(), spacenum, space))
return;
// further validation
@@ -2709,7 +2489,8 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
}
// open the file
- FILE *f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ FILE *f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -2747,28 +2528,29 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
// get the character data
u64 data = 0;
offs_t curaddr = offset;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, curaddr, tspace))
{
switch (width)
{
case 1:
- data = space->read_byte(curaddr);
+ data = tspace->read_byte(curaddr);
break;
case 2:
- data = space->read_word(curaddr);
+ data = tspace->read_word(curaddr);
if (be)
data = swapendian_int16(data);
break;
case 4:
- data = space->read_dword(curaddr);
+ data = tspace->read_dword(curaddr);
if (be)
data = swapendian_int32(data);
break;
case 8:
- data = space->read_qword(curaddr);
+ data = tspace->read_qword(curaddr);
if (be)
data = swapendian_int64(data);
break;
@@ -2858,7 +2640,7 @@ void debugger_commands::execute_strdump(int spacenum, const std::vector<std::str
cheats
-------------------------------------------------*/
-void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string> &params)
+void debugger_commands::execute_cheatrange(bool init, const std::vector<std::string_view> &params)
{
address_space *space = m_cheat.space;
if (!space && !init)
@@ -2875,7 +2657,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
// first argument is sign/size/swap flags
if (!params.empty())
{
- std::string const &srtpnt = params[0];
+ std::string_view const &srtpnt = params[0];
if (!srtpnt.empty())
{
width = 1;
@@ -2928,7 +2710,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
}
// fourth argument is device/space
- if (!validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
+ if (!m_console.validate_device_space_parameter((params.size() > 3) ? params[3] : std::string_view(), -1, space))
return;
}
@@ -2938,9 +2720,9 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
{
// validate parameters
u64 offset, length;
- if (!validate_number_parameter(params[init ? 1 : 0], offset))
+ if (!m_console.validate_number_parameter(params[init ? 1 : 0], offset))
return;
- if (!validate_number_parameter(params[init ? 2 : 1], length))
+ if (!m_console.validate_number_parameter(params[init ? 2 : 1], length))
return;
// force region to the specified range
@@ -3027,7 +2809,7 @@ void debugger_commands::execute_cheatrange(bool init, const std::vector<std::str
execute_cheatnext - execute the search
-------------------------------------------------*/
-void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string> &params)
+void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::string_view> &params)
{
enum
{
@@ -3055,36 +2837,40 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
}
u64 comp_value = 0;
- if (params.size() > 1 && !validate_number_parameter(params[1], comp_value))
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], comp_value))
return;
comp_value = m_cheat.sign_extend(comp_value);
// decode condition
u8 condition;
- if (!core_stricmp(params[0].c_str(), "all"))
- condition = CHEAT_ALL;
- else if (!core_stricmp(params[0].c_str(), "equal") || !core_stricmp(params[0].c_str(), "eq"))
- condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "notequal") || !core_stricmp(params[0].c_str(), "ne"))
- condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
- else if (!core_stricmp(params[0].c_str(), "decrease") || !core_stricmp(params[0].c_str(), "de") || params[0] == "-")
- condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
- else if (!core_stricmp(params[0].c_str(), "increase") || !core_stricmp(params[0].c_str(), "in") || params[0] == "+")
- condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
- else if (!core_stricmp(params[0].c_str(), "decreaseorequal") || !core_stricmp(params[0].c_str(), "deeq"))
- condition = CHEAT_DECREASE_OR_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "increaseorequal") || !core_stricmp(params[0].c_str(), "ineq"))
- condition = CHEAT_INCREASE_OR_EQUAL;
- else if (!core_stricmp(params[0].c_str(), "smallerof") || !core_stricmp(params[0].c_str(), "lt") || params[0] == "<")
- condition = CHEAT_SMALLEROF;
- else if (!core_stricmp(params[0].c_str(), "greaterof") || !core_stricmp(params[0].c_str(), "gt") || params[0] == ">")
- condition = CHEAT_GREATEROF;
- else if (!core_stricmp(params[0].c_str(), "changedby") || !core_stricmp(params[0].c_str(), "ch") || params[0] == "~")
- condition = CHEAT_CHANGEDBY;
- else
{
- m_console.printf("Invalid condition type\n");
- return;
+ using util::streqlower;
+ using namespace std::literals;
+ if (streqlower(params[0], "all"sv))
+ condition = CHEAT_ALL;
+ else if (streqlower(params[0], "equal"sv) || streqlower(params[0], "eq"sv))
+ condition = (params.size() > 1) ? CHEAT_EQUALTO : CHEAT_EQUAL;
+ else if (streqlower(params[0], "notequal"sv) || streqlower(params[0], "ne"sv))
+ condition = (params.size() > 1) ? CHEAT_NOTEQUALTO : CHEAT_NOTEQUAL;
+ else if (streqlower(params[0], "decrease"sv) || streqlower(params[0], "de"sv) || params[0] == "-"sv)
+ condition = (params.size() > 1) ? CHEAT_DECREASEOF : CHEAT_DECREASE;
+ else if (streqlower(params[0], "increase"sv) || streqlower(params[0], "in"sv) || params[0] == "+"sv)
+ condition = (params.size() > 1) ? CHEAT_INCREASEOF : CHEAT_INCREASE;
+ else if (streqlower(params[0], "decreaseorequal"sv) || streqlower(params[0], "deeq"sv))
+ condition = CHEAT_DECREASE_OR_EQUAL;
+ else if (streqlower(params[0], "increaseorequal"sv) || streqlower(params[0], "ineq"sv))
+ condition = CHEAT_INCREASE_OR_EQUAL;
+ else if (streqlower(params[0], "smallerof"sv) || streqlower(params[0], "lt"sv) || params[0] == "<"sv)
+ condition = CHEAT_SMALLEROF;
+ else if (streqlower(params[0], "greaterof"sv) || streqlower(params[0], "gt"sv) || params[0] == ">"sv)
+ condition = CHEAT_GREATEROF;
+ else if (streqlower(params[0], "changedby"sv) || streqlower(params[0], "ch"sv) || params[0] == "~"sv)
+ condition = CHEAT_CHANGEDBY;
+ else
+ {
+ m_console.printf("Invalid condition type\n");
+ return;
+ }
}
m_cheat.undo++;
@@ -3191,7 +2977,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
}
if (active_cheat <= 5)
- execute_cheatlist(std::vector<std::string>());
+ execute_cheatlist(std::vector<std::string_view>());
m_console.printf("%u cheats found\n", active_cheat);
}
@@ -3201,7 +2987,7 @@ void debugger_commands::execute_cheatnext(bool initial, const std::vector<std::s
execute_cheatlist - show a list of active cheat
-------------------------------------------------*/
-void debugger_commands::execute_cheatlist(const std::vector<std::string> &params)
+void debugger_commands::execute_cheatlist(const std::vector<std::string_view> &params)
{
address_space *const space = m_cheat.space;
if (!space)
@@ -3213,7 +2999,8 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> &params
FILE *f = nullptr;
if (params.size() > 0)
{
- f = fopen(params[0].c_str(), "w");
+ std::string filename(params[0]);
+ f = fopen(filename.c_str(), "w");
if (!f)
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -3318,7 +3105,7 @@ void debugger_commands::execute_cheatlist(const std::vector<std::string> &params
execute_cheatundo - undo the last search
-------------------------------------------------*/
-void debugger_commands::execute_cheatundo(const std::vector<std::string> &params)
+void debugger_commands::execute_cheatundo(const std::vector<std::string_view> &params)
{
if (m_cheat.undo > 0)
{
@@ -3347,15 +3134,15 @@ void debugger_commands::execute_cheatundo(const std::vector<std::string> &params
execute_find - execute the find command
-------------------------------------------------*/
-void debugger_commands::execute_find(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_find(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[0], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// further validation
@@ -3371,11 +3158,11 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
- char const *pdata = params[i].c_str();
- auto const pdatalen = params[i].length() - 1;
+ std::string_view pdata = params[i];
- if (pdata[0] == '"' && pdata[pdatalen] == '"') // check for a string
+ if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"') // check for a string
{
+ auto const pdatalen = params[i].length() - 1;
for (int j = 1; j < pdatalen; j++)
{
data_to_find[data_count] = pdata[j];
@@ -3386,17 +3173,20 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
{
// check for a 'b','w','d',or 'q' prefix
data_size[data_count] = cur_data_size;
- if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata += 2; }
+ if (pdata.length() >= 2)
+ {
+ if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
+ }
// look for a wildcard
- if (!strcmp(pdata, "?"))
+ if (pdata == "?")
data_size[data_count++] |= 0x10;
// otherwise, validate as a number
- else if (!validate_number_parameter(pdata, data_to_find[data_count++]))
+ else if (!m_console.validate_number_parameter(pdata, data_to_find[data_count++]))
return;
}
}
@@ -3414,36 +3204,37 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
for (int j = 0; j < data_count && match; j++)
{
offs_t address = space->byte_to_address(i + suboffset);
+ address_space *tspace;
switch (data_size[j])
{
case 1:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_byte(address) == u8(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_byte(address) == u8(data_to_find[j]);
else
match = false;
break;
case 2:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_word_unaligned(address) == u16(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_word_unaligned(address) == u16(data_to_find[j]);
else
match = false;
break;
case 4:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_dword_unaligned(address) == u32(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_dword_unaligned(address) == u32(data_to_find[j]);
else
match = false;
break;
case 8:
address &= space->logaddrmask();
- if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address))
- match = space->read_qword_unaligned(address) == u64(data_to_find[j]);
+ if (memory.translate(space->spacenum(), device_memory_interface::TR_READ, address, tspace))
+ match = tspace->read_qword_unaligned(address) == u64(data_to_find[j]);
else
match = false;
break;
@@ -3473,15 +3264,15 @@ void debugger_commands::execute_find(int spacenum, const std::vector<std::string
// execute_fill - execute the fill command
//-------------------------------------------------
-void debugger_commands::execute_fill(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_fill(int spacenum, const std::vector<std::string_view> &params)
{
u64 offset, length;
address_space *space;
// validate parameters
- if (!validate_target_address_parameter(params[0], spacenum, space, offset))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, offset))
return;
- if (!validate_number_parameter(params[1], length))
+ if (!m_console.validate_number_parameter(params[1], length))
return;
// further validation
@@ -3496,12 +3287,12 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
int data_count = 0;
for (int i = 2; i < params.size(); i++)
{
- const char *pdata = params[i].c_str();
- size_t pdatalen = strlen(pdata) - 1;
+ std::string_view pdata = params[i];
// check for a string
- if (pdata[0] == '"' && pdata[pdatalen] == '"')
+ if (!pdata.empty() && pdata.front() == '"' && pdata.back() == '"')
{
+ auto const pdatalen = pdata.length() - 1;
for (int j = 1; j < pdatalen; j++)
{
fill_data[data_count] = pdata[j];
@@ -3514,13 +3305,16 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
{
// check for a 'b','w','d',or 'q' prefix
fill_data_size[data_count] = cur_data_size;
- if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata += 2; }
- if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata += 2; }
+ if (pdata.length() >= 2)
+ {
+ if (tolower(u8(pdata[0])) == 'b' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 1; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'w' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 2; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'd' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 4; pdata.remove_prefix(2); }
+ if (tolower(u8(pdata[0])) == 'q' && pdata[1] == '.') { fill_data_size[data_count] = cur_data_size = 8; pdata.remove_prefix(2); }
+ }
// validate as a number
- if (!validate_number_parameter(pdata, fill_data[data_count++]))
+ if (!m_console.validate_number_parameter(pdata, fill_data[data_count++]))
return;
}
}
@@ -3537,7 +3331,8 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
for (int j = 0; j < data_count; j++)
{
offs_t address = space->byte_to_address(offset) & space->logaddrmask();
- if (!memory.translate(space->spacenum(), TRANSLATE_WRITE_DEBUG, address))
+ address_space *tspace;
+ if (!memory.translate(space->spacenum(), device_memory_interface::TR_WRITE, address, tspace))
{
m_console.printf("Fill aborted due to page fault at %0*X\n", space->logaddrchars(), space->byte_to_address(offset) & space->logaddrmask());
length = 0;
@@ -3546,19 +3341,19 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
switch (fill_data_size[j])
{
case 1:
- space->write_byte(address, fill_data[j]);
+ tspace->write_byte(address, fill_data[j]);
break;
case 2:
- space->write_word_unaligned(address, fill_data[j]);
+ tspace->write_word_unaligned(address, fill_data[j]);
break;
case 4:
- space->write_dword_unaligned(address, fill_data[j]);
+ tspace->write_dword_unaligned(address, fill_data[j]);
break;
case 8:
- space->read_qword_unaligned(address, fill_data[j]);
+ tspace->read_qword_unaligned(address, fill_data[j]);
break;
}
offset += fill_data_size[j];
@@ -3578,20 +3373,20 @@ void debugger_commands::execute_fill(int spacenum, const std::vector<std::string
execute_dasm - execute the dasm command
-------------------------------------------------*/
-void debugger_commands::execute_dasm(const std::vector<std::string> &params)
+void debugger_commands::execute_dasm(const std::vector<std::string_view> &params)
{
u64 offset, length;
bool bytes = true;
address_space *space;
// validate parameters
- if (!validate_number_parameter(params[1], offset))
+ if (!m_console.validate_number_parameter(params[1], offset))
return;
- if (!validate_number_parameter(params[2], length))
+ if (!m_console.validate_number_parameter(params[2], length))
return;
- if (params.size() > 3 && !validate_boolean_parameter(params[3], bytes))
+ if (params.size() > 3 && !m_console.validate_boolean_parameter(params[3], bytes))
return;
- if (!validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space))
+ if (!m_console.validate_device_space_parameter(params.size() > 4 ? params[4] : std::string_view(), AS_PROGRAM, space))
return;
// determine the width of the bytes
@@ -3637,7 +3432,8 @@ void debugger_commands::execute_dasm(const std::vector<std::string> &params)
}
/* write the data */
- std::ofstream f(params[0]);
+ std::string fname(params[0]);
+ std::ofstream f(fname);
if (!f.good())
{
m_console.printf("Error opening file '%s'\n", params[0]);
@@ -3676,32 +3472,32 @@ void debugger_commands::execute_dasm(const std::vector<std::string> &params)
trace over and trace info
-------------------------------------------------*/
-void debugger_commands::execute_trace(const std::vector<std::string> &params, bool trace_over)
+void debugger_commands::execute_trace(const std::vector<std::string_view> &params, bool trace_over)
{
- const char *action = nullptr;
+ std::string_view action;
bool detect_loops = true;
bool logerror = false;
- device_t *cpu;
- const char *mode;
- std::string filename = params[0];
+ std::string filename(params[0]);
// replace macros
strreplace(filename, "{game}", m_machine.basename());
// validate parameters
- if (!validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu))
+ device_t *cpu;
+ if (!m_console.validate_cpu_parameter(params.size() > 1 ? params[1] : std::string_view(), cpu))
return;
if (params.size() > 2)
{
std::stringstream stream;
- stream.str(params[2]);
+ stream.str(std::string(params[2]));
std::string flag;
while (std::getline(stream, flag, '|'))
{
- if (!core_stricmp(flag.c_str(), "noloop"))
+ using namespace std::literals;
+ if (util::streqlower(flag, "noloop"sv))
detect_loops = false;
- else if (!core_stricmp(flag.c_str(), "logerror"))
+ else if (util::streqlower(flag, "logerror"sv))
logerror = true;
else
{
@@ -3710,24 +3506,27 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
}
}
}
- if (!debug_command_parameter_command(action = (params.size() > 3) ? params[3].c_str() : nullptr))
+ if (params.size() > 3 && !m_console.validate_command_parameter(action = params[3]))
return;
// open the file
- FILE *f = nullptr;
- if (core_stricmp(filename.c_str(), "off") != 0)
+ std::unique_ptr<std::ofstream> f;
+ using namespace std::literals;
+ if (!util::streqlower(filename, "off"sv))
{
- mode = "w";
+ std::ios_base::openmode mode = std::ios_base::out;
// opening for append?
if ((filename[0] == '>') && (filename[1] == '>'))
{
- mode = "a";
+ mode |= std::ios_base::ate;
filename = filename.substr(2);
}
+ else
+ mode |= std::ios_base::trunc;
- f = fopen(filename.c_str(), mode);
- if (!f)
+ f = std::make_unique<std::ofstream>(filename.c_str(), mode);
+ if (f->fail())
{
m_console.printf("Error opening file '%s'\n", params[0]);
return;
@@ -3735,8 +3534,9 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
}
// do it
- cpu->debug()->trace(f, trace_over, detect_loops, logerror, action);
- if (f)
+ bool const on(f);
+ cpu->debug()->trace(std::move(f), trace_over, detect_loops, logerror, action);
+ if (on)
m_console.printf("Tracing CPU '%s' to file %s\n", cpu->tag(), filename);
else
m_console.printf("Stopped tracing on CPU '%s'\n", cpu->tag());
@@ -3747,7 +3547,7 @@ void debugger_commands::execute_trace(const std::vector<std::string> &params, bo
execute_traceflush - execute the trace flush command
-------------------------------------------------*/
-void debugger_commands::execute_traceflush(const std::vector<std::string> &params)
+void debugger_commands::execute_traceflush(const std::vector<std::string_view> &params)
{
m_machine.debugger().cpu().flush_traces();
}
@@ -3757,15 +3557,15 @@ void debugger_commands::execute_traceflush(const std::vector<std::string> &param
execute_history - execute the history command
-------------------------------------------------*/
-void debugger_commands::execute_history(const std::vector<std::string> &params)
+void debugger_commands::execute_history(const std::vector<std::string_view> &params)
{
// validate parameters
device_t *device;
- if (!validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device))
+ if (!m_console.validate_cpu_parameter(!params.empty() ? params[0] : std::string_view(), device))
return;
u64 count = device_debug::HISTORY_SIZE;
- if (params.size() > 1 && !validate_number_parameter(params[1], count))
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], count))
return;
// further validation
@@ -3782,13 +3582,13 @@ void debugger_commands::execute_history(const std::vector<std::string> &params)
}
// loop over lines
- debug_disasm_buffer buffer(*device);
std::string instruction;
for (int index = int(unsigned(count)); index > 0; index--)
{
auto const pc = debug->history_pc(1 - index);
if (pc.second)
{
+ debug_disasm_buffer buffer(*device);
offs_t next_offset;
offs_t size;
u32 info;
@@ -3805,16 +3605,16 @@ void debugger_commands::execute_history(const std::vector<std::string> &params)
execute_trackpc - execute the trackpc command
-------------------------------------------------*/
-void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
+void debugger_commands::execute_trackpc(const std::vector<std::string_view> &params)
{
// Gather the on/off switch (if present)
bool turnOn = true;
- if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn))
+ if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn))
return;
// Gather the cpu id (if present)
device_t *cpu = nullptr;
- if (!validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu))
+ if (!m_console.validate_cpu_parameter((params.size() > 1) ? params[1] : std::string_view(), cpu))
return;
const device_state_interface *state;
@@ -3826,7 +3626,7 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
// Should we clear the existing data?
bool clear = false;
- if (params.size() > 2 && !validate_boolean_parameter(params[2], clear))
+ if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear))
return;
cpu->debug()->set_track_pc((bool)turnOn);
@@ -3854,11 +3654,11 @@ void debugger_commands::execute_trackpc(const std::vector<std::string> &params)
execute_trackmem - execute the trackmem command
-------------------------------------------------*/
-void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
+void debugger_commands::execute_trackmem(const std::vector<std::string_view> &params)
{
// Gather the on/off switch (if present)
bool turnOn = true;
- if (params.size() > 0 && !validate_boolean_parameter(params[0], turnOn))
+ if (params.size() > 0 && !m_console.validate_boolean_parameter(params[0], turnOn))
return;
// Gather the cpu id (if present)
@@ -3866,17 +3666,17 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
if (params.size() > 1)
cpuparam = params[1];
device_t *cpu = nullptr;
- if (!validate_cpu_parameter(cpuparam, cpu))
+ if (!m_console.validate_cpu_parameter(cpuparam, cpu))
return;
// Should we clear the existing data?
bool clear = false;
- if (params.size() > 2 && !validate_boolean_parameter(params[2], clear))
+ if (params.size() > 2 && !m_console.validate_boolean_parameter(params[2], clear))
return;
// Get the address space for the given cpu
address_space *space;
- if (!validate_device_space_parameter(cpuparam, AS_PROGRAM, space))
+ if (!m_console.validate_device_space_parameter(cpuparam, AS_PROGRAM, space))
return;
// Inform the CPU it's time to start tracking memory writes
@@ -3892,17 +3692,18 @@ void debugger_commands::execute_trackmem(const std::vector<std::string> &params)
execute_pcatmem - execute the pcatmem command
-------------------------------------------------*/
-void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::string_view> &params)
{
// Gather the required target address/space parameter
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
// Translate the address
offs_t a = address & space->logaddrmask();
- if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a))
+ address_space *tspace;
+ if (!space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, a, tspace))
{
m_console.printf("Address translation failed\n");
return;
@@ -3914,19 +3715,19 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str
switch (space->data_width())
{
case 8:
- data = space->read_byte(a);
+ data = tspace->read_byte(a);
break;
case 16:
- data = space->read_word_unaligned(a);
+ data = tspace->read_word_unaligned(a);
break;
case 32:
- data = space->read_dword_unaligned(a);
+ data = tspace->read_dword_unaligned(a);
break;
case 64:
- data = space->read_qword_unaligned(a);
+ data = tspace->read_qword_unaligned(a);
break;
}
@@ -3943,7 +3744,7 @@ void debugger_commands::execute_pcatmem(int spacenum, const std::vector<std::str
execute_snap - execute the snapshot command
-------------------------------------------------*/
-void debugger_commands::execute_snap(const std::vector<std::string> &params)
+void debugger_commands::execute_snap(const std::vector<std::string_view> &params)
{
/* if no params, use the default behavior */
if (params.empty())
@@ -3955,8 +3756,9 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
/* otherwise, we have to open the file ourselves */
else
{
- const char *filename = params[0].c_str();
- int scrnum = (params.size() > 1) ? atoi(params[1].c_str()) : 0;
+ u64 scrnum = 0;
+ if (params.size() > 1 && !m_console.validate_number_parameter(params[1], scrnum))
+ return;
screen_device_enumerator iter(m_machine.root_device());
screen_device *screen = iter.byindex(scrnum);
@@ -3967,7 +3769,7 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
return;
}
- std::string fname(filename);
+ std::string fname(params[0]);
if (fname.find(".png") == -1)
fname.append(".png");
emu_file file(m_machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
@@ -3975,12 +3777,12 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
if (filerr)
{
- m_console.printf("Error creating file '%s' (%s:%d %s)\n", filename, filerr.category().name(), filerr.value(), filerr.message());
+ m_console.printf("Error creating file '%s' (%s:%d %s)\n", params[0], filerr.category().name(), filerr.value(), filerr.message());
return;
}
screen->machine().video().save_snapshot(screen, file);
- m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, filename);
+ m_console.printf("Saved screen #%d snapshot as '%s'\n", scrnum, params[0]);
}
}
@@ -3989,9 +3791,10 @@ void debugger_commands::execute_snap(const std::vector<std::string> &params)
execute_source - execute the source command
-------------------------------------------------*/
-void debugger_commands::execute_source(const std::vector<std::string> &params)
+void debugger_commands::execute_source(const std::vector<std::string_view> &params)
{
- m_console.source_script(params[0].c_str());
+ std::string filename(params[0]);
+ m_console.source_script(filename.c_str());
}
@@ -3999,27 +3802,29 @@ void debugger_commands::execute_source(const std::vector<std::string> &params)
execute_map - execute the map command
-------------------------------------------------*/
-void debugger_commands::execute_map(int spacenum, const std::vector<std::string> &params)
+void debugger_commands::execute_map(int spacenum, const std::vector<std::string_view> &params)
{
// validate parameters
u64 address;
address_space *space;
- if (!validate_target_address_parameter(params[0], spacenum, space, address))
+ if (!m_console.validate_target_address_parameter(params[0], spacenum, space, address))
return;
+ address &= space->logaddrmask();
// do the translation first
- for (int intention = TRANSLATE_READ_DEBUG; intention <= TRANSLATE_FETCH_DEBUG; intention++)
+ for (int intention = device_memory_interface::TR_READ; intention <= device_memory_interface::TR_FETCH; intention++)
{
static const char *const intnames[] = { "Read", "Write", "Fetch" };
- offs_t taddress = address & space->addrmask();
- if (space->device().memory().translate(space->spacenum(), intention, taddress))
+ offs_t taddress = address;
+ address_space *tspace;
+ if (space->device().memory().translate(space->spacenum(), intention, taddress, tspace))
{
- std::string mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress);
+ std::string mapname = tspace->get_handler_string((intention == device_memory_interface::TR_WRITE) ? read_or_write::WRITE : read_or_write::READ, taddress);
m_console.printf(
- "%7s: %0*X logical == %0*X physical -> %s\n",
+ "%7s: %0*X logical %s == %0*X physical %s -> %s\n",
intnames[intention & 3],
- space->logaddrchars(), address,
- space->addrchars(), taddress,
+ space->logaddrchars(), address, space->name(),
+ tspace->addrchars(), taddress, tspace->name(),
mapname);
}
else
@@ -4032,14 +3837,15 @@ void debugger_commands::execute_map(int spacenum, const std::vector<std::string>
execute_memdump - execute the memdump command
-------------------------------------------------*/
-void debugger_commands::execute_memdump(const std::vector<std::string> &params)
+void debugger_commands::execute_memdump(const std::vector<std::string_view> &params)
{
device_t *root = &m_machine.root_device();
- if ((params.size() >= 2) && !validate_device_parameter(params[1], root))
+ if ((params.size() >= 2) && !m_console.validate_device_parameter(params[1], root))
return;
- char const *const filename = params.empty() ? "memdump.log" : params[0].c_str();
- FILE *const file = fopen(filename, "w");
+ using namespace std::literals;
+ std::string filename = params.empty() ? "memdump.log"s : std::string(params[0]);
+ FILE *const file = fopen(filename.c_str(), "w");
if (!file)
{
m_console.printf("Error opening file %s\n", filename);
@@ -4098,7 +3904,7 @@ void debugger_commands::execute_memdump(const std::vector<std::string> &params)
execute_symlist - execute the symlist command
-------------------------------------------------*/
-void debugger_commands::execute_symlist(const std::vector<std::string> &params)
+void debugger_commands::execute_symlist(const std::vector<std::string_view> &params)
{
const char *namelist[1000];
symbol_table *symtable;
@@ -4108,7 +3914,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> &params)
{
// validate parameters
device_t *cpu;
- if (!validate_cpu_parameter(params[0], cpu))
+ if (!m_console.validate_cpu_parameter(params[0], cpu))
return;
symtable = &cpu->debug()->symtable();
m_console.printf("CPU '%s' symbols:\n", cpu->tag());
@@ -4160,7 +3966,7 @@ void debugger_commands::execute_symlist(const std::vector<std::string> &params)
execute_softreset - execute the softreset command
-------------------------------------------------*/
-void debugger_commands::execute_softreset(const std::vector<std::string> &params)
+void debugger_commands::execute_softreset(const std::vector<std::string_view> &params)
{
m_machine.schedule_soft_reset();
}
@@ -4170,7 +3976,7 @@ void debugger_commands::execute_softreset(const std::vector<std::string> &params
execute_hardreset - execute the hardreset command
-------------------------------------------------*/
-void debugger_commands::execute_hardreset(const std::vector<std::string> &params)
+void debugger_commands::execute_hardreset(const std::vector<std::string_view> &params)
{
m_machine.schedule_hard_reset();
}
@@ -4180,7 +3986,7 @@ void debugger_commands::execute_hardreset(const std::vector<std::string> &params
mounted files
-------------------------------------------------*/
-void debugger_commands::execute_images(const std::vector<std::string> &params)
+void debugger_commands::execute_images(const std::vector<std::string_view> &params)
{
image_interface_enumerator iter(m_machine.root_device());
for (device_image_interface &img : iter)
@@ -4210,16 +4016,25 @@ void debugger_commands::execute_images(const std::vector<std::string> &params)
execute_mount - execute the image mount command
-------------------------------------------------*/
-void debugger_commands::execute_mount(const std::vector<std::string> &params)
+void debugger_commands::execute_mount(const std::vector<std::string_view> &params)
{
for (device_image_interface &img : image_interface_enumerator(m_machine.root_device()))
{
if ((img.instance_name() == params[0]) || (img.brief_instance_name() == params[0]))
{
- if (img.load(params[1]) != image_init_result::PASS)
- m_console.printf("Unable to mount file %s on %s\n", params[1], params[0]);
- else
+ auto [err, msg] = img.load(params[1]);
+ if (!err)
+ {
m_console.printf("File %s mounted on %s\n", params[1], params[0]);
+ }
+ else
+ {
+ m_console.printf(
+ "Unable to mount file %s on %s: %s\n",
+ params[1],
+ params[0],
+ !msg.empty() ? msg : err.message());
+ }
return;
}
}
@@ -4230,7 +4045,7 @@ void debugger_commands::execute_mount(const std::vector<std::string> &params)
execute_unmount - execute the image unmount command
-------------------------------------------------*/
-void debugger_commands::execute_unmount(const std::vector<std::string> &params)
+void debugger_commands::execute_unmount(const std::vector<std::string_view> &params)
{
for (device_image_interface &img : image_interface_enumerator(m_machine.root_device()))
{
@@ -4257,9 +4072,9 @@ void debugger_commands::execute_unmount(const std::vector<std::string> &params)
natural keyboard input
-------------------------------------------------*/
-void debugger_commands::execute_input(const std::vector<std::string> &params)
+void debugger_commands::execute_input(const std::vector<std::string_view> &params)
{
- m_machine.natkeyboard().post_coded(params[0].c_str());
+ m_machine.natkeyboard().post_coded(params[0]);
}
@@ -4268,15 +4083,15 @@ void debugger_commands::execute_input(const std::vector<std::string> &params)
keyboard codes
-------------------------------------------------*/
-void debugger_commands::execute_dumpkbd(const std::vector<std::string> &params)
+void debugger_commands::execute_dumpkbd(const std::vector<std::string_view> &params)
{
// was there a file specified?
- const char *filename = !params.empty() ? params[0].c_str() : nullptr;
+ std::string filename = !params.empty() ? std::string(params[0]) : std::string();
FILE *file = nullptr;
- if (filename != nullptr)
+ if (!filename.empty())
{
// if so, open it
- file = fopen(filename, "w");
+ file = fopen(filename.c_str(), "w");
if (file == nullptr)
{
m_console.printf("Cannot open \"%s\"\n", filename);
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index fd0bcea673a..134f838f8a7 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -24,27 +24,6 @@ class debugger_commands
public:
debugger_commands(running_machine &machine, debugger_cpu &cpu, debugger_console &console);
- // validates a parameter as a boolean value
- bool validate_boolean_parameter(const std::string &param, bool &result);
-
- // validates a parameter as a numeric value
- bool validate_number_parameter(std::string_view param, u64 &result);
-
- // validates a parameter as a device
- bool validate_device_parameter(std::string_view param, device_t *&result);
-
- // validates a parameter as a CPU
- bool validate_cpu_parameter(std::string_view param, device_t *&result);
-
- // validates a parameter as an address space identifier
- bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result);
-
- // validates a parameter as a target address and retrieves the given address space and address
- bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr);
-
- // validates a parameter as a memory region name and retrieves the given region
- bool validate_memory_region_parameter(std::string_view param, memory_region *&result);
-
private:
struct global_entry
{
@@ -87,11 +66,6 @@ private:
u8 disabled = 0U;
};
- device_t &get_device_search_base(std::string_view &param);
- device_t *get_cpu_by_index(u64 cpunum);
- bool debug_command_parameter_expression(std::string_view param, parsed_expression &result);
- bool debug_command_parameter_command(const char *param);
-
bool cheat_address_is_valid(address_space &space, offs_t address);
u64 get_cpunum();
@@ -99,86 +73,93 @@ 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, const std::vector<std::string_view> &params);
template <typename T>
- void execute_index_command(std::vector<std::string> const &params, T &&apply, char const *unused_message);
-
- void execute_help(const std::vector<std::string> &params);
- void execute_print(const std::vector<std::string> &params);
- void execute_printf(const std::vector<std::string> &params);
- void execute_logerror(const std::vector<std::string> &params);
- void execute_tracelog(const std::vector<std::string> &params);
- void execute_tracesym(const std::vector<std::string> &params);
- void execute_cls(const std::vector<std::string> &params);
- void execute_quit(const std::vector<std::string> &params);
- void execute_do(const std::vector<std::string> &params);
- void execute_step(const std::vector<std::string> &params);
- void execute_over(const std::vector<std::string> &params);
- void execute_out(const std::vector<std::string> &params);
- void execute_go(const std::vector<std::string> &params);
- void execute_go_vblank(const std::vector<std::string> &params);
- void execute_go_interrupt(const std::vector<std::string> &params);
- 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_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);
- void execute_suspend(const std::vector<std::string> &params);
- 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_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);
- void execute_comment_list(const std::vector<std::string> &params);
- void execute_comment_commit(const std::vector<std::string> &params);
- void execute_bpset(const std::vector<std::string> &params);
- void execute_bpclear(const std::vector<std::string> &params);
- void execute_bpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_bplist(const std::vector<std::string> &params);
- void execute_wpset(int spacenum, const std::vector<std::string> &params);
- void execute_wpclear(const std::vector<std::string> &params);
- void execute_wpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_wplist(const std::vector<std::string> &params);
- void execute_rpset(const std::vector<std::string> &params);
- void execute_rpclear(const std::vector<std::string> &params);
- void execute_rpdisenable(bool enable, const std::vector<std::string> &params);
- void execute_rplist(const std::vector<std::string> &params);
- void execute_statesave(const std::vector<std::string> &params);
- void execute_stateload(const std::vector<std::string> &params);
- void execute_rewind(const std::vector<std::string> &params);
- void execute_save(int spacenum, const std::vector<std::string> &params);
- void execute_saveregion(const std::vector<std::string> &params);
- void execute_load(int spacenum, const std::vector<std::string> &params);
- void execute_loadregion(const std::vector<std::string> &params);
- void execute_dump(int spacenum, const std::vector<std::string> &params);
- void execute_strdump(int spacenum, const std::vector<std::string> &params);
- void execute_cheatrange(bool init, const std::vector<std::string> &params);
- void execute_cheatnext(bool initial, const std::vector<std::string> &params);
- void execute_cheatlist(const std::vector<std::string> &params);
- void execute_cheatundo(const std::vector<std::string> &params);
- void execute_dasm(const std::vector<std::string> &params);
- void execute_find(int spacenum, const std::vector<std::string> &params);
- void execute_fill(int spacenum, const std::vector<std::string> &params);
- void execute_trace(const std::vector<std::string> &params, bool trace_over);
- void execute_traceflush(const std::vector<std::string> &params);
- void execute_history(const std::vector<std::string> &params);
- void execute_trackpc(const std::vector<std::string> &params);
- void execute_trackmem(const std::vector<std::string> &params);
- void execute_pcatmem(int spacenum, const std::vector<std::string> &params);
- void execute_snap(const std::vector<std::string> &params);
- void execute_source(const std::vector<std::string> &params);
- void execute_map(int spacenum, const std::vector<std::string> &params);
- void execute_memdump(const std::vector<std::string> &params);
- void execute_symlist(const std::vector<std::string> &params);
- void execute_softreset(const std::vector<std::string> &params);
- void execute_hardreset(const std::vector<std::string> &params);
- void execute_images(const std::vector<std::string> &params);
- void execute_mount(const std::vector<std::string> &params);
- void execute_unmount(const std::vector<std::string> &params);
- void execute_input(const std::vector<std::string> &params);
- void execute_dumpkbd(const std::vector<std::string> &params);
+ void execute_index_command(std::vector<std::string_view> const &params, T &&apply, char const *unused_message);
+
+ void execute_help(const std::vector<std::string_view> &params);
+ void execute_print(const std::vector<std::string_view> &params);
+ void execute_printf(const std::vector<std::string_view> &params);
+ void execute_logerror(const std::vector<std::string_view> &params);
+ void execute_tracelog(const std::vector<std::string_view> &params);
+ void execute_tracesym(const std::vector<std::string_view> &params);
+ void execute_cls(const std::vector<std::string_view> &params);
+ void execute_quit(const std::vector<std::string_view> &params);
+ void execute_do(const std::vector<std::string_view> &params);
+ void execute_step(const std::vector<std::string_view> &params);
+ void execute_over(const std::vector<std::string_view> &params);
+ void execute_out(const std::vector<std::string_view> &params);
+ void execute_go(const std::vector<std::string_view> &params);
+ void execute_go_vblank(const std::vector<std::string_view> &params);
+ void execute_go_interrupt(const std::vector<std::string_view> &params);
+ void execute_go_exception(const std::vector<std::string_view> &params);
+ void execute_go_time(const std::vector<std::string_view> &params);
+ void execute_go_privilege(const std::vector<std::string_view> &params);
+ void execute_go_branch(bool sense, const std::vector<std::string_view> &params);
+ void execute_go_next_instruction(const std::vector<std::string_view> &params);
+ void execute_focus(const std::vector<std::string_view> &params);
+ void execute_ignore(const std::vector<std::string_view> &params);
+ void execute_observe(const std::vector<std::string_view> &params);
+ void execute_suspend(const std::vector<std::string_view> &params);
+ void execute_resume(const std::vector<std::string_view> &params);
+ void execute_next(const std::vector<std::string_view> &params);
+ void execute_cpulist(const std::vector<std::string_view> &params);
+ void execute_time(const std::vector<std::string_view> &params);
+ void execute_comment_add(const std::vector<std::string_view> &params);
+ void execute_comment_del(const std::vector<std::string_view> &params);
+ void execute_comment_save(const std::vector<std::string_view> &params);
+ void execute_comment_list(const std::vector<std::string_view> &params);
+ void execute_comment_commit(const std::vector<std::string_view> &params);
+ void execute_bpset(const std::vector<std::string_view> &params);
+ void execute_bpclear(const std::vector<std::string_view> &params);
+ void execute_bpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_bplist(const std::vector<std::string_view> &params);
+ void execute_wpset(int spacenum, const std::vector<std::string_view> &params);
+ void execute_wpclear(const std::vector<std::string_view> &params);
+ void execute_wpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_wplist(const std::vector<std::string_view> &params);
+ void execute_rpset(const std::vector<std::string_view> &params);
+ void execute_rpclear(const std::vector<std::string_view> &params);
+ void execute_rpdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_rplist(const std::vector<std::string_view> &params);
+ void execute_epset(const std::vector<std::string_view> &params);
+ void execute_epclear(const std::vector<std::string_view> &params);
+ void execute_epdisenable(bool enable, const std::vector<std::string_view> &params);
+ void execute_eplist(const std::vector<std::string_view> &params);
+ void execute_statesave(const std::vector<std::string_view> &params);
+ void execute_stateload(const std::vector<std::string_view> &params);
+ void execute_rewind(const std::vector<std::string_view> &params);
+ void execute_save(int spacenum, const std::vector<std::string_view> &params);
+ void execute_saveregion(const std::vector<std::string_view> &params);
+ void execute_load(int spacenum, const std::vector<std::string_view> &params);
+ void execute_loadregion(const std::vector<std::string_view> &params);
+ void execute_dump(int spacenum, const std::vector<std::string_view> &params);
+ void execute_strdump(int spacenum, const std::vector<std::string_view> &params);
+ void execute_cheatrange(bool init, const std::vector<std::string_view> &params);
+ void execute_cheatnext(bool initial, const std::vector<std::string_view> &params);
+ void execute_cheatlist(const std::vector<std::string_view> &params);
+ void execute_cheatundo(const std::vector<std::string_view> &params);
+ void execute_dasm(const std::vector<std::string_view> &params);
+ void execute_find(int spacenum, const std::vector<std::string_view> &params);
+ void execute_fill(int spacenum, const std::vector<std::string_view> &params);
+ void execute_trace(const std::vector<std::string_view> &params, bool trace_over);
+ void execute_traceflush(const std::vector<std::string_view> &params);
+ void execute_history(const std::vector<std::string_view> &params);
+ void execute_trackpc(const std::vector<std::string_view> &params);
+ void execute_trackmem(const std::vector<std::string_view> &params);
+ void execute_pcatmem(int spacenum, const std::vector<std::string_view> &params);
+ void execute_snap(const std::vector<std::string_view> &params);
+ void execute_source(const std::vector<std::string_view> &params);
+ void execute_map(int spacenum, const std::vector<std::string_view> &params);
+ void execute_memdump(const std::vector<std::string_view> &params);
+ void execute_symlist(const std::vector<std::string_view> &params);
+ void execute_softreset(const std::vector<std::string_view> &params);
+ void execute_hardreset(const std::vector<std::string_view> &params);
+ void execute_images(const std::vector<std::string_view> &params);
+ void execute_mount(const std::vector<std::string_view> &params);
+ void execute_unmount(const std::vector<std::string_view> &params);
+ void execute_input(const std::vector<std::string_view> &params);
+ void execute_dumpkbd(const std::vector<std::string_view> &params);
running_machine& m_machine;
debugger_console& m_console;
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index 32a4888c285..ec5bc154751 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/*********************************************************************
debugcon.cpp
@@ -16,6 +16,8 @@
#include "textbuf.h"
#include "debugger.h"
+#include "fileio.h"
+#include "main.h"
#include "corestr.h"
@@ -86,10 +88,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 +120,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_view> &)> &&_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)
+void debugger_console::execute_help_custom(const std::vector<std::string_view> &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);
}
}
}
@@ -157,9 +161,9 @@ void debugger_console::execute_help_custom(const std::vector<std::string> &param
execute_condump - execute the condump command
------------------------------------------------------------*/
-void debugger_console::execute_condump(const std::vector<std::string>& params)
+void debugger_console::execute_condump(const std::vector<std::string_view>& params)
{
- std::string filename = params[0];
+ std::string filename(params[0]);
const char* mode;
/* replace macros */
@@ -195,166 +199,149 @@ void debugger_console::execute_condump(const std::vector<std::string>& params)
// symbol table
//-------------------------------------------------
-symbol_table &debugger_console::visible_symtable()
+symbol_table &debugger_console::visible_symtable() const
{
return m_visiblecpu->debug()->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);
- found->handler(params_vec);
- }
+ found->handler(params);
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;
-
- /* make a copy of the command */
- strcpy(command, original_command.c_str());
+ std::string_view::size_type pos = 0;
+ std::string_view::size_type len = command.length();
- /* 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 +351,44 @@ 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);
-
- /* NULL-terminate if we ended in a semicolon */
- p--;
- if (c == ';') *p++ = 0;
+ return CMDERR::unbalanced_quotes(pos);
+ if (!parens.empty())
+ return CMDERR::unbalanced_parens(pos);
- /* process the command */
- command_start = params[0];
+ // process the command
+ std::string_view command_or_expr = 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 expr(visible_symtable(), command_or_expr);
+ if (execute)
+ 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_view> &)> &&handler)
{
if (m_machine.phase() != machine_phase::INIT)
throw emu_fatalerror("Can only call debugger_console::register_command() at init time!");
@@ -576,6 +560,494 @@ std::string debugger_console::cmderr_to_string(CMDERR error)
}
+//**************************************************************************
+// PARAMETER VALIDATION HELPERS
+//**************************************************************************
+
+namespace {
+
+template <typename T>
+inline std::string_view::size_type find_delimiter(std::string_view str, T &&is_delim)
+{
+ unsigned parens = 0;
+ for (std::string_view::size_type i = 0; str.length() > i; ++i)
+ {
+ if (str[i] == '(')
+ {
+ ++parens;
+ }
+ else if (parens)
+ {
+ if (str[i] == ')')
+ --parens;
+ }
+ else if (is_delim(str[i]))
+ {
+ return i;
+ }
+ }
+ return std::string_view::npos;
+}
+
+} // anonymous namespace
+
+
+/// \brief Validate parameter as a Boolean value
+///
+/// Validates a parameter as a Boolean value. Fixed strings and
+/// expressions evaluating to numeric values are recognised. The result
+/// is unchanged for an empty string.
+/// \param [in] param The parameter string.
+/// \param [in,out] result The default value on entry, and the value of
+/// the parameter interpreted as a Boolean on success. Unchanged if
+/// the parameter is an empty string.
+/// \return true if the parameter is a valid Boolean value or an empty
+/// string, or false otherwise.
+bool debugger_console::validate_boolean_parameter(std::string_view param, bool &result)
+{
+ // nullptr parameter does nothing and returns no error
+ if (param.empty())
+ return true;
+
+ // evaluate the expression; success if no error
+ using namespace std::literals;
+ bool const is_true = util::streqlower(param, "true"sv);
+ bool const is_false = util::streqlower(param, "false"sv);
+
+ if (is_true || is_false)
+ {
+ result = is_true;
+ return true;
+ }
+
+ // try to evaluate as a number
+ u64 val;
+ if (!validate_number_parameter(param, val))
+ return false;
+
+ result = val != 0;
+ return true;
+}
+
+
+/// \brief Validate parameter as a numeric value
+///
+/// Parses the parameter as an expression and evaluates it as a number.
+/// \param [in] param The parameter string.
+/// \param [out] result The numeric value of the expression on success.
+/// Unchanged on failure.
+/// \return true if the parameter is a valid expression that evaluates
+/// to a numeric value, or false otherwise.
+bool debugger_console::validate_number_parameter(std::string_view param, u64 &result)
+{
+ // evaluate the expression; success if no error
+ try
+ {
+ result = parsed_expression(visible_symtable(), param).execute();
+ return true;
+ }
+ catch (expression_error const &error)
+ {
+ // print an error pointing to the character that caused it
+ printf("Error in expression: %s\n", param);
+ printf(" %*s^", error.offset(), "");
+ printf("%s\n", error.code_string());
+ return false;
+ }
+}
+
+
+/// \brief Validate parameter as a device
+///
+/// Validates a parameter as a device identifier and retrieves the
+/// device on success. A string corresponding to the tag of a device
+/// refers to that device; an empty string refers to the current CPU
+/// with debugger focus; any other string is parsed as an expression
+/// and treated as an index of a device implementing
+/// #device_execute_interface and #device_state_interface, and exposing
+/// a generic PC base value.
+/// \param [in] param The parameter string.
+/// \param [out] result A pointer to the device on success, or unchanged
+/// on failure.
+/// \return true if the parameter refers to a device in the current
+/// system, or false otherwise.
+bool debugger_console::validate_device_parameter(std::string_view param, device_t *&result)
+{
+ // if no parameter, use the visible CPU
+ if (param.empty())
+ {
+ device_t *const current = m_visiblecpu;
+ if (current)
+ {
+ result = current;
+ return true;
+ }
+ else
+ {
+ printf("No valid CPU is currently selected\n");
+ return false;
+ }
+ }
+
+ // next look for a tag match
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ device_t *device = base.subdevice(strmakelower(relative));
+ if (device)
+ {
+ result = device;
+ return true;
+ }
+
+ // then evaluate as an expression; on an error assume it was a tag
+ u64 cpunum;
+ try
+ {
+ cpunum = parsed_expression(visible_symtable(), param).execute();
+ }
+ catch (expression_error &)
+ {
+ printf("Unable to find device '%s'\n", param);
+ return false;
+ }
+
+ // attempt to find by numerical index
+ device = get_cpu_by_index(cpunum);
+ if (device)
+ {
+ result = device;
+ return true;
+ }
+ else
+ {
+ // if out of range, complain
+ printf("Invalid CPU index %u\n", cpunum);
+ return false;
+ }
+}
+
+
+/// \brief Validate a parameter as a CPU
+///
+/// Validates a parameter as a CPU identifier. Uses the same rules as
+/// #validate_device_parameter to identify devices, but additionally
+/// checks that the device is a "CPU" for the debugger's purposes.
+/// \param [in] The parameter string.
+/// \param [out] result The device on success, or unchanged on failure.
+/// \return true if the parameter refers to a CPU-like device in the
+/// current system, or false otherwise.
+bool debugger_console::validate_cpu_parameter(std::string_view param, device_t *&result)
+{
+ // first do the standard device thing
+ device_t *device;
+ if (!validate_device_parameter(param, device))
+ return false;
+
+ // check that it's a "CPU" for the debugger's purposes
+ device_execute_interface const *execute;
+ if (device->interface(execute))
+ {
+ result = device;
+ return true;
+ }
+
+ printf("Device %s is not a CPU\n", device->name());
+ return false;
+}
+
+
+/// \brief Validate a parameter as an address space identifier
+///
+/// Validates a parameter as an address space identifier. Uses the same
+/// rules as #validate_device_parameter to identify devices. If the
+/// default address space number is negative, the first address space
+/// exposed by the device will be used as the default.
+/// \param [in] The parameter string.
+/// \param [in] spacenum The default address space index. If negative,
+/// the first address space exposed by the device (i.e. the address
+/// space with the lowest index) will be used as the default.
+/// \param [out] result The addresfs space on success, or unchanged on
+/// failure.
+/// \return true if the parameter refers to an address space in the
+/// current system, or false otherwise.
+bool debugger_console::validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result)
+{
+ device_t *device;
+ std::string spacename;
+ if (param.empty())
+ {
+ // if no parameter, use the visible CPU
+ device = m_visiblecpu;
+ if (!device)
+ {
+ printf("No valid CPU is currently selected\n");
+ return false;
+ }
+ }
+ else
+ {
+ // look for a tag match on the whole parameter value
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ device = base.subdevice(strmakelower(relative));
+
+ // if that failed, treat the last component as an address space
+ if (!device)
+ {
+ auto const delimiter = relative.find_last_of(":^");
+ bool const found = std::string_view::npos != delimiter;
+ if (!found || (':' == relative[delimiter]))
+ {
+ spacename = strmakelower(relative.substr(found ? (delimiter + 1) : 0));
+ relative = relative.substr(0, !found ? 0 : !delimiter ? 1 : delimiter);
+ if (!relative.empty())
+ device = base.subdevice(strmakelower(relative));
+ else if (m_visiblecpu)
+ device = m_visiblecpu;
+ else
+ device = &m_machine.root_device();
+ }
+ }
+ }
+
+ // if still no device found, evaluate as an expression
+ if (!device)
+ {
+ u64 cpunum;
+ try
+ {
+ cpunum = parsed_expression(visible_symtable(), param).execute();
+ }
+ catch (expression_error const &)
+ {
+ // parsing failed - assume it was a tag
+ printf("Unable to find device '%s'\n", param);
+ return false;
+ }
+
+ // attempt to find by numerical index
+ device = get_cpu_by_index(cpunum);
+ if (!device)
+ {
+ // if out of range, complain
+ printf("Invalid CPU index %u\n", cpunum);
+ return false;
+ }
+ }
+
+ // ensure the device implements the memory interface
+ device_memory_interface *memory;
+ if (!device->interface(memory))
+ {
+ printf("No memory interface found for device %s\n", device->name());
+ return false;
+ }
+
+ // fall back to supplied default space if appropriate
+ if (spacename.empty() && (0 <= spacenum))
+ {
+ if (memory->has_space(spacenum))
+ {
+ result = &memory->space(spacenum);
+ return true;
+ }
+ else
+ {
+ printf("No matching memory space found for device '%s'\n", device->tag());
+ return false;
+ }
+ }
+
+ // otherwise find the specified space or fall back to the first populated space
+ for (int i = 0; memory->max_space_count() > i; ++i)
+ {
+ if (memory->has_space(i) && (spacename.empty() || (memory->space(i).name() == spacename)))
+ {
+ result = &memory->space(i);
+ return true;
+ }
+ }
+
+ // report appropriate error message
+ if (spacename.empty())
+ printf("No memory spaces found for device '%s'\n", device->tag());
+ else
+ printf("Memory space '%s' not found found for device '%s'\n", spacename, device->tag());
+ return false;
+}
+
+
+/// \brief Validate a parameter as a target address
+///
+/// Validates a parameter as an numeric expression to use as an address
+/// optionally followed by a colon and a device identifier. If the
+/// device identifier is not presnt, the current CPU with debugger focus
+/// is assumed. See #validate_device_parameter for information on how
+/// device parametersare interpreted.
+/// \param [in] The parameter string.
+/// \param [in] spacenum The default address space index. If negative,
+/// the first address space exposed by the device (i.e. the address
+/// space with the lowest index) will be used as the default.
+/// \param [out] space The address space on success, or unchanged on
+/// failure.
+/// \param [out] addr The address on success, or unchanged on failure.
+/// \return true if the address is a valid expression evaluating to a
+/// number and the address space is found, or false otherwise.
+bool debugger_console::validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr)
+{
+ // check for the device delimiter
+ std::string_view::size_type const devdelim = find_delimiter(param, [] (char ch) { return ':' == ch; });
+ std::string_view device;
+ if (devdelim != std::string::npos)
+ device = param.substr(devdelim + 1);
+
+ // parse the address first
+ u64 addrval;
+ if (!validate_number_parameter(param.substr(0, devdelim), addrval))
+ return false;
+
+ // find the address space
+ if (!validate_device_space_parameter(device, spacenum, space))
+ return false;
+
+ // set the address now that we have the space
+ addr = addrval;
+ return true;
+}
+
+
+/// \brief Validate a parameter as a memory region
+///
+/// Validates a parameter as a memory region tag and retrieves the
+/// specified memory region.
+/// \param [in] The parameter string.
+/// \param [out] result The memory region on success, or unchanged on
+/// failure.
+/// \return true if the parameter refers to a memory region in the
+/// current system, or false otherwise.
+bool debugger_console::validate_memory_region_parameter(std::string_view param, memory_region *&result)
+{
+ auto const &regions = m_machine.memory().regions();
+ std::string_view relative = param;
+ device_t &base = get_device_search_base(relative);
+ auto const iter = regions.find(base.subtag(strmakelower(relative)));
+ if (regions.end() != iter)
+ {
+ result = iter->second.get();
+ return true;
+ }
+ else
+ {
+ printf("No matching memory region found for '%s'\n", param);
+ return false;
+ }
+}
+
+
+/// \brief Get search base for device or address space parameter
+///
+/// Handles prefix prefixes used to indicate that a device tag should be
+/// interpreted relative to the selected CPU. Removes the recognised
+/// prefixes from the parameter value.
+/// \param [in,out] param The parameter string. Recognised prefixes
+/// affecting the search base are removed, leaving a tag relative to
+/// the base device.
+/// \return A reference to the base device that the tag should be
+/// interpreted relative to.
+device_t &debugger_console::get_device_search_base(std::string_view &param) const
+{
+ if (!param.empty())
+ {
+ // handle ".:" or ".^" prefix for tag relative to current CPU if any
+ if (('.' == param[0]) && ((param.size() == 1) || (':' == param[1]) || ('^' == param[1])))
+ {
+ param.remove_prefix(((param.size() > 1) && (':' == param[1])) ? 2 : 1);
+ device_t *const current = m_visiblecpu;
+ return current ? *current : m_machine.root_device();
+ }
+
+ // a sibling path makes most sense relative to current CPU
+ if ('^' == param[0])
+ {
+ device_t *const current = m_visiblecpu;
+ return current ? *current : m_machine.root_device();
+ }
+ }
+
+ // default to root device
+ return m_machine.root_device();
+}
+
+
+/// \brief Get CPU by index
+///
+/// Looks up a CPU by the number the debugger assigns it based on its
+/// position in the device tree relative to other CPUs.
+/// \param [in] cpunum Zero-based index of the CPU to find.
+/// \return A pointer to the CPU if found, or \c nullptr if no CPU has
+/// the specified index.
+device_t *debugger_console::get_cpu_by_index(u64 cpunum) const
+{
+ unsigned index = 0;
+ for (device_execute_interface &exec : execute_interface_enumerator(m_machine.root_device()))
+ {
+ // real CPUs should have pcbase
+ device_state_interface const *state;
+ if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE))
+ {
+ if (index++ == cpunum)
+ {
+ return &exec.device();
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+//-------------------------------------------------
+// validate_expression_parameter - validates
+// an expression parameter
+//-----------------------------------------------*/
+
+bool debugger_console::validate_expression_parameter(std::string_view param, parsed_expression &result)
+{
+ try
+ {
+ // parse the expression; success if no error
+ result.parse(param);
+ return true;
+ }
+ catch (expression_error const &err)
+ {
+ // output an error
+ printf("Error in expression: %s\n", param);
+ printf(" %*s^", err.offset(), "");
+ printf("%s\n", err.code_string());
+ return false;
+ }
+}
+
+
+//-------------------------------------------------
+// validate_command_parameter - validates a
+// command parameter
+//-------------------------------------------------
+
+bool debugger_console::validate_command_parameter(std::string_view param)
+{
+ // validate the comment; success if no error
+ CMDERR err = validate_command(param);
+ if (err.error_class() == CMDERR::NONE)
+ return true;
+
+ // output an error
+ printf("Error in command: %s\n", param);
+ printf(" %*s^", err.error_offset(), "");
+ printf("%s\n", cmderr_to_string(err));
+ return false;
+}
+
/***************************************************************************
@@ -614,7 +1086,7 @@ void debugger_console::print_core_wrap(std::string_view text, int wrapcol)
// the format to the debug console
//-------------------------------------------------
-void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &args)
+void debugger_console::vprintf(util::format_argument_pack<char> const &args)
{
print_core(util::string_format(args));
@@ -622,7 +1094,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> const &a
m_machine.debug_view().update_all(DVT_CONSOLE);
}
-void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args)
+void debugger_console::vprintf(util::format_argument_pack<char> &&args)
{
print_core(util::string_format(std::move(args)));
@@ -636,7 +1108,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args)
// using the format to the debug console
//-------------------------------------------------
-void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args)
+void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args)
{
print_core_wrap(util::string_format(args), wrapcol);
@@ -644,7 +1116,7 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std:
m_machine.debug_view().update_all(DVT_CONSOLE);
}
-void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args)
+void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args)
{
print_core_wrap(util::string_format(std::move(args)), wrapcol);
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 5271b0e5ae5..37b2e235348 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -23,18 +23,13 @@
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;
constexpr u32 CMDFLAG_KEEP_QUOTES = 0x0001;
constexpr u32 CMDFLAG_CUSTOM_HELP = 0x0002;
-// parameter separator macros
-#define CMDPARAM_SEPARATOR "\0"
-#define CMDPARAM_TERMINATOR "\0\0"
-
/***************************************************************************
@@ -79,19 +74,20 @@ 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_view> &)> &&handler);
void source_script(const char *file);
void process_source_file();
// console management
- void vprintf(util::format_argument_pack<std::ostream> const &args);
- void vprintf(util::format_argument_pack<std::ostream> &&args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args);
+ void vprintf(util::format_argument_pack<char> const &args);
+ void vprintf(util::format_argument_pack<char> &&args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<char> const &args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<char> &&args);
text_buffer &get_console_textbuf() const { return *m_console_textbuf; }
// errorlog management
@@ -110,28 +106,58 @@ public:
vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
- device_t *get_visible_cpu() { return m_visiblecpu; }
+ device_t *get_visible_cpu() const { return m_visiblecpu; }
void set_visible_cpu(device_t *visiblecpu) { m_visiblecpu = visiblecpu; }
- symbol_table &visible_symtable();
+ symbol_table &visible_symtable() const;
static std::string cmderr_to_string(CMDERR error);
+ // validates a parameter as a boolean value
+ bool validate_boolean_parameter(std::string_view param, bool &result);
+
+ // validates a parameter as a numeric value
+ bool validate_number_parameter(std::string_view param, u64 &result);
+
+ // validates a parameter as a device
+ bool validate_device_parameter(std::string_view param, device_t *&result);
+
+ // validates a parameter as a CPU
+ bool validate_cpu_parameter(std::string_view param, device_t *&result);
+
+ // validates a parameter as an address space identifier
+ bool validate_device_space_parameter(std::string_view param, int spacenum, address_space *&result);
+
+ // validates a parameter as a target address and retrieves the given address space and address
+ bool validate_target_address_parameter(std::string_view param, int spacenum, address_space *&space, u64 &addr);
+
+ // validates a parameter as a memory region name and retrieves the given region
+ bool validate_memory_region_parameter(std::string_view param, memory_region *&result);
+
+ // validates a parameter as a debugger expression
+ bool validate_expression_parameter(std::string_view param, parsed_expression &result);
+
+ // validates a parameter as a debugger command
+ bool validate_command_parameter(std::string_view param);
+
private:
void exit();
- void execute_help_custom(const std::vector<std::string> &params);
- void execute_condump(const std::vector<std::string>& params);
+ void execute_help_custom(const std::vector<std::string_view> &params);
+ void execute_condump(const std::vector<std::string_view>& 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
+ device_t &get_device_search_base(std::string_view &param) const;
+ device_t *get_cpu_by_index(u64 cpunum) const;
+
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_view> &)> &&_handler);
struct compare
{
@@ -144,7 +170,7 @@ private:
std::string command;
const char * params;
const char * help;
- std::function<void (const std::vector<std::string> &)> handler;
+ std::function<void (const std::vector<std::string_view> &)> handler;
u32 flags;
int minparams;
int maxparams;
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 403d0b104ee..fd0093bd283 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -19,11 +19,12 @@
#include "debugger.h"
#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "screen.h"
#include "uiinput.h"
#include "corestr.h"
-#include "coreutil.h"
#include "osdepend.h"
#include "xmlfile.h"
@@ -46,6 +47,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
, m_bpindex(1)
, m_wpindex(1)
, m_rpindex(1)
+ , m_epindex(1)
, m_wpdata(0)
, m_wpaddr(0)
, m_wpsize(0)
@@ -91,7 +93,7 @@ debugger_cpu::debugger_cpu(running_machine &machine)
for (int regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++)
{
char symname[10];
- sprintf(symname, "temp%d", regnum);
+ snprintf(symname, 10, "temp%d", regnum);
m_symtable->add(symname, symbol_table::READ_WRITE, &m_tempvar[regnum]);
}
}
@@ -385,7 +387,7 @@ void debugger_cpu::go_vblank()
m_execution_state = exec_state::RUNNING;
}
-void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args)
+void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args)
{
// if something is pending on this CPU already, ignore this request
if (device == m_breakcpu)
@@ -423,9 +425,9 @@ device_debug::device_debug(device_t &device)
, m_disasm(nullptr)
, m_flags(0)
, m_symtable(std::make_unique<symbol_table>(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device))
- , m_instrhook(nullptr)
, m_stepaddr(0)
, m_stepsleft(0)
+ , m_delay_steps(0)
, m_stopaddr(0)
, m_stoptime(attotime::zero)
, m_stopirq(0)
@@ -436,7 +438,8 @@ device_debug::device_debug(device_t &device)
, m_pc_history_index(0)
, m_pc_history_valid(0)
, m_bplist()
- , m_rplist(std::make_unique<std::forward_list<debug_registerpoint>>())
+ , m_rplist()
+ , m_eplist()
, m_triggered_breakpoint(nullptr)
, m_triggered_watchpoint(nullptr)
, m_trace(nullptr)
@@ -458,14 +461,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
@@ -547,6 +550,7 @@ device_debug::~device_debug()
breakpoint_clear_all();
watchpoint_clear_all();
registerpoint_clear_all();
+ exceptionpoint_clear_all();
}
void device_debug::write_tracking(address_space &space, offs_t address, u64 data)
@@ -562,15 +566,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;
}
}
}
@@ -633,15 +636,46 @@ void device_debug::stop_hook()
// acknowledged
//-------------------------------------------------
-void device_debug::interrupt_hook(int irqline)
+void device_debug::interrupt_hook(int irqline, offs_t pc)
{
// see if this matches a pending interrupt request
if ((m_flags & DEBUG_FLAG_STOP_INTERRUPT) != 0 && (m_stopirq == -1 || m_stopirq == irqline))
{
m_device.machine().debugger().cpu().set_execution_stopped();
- m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d)\n", m_device.tag(), irqline);
+ const address_space &space = m_memory->space(AS_PROGRAM);
+ if (space.is_octal())
+ m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*o)\n", m_device.tag(), irqline, (space.logaddr_width() + 2) / 3, pc);
+ else
+ m_device.machine().debugger().console().printf("Stopped on interrupt (CPU '%s', IRQ %d, PC=%0*X)\n", m_device.tag(), irqline, space.logaddrchars(), pc);
compute_debug_flags();
}
+
+ if (m_trace != nullptr)
+ m_trace->interrupt_update(irqline, pc);
+
+ if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH)) != 0)
+ {
+ if ((m_flags & DEBUG_FLAG_CALL_IN_PROGRESS) == 0)
+ {
+ if ((m_flags & DEBUG_FLAG_TEST_IN_PROGRESS) != 0)
+ {
+ if ((m_stepaddr == pc && (m_flags & DEBUG_FLAG_STEPPING_BRANCH_FALSE) != 0) ||
+ (m_stepaddr != pc && m_delay_steps == 1 && (m_flags & (DEBUG_FLAG_STEPPING_OUT | DEBUG_FLAG_STEPPING_BRANCH_TRUE)) != 0))
+ {
+ // step over the interrupt and then call it finished
+ m_flags = (m_flags & ~(DEBUG_FLAG_TEST_IN_PROGRESS | DEBUG_FLAG_STEPPING_ANY)) | DEBUG_FLAG_STEPPING_OVER;
+ m_stepsleft = 1;
+ }
+ }
+
+ // remember the interrupt return address
+ m_flags |= DEBUG_FLAG_CALL_IN_PROGRESS;
+ m_stepaddr = pc;
+ }
+
+ m_flags &= ~DEBUG_FLAG_TEST_IN_PROGRESS;
+ m_delay_steps = 0;
+ }
}
@@ -671,10 +705,39 @@ void device_debug::exception_hook(int exception)
if (matched)
{
m_device.machine().debugger().cpu().set_execution_stopped();
- m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %d, PC=%X)\n", m_device.tag(), exception, m_state->pcbase());
+ m_device.machine().debugger().console().printf("Stopped on exception (CPU '%s', exception %X, PC=%s)\n", m_device.tag(), exception, m_state->state_string(STATE_GENPC));
compute_debug_flags();
}
}
+
+ // see if any exception points match
+ if (!m_eplist.empty())
+ {
+ auto epitp = m_eplist.equal_range(exception);
+ for (auto epit = epitp.first; epit != epitp.second; ++epit)
+ {
+ debug_exceptionpoint &ep = *epit->second;
+ if (ep.hit(exception))
+ {
+ // halt in the debugger by default
+ debugger_cpu &debugcpu = m_device.machine().debugger().cpu();
+ debugcpu.set_execution_stopped();
+
+ // if we hit, evaluate the action
+ if (!ep.m_action.empty())
+ m_device.machine().debugger().console().execute_command(ep.m_action, false);
+
+ // print a notification, unless the action made us go again
+ if (debugcpu.is_stopped())
+ {
+ debugcpu.set_execution_stopped();
+ m_device.machine().debugger().console().printf("Stopped at exception point %X (CPU '%s', PC=%s)\n", ep.m_index, m_device.tag(), m_state->state_string(STATE_GENPC));
+ compute_debug_flags();
+ }
+ break;
+ }
+ }
+ }
}
@@ -688,11 +751,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 &)
{
@@ -743,26 +806,56 @@ void device_debug::instruction_hook(offs_t curpc)
if (m_trace != nullptr)
m_trace->update(curpc);
- // per-instruction hook?
- if (!debugcpu.is_stopped() && (m_flags & DEBUG_FLAG_HOOKED) != 0 && (*m_instrhook)(m_device, curpc))
- debugcpu.set_execution_stopped();
-
// 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: 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();
@@ -784,7 +877,10 @@ void device_debug::instruction_hook(offs_t curpc)
// check the temp running breakpoint and break if we hit it
else if ((m_flags & DEBUG_FLAG_STOP_PC) != 0 && m_stopaddr == curpc)
{
- machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag());
+ if (is_octal())
+ machine.debugger().console().printf("Stopped at temporary breakpoint %o on CPU '%s'\n", m_stopaddr, m_device.tag());
+ else
+ machine.debugger().console().printf("Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag());
debugcpu.set_execution_stopped();
}
@@ -849,7 +945,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
@@ -858,22 +954,6 @@ void device_debug::instruction_hook(offs_t curpc)
//-------------------------------------------------
-// set_instruction_hook - set a hook to be
-// called on each instruction for a given device
-//-------------------------------------------------
-
-void device_debug::set_instruction_hook(debug_instruction_hook_func hook)
-{
- // set the hook and also the CPU's flag for fast knowledge of the hook
- m_instrhook = hook;
- if (hook != nullptr)
- m_flags |= DEBUG_FLAG_HOOKED;
- else
- m_flags &= ~DEBUG_FLAG_HOOKED;
-}
-
-
-//-------------------------------------------------
// ignore - ignore/observe a given device
//-------------------------------------------------
@@ -928,8 +1008,9 @@ 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_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -945,8 +1026,9 @@ 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_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -961,9 +1043,11 @@ 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_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
m_device.machine().debugger().cpu().set_execution_running();
}
@@ -1060,20 +1144,38 @@ 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_flags &= ~(DEBUG_FLAG_CALL_IN_PROGRESS | DEBUG_FLAG_TEST_IN_PROGRESS);
+ 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
// to templates in C++ being janky as all get out
//-------------------------------------------------
-void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args)
+void device_debug::halt_on_next_instruction_impl(util::format_argument_pack<char> &&args)
{
assert(m_exec != nullptr);
m_device.machine().debugger().cpu().halt_on_next_instruction(&m_device, std::move(args));
@@ -1098,7 +1200,7 @@ const debug_breakpoint *device_debug::breakpoint_find(offs_t address) const
// returning its index
//-------------------------------------------------
-int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action)
+int device_debug::breakpoint_set(offs_t address, const char *condition, std::string_view action)
{
// allocate a new one and hook it into our list
u32 id = m_device.machine().debugger().cpu().get_breakpoint_index();
@@ -1185,7 +1287,7 @@ void device_debug::breakpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action)
+int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, std::string_view action)
{
if (space.spacenum() >= int(m_wplist.size()))
m_wplist.resize(space.spacenum()+1);
@@ -1272,15 +1374,15 @@ void device_debug::watchpoint_enable_all(bool enable)
// returning its index
//-------------------------------------------------
-int device_debug::registerpoint_set(const char *condition, const char *action)
+int device_debug::registerpoint_set(const char *condition, std::string_view action)
{
// allocate a new one
u32 id = m_device.machine().debugger().cpu().get_registerpoint_index();
- m_rplist->emplace_front(*m_symtable, id, condition, action);
+ m_rplist.emplace_front(*m_symtable, id, condition, action);
// update the flags and return the index
breakpoint_update_flags();
- return m_rplist->front().m_index;
+ return m_rplist.front().m_index;
}
@@ -1292,10 +1394,10 @@ int device_debug::registerpoint_set(const char *condition, const char *action)
bool device_debug::registerpoint_clear(int index)
{
// scan the list to see if we own this registerpoint
- for (auto brp = m_rplist->before_begin(); std::next(brp) != m_rplist->end(); ++brp)
+ for (auto brp = m_rplist.before_begin(); std::next(brp) != m_rplist.end(); ++brp)
if (std::next(brp)->m_index == index)
{
- m_rplist->erase_after(brp);
+ m_rplist.erase_after(brp);
breakpoint_update_flags();
return true;
}
@@ -1312,7 +1414,7 @@ bool device_debug::registerpoint_clear(int index)
void device_debug::registerpoint_clear_all()
{
// clear the list
- m_rplist->clear();
+ m_rplist.clear();
breakpoint_update_flags();
}
@@ -1325,7 +1427,7 @@ void device_debug::registerpoint_clear_all()
bool device_debug::registerpoint_enable(int index, bool enable)
{
// scan the list to see if we own this conditionpoint
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
if (rp.m_index == index)
{
rp.m_enabled = enable;
@@ -1346,12 +1448,97 @@ bool device_debug::registerpoint_enable(int index, bool enable)
void device_debug::registerpoint_enable_all(bool enable)
{
// apply the enable to all registerpoints we own
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
registerpoint_enable(rp.index(), enable);
}
//-------------------------------------------------
+// exceptionpoint_set - set a new exception
+// point, returning its index
+//-------------------------------------------------
+
+int device_debug::exceptionpoint_set(int exception, const char *condition, std::string_view action)
+{
+ // allocate a new one and hook it into our list
+ u32 id = m_device.machine().debugger().cpu().get_exceptionpoint_index();
+ m_eplist.emplace(exception, std::make_unique<debug_exceptionpoint>(this, *m_symtable, id, exception, condition, action));
+
+ // return the index
+ return id;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear - clear an exception
+// point by index, returning true if we found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_clear(int index)
+{
+ // scan the list to see if we own this breakpoint
+ for (auto epit = m_eplist.begin(); epit != m_eplist.end(); ++epit)
+ if (epit->second->m_index == index)
+ {
+ m_eplist.erase(epit);
+ return true;
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_clear_all - clear all exception
+// points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_clear_all()
+{
+ // clear the list
+ m_eplist.clear();
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable - enable/disable an
+// exception point by index, returning true if we
+// found it
+//-------------------------------------------------
+
+bool device_debug::exceptionpoint_enable(int index, bool enable)
+{
+ // scan the list to see if we own this exception point
+ for (auto &epp : m_eplist)
+ {
+ debug_exceptionpoint &ep = *epp.second;
+ if (ep.m_index == index)
+ {
+ ep.m_enabled = enable;
+ return true;
+ }
+ }
+
+ // we don't own it, return false
+ return false;
+}
+
+
+//-------------------------------------------------
+// exceptionpoint_enable_all - enable/disable all
+// exception points
+//-------------------------------------------------
+
+void device_debug::exceptionpoint_enable_all(bool enable)
+{
+ // apply the enable to all exception points we own
+ for (auto &epp : m_eplist)
+ exceptionpoint_enable(epp.second->index(), enable);
+}
+
+
+//-------------------------------------------------
// history_pc - return an entry from the PC
// history
//-------------------------------------------------
@@ -1385,7 +1572,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 +1585,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)
@@ -1541,7 +1726,7 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const
buffer.data_get(pc, dasmresult & util::disasm_interface::LENGTHMASK, true, opbuf);
// return a CRC of the exact count of opcode bytes
- return core_crc32(0, &opbuf[0], opbuf.size());
+ return util::crc32_creator::simple(&opbuf[0], opbuf.size());
}
@@ -1549,31 +1734,14 @@ u32 device_debug::compute_opcode_crc32(offs_t pc) const
// trace - trace execution of a given device
//-------------------------------------------------
-void device_debug::trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+void device_debug::trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
{
// delete any existing tracers
m_trace = nullptr;
// if we have a new file, make a new tracer
if (file != nullptr)
- m_trace = std::make_unique<tracer>(*this, *file, trace_over, detect_loops, logerror, action);
-}
-
-
-//-------------------------------------------------
-// trace_printf - output data into the given
-// device's tracefile, if tracing
-//-------------------------------------------------
-
-void device_debug::trace_printf(const char *fmt, ...)
-{
- if (m_trace != nullptr)
- {
- va_list va;
- va_start(va, fmt);
- m_trace->vprintf(fmt, va);
- va_end(va);
- }
+ m_trace = std::make_unique<tracer>(*this, std::move(file), trace_over, detect_loops, logerror, action);
}
@@ -1601,7 +1769,7 @@ void device_debug::compute_debug_flags()
// if we're tracking history, or we're hooked, or stepping, or stopping at a breakpoint
// make sure we call the hook
- if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_HOOKED | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
+ if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
// also call if we are tracing
@@ -1625,12 +1793,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 +1826,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
{
@@ -1678,7 +1870,7 @@ void device_debug::breakpoint_update_flags()
if (!(m_flags & DEBUG_FLAG_LIVE_BP))
{
// see if there are any enabled registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.m_enabled)
{
@@ -1728,7 +1920,7 @@ void device_debug::breakpoint_check(offs_t pc)
}
// see if we have any matching registerpoints
- for (debug_registerpoint &rp : *m_rplist)
+ for (debug_registerpoint &rp : m_rplist)
{
if (rp.hit())
{
@@ -1761,10 +1953,10 @@ void device_debug::breakpoint_check(offs_t pc)
// tracer - constructor
//-------------------------------------------------
-device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action)
+device_debug::tracer::tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action)
: m_debug(debug)
- , m_file(file)
- , m_action((action != nullptr) ? action : "")
+ , m_file(std::move(file))
+ , m_action(action)
, m_detect_loops(detect_loops)
, m_logerror(logerror)
, m_loops(0)
@@ -1783,7 +1975,7 @@ device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, b
device_debug::tracer::~tracer()
{
// make sure we close the file if we can
- fclose(&m_file);
+ m_file.reset();
}
@@ -1819,7 +2011,7 @@ void device_debug::tracer::update(offs_t pc)
// if we just finished looping, indicate as much
if (m_loops != 0)
- fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops);
+ util::stream_format(*m_file, "\n (loops for %d instructions)\n\n", m_loops);
m_loops = 0;
}
@@ -1834,7 +2026,7 @@ void device_debug::tracer::update(offs_t pc)
buffer.disassemble(pc, instruction, next_pc, size, dasmresult);
// output the result
- fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str());
+ util::stream_format(*m_file, "%s: %s\n", buffer.pc_to_string(pc), instruction);
// do we need to step the trace over this instruction?
if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
@@ -1852,7 +2044,33 @@ void device_debug::tracer::update(offs_t pc)
// log this PC
m_nextdex = (m_nextdex + 1) % TRACE_LOOPS;
m_history[m_nextdex] = pc;
- fflush(&m_file);
+ m_file->flush();
+}
+
+
+//-------------------------------------------------
+// interrupt_update - log interrupt to tracefile
+//-------------------------------------------------
+
+void device_debug::tracer::interrupt_update(int irqline, offs_t pc)
+{
+ if (m_trace_over)
+ {
+ if (m_trace_over_target != ~0)
+ return;
+ m_trace_over_target = pc;
+ }
+
+ // if we just finished looping, indicate as much
+ *m_file << "\n";
+ if (m_detect_loops && m_loops != 0)
+ {
+ util::stream_format(*m_file, " (loops for %d instructions)\n", m_loops);
+ m_loops = 0;
+ }
+
+ util::stream_format(*m_file, " (interrupted at %s, IRQ %d)\n\n", debug_disasm_buffer(m_debug.device()).pc_to_string(pc), irqline);
+ m_file->flush();
}
@@ -1860,11 +2078,11 @@ void device_debug::tracer::update(offs_t pc)
// vprintf - generic print to the trace file
//-------------------------------------------------
-void device_debug::tracer::vprintf(const char *format, va_list va)
+void device_debug::tracer::vprintf(util::format_argument_pack<char> const &args)
{
// pass through to the file
- vfprintf(&m_file, format, va);
- fflush(&m_file);
+ util::stream_format(*m_file, args);
+ m_file->flush();
}
@@ -1875,7 +2093,7 @@ void device_debug::tracer::vprintf(const char *format, va_list va)
void device_debug::tracer::flush()
{
- fflush(&m_file);
+ m_file->flush();
}
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 9e3d23d8d7f..9a9f6e69f70 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -29,9 +29,6 @@ constexpr int COMMENT_VERSION = 1;
// TYPE DEFINITIONS
//**************************************************************************
-typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc);
-
-
// ======================> device_debug
// [TODO] This whole thing is terrible.
@@ -54,14 +51,11 @@ public:
// hooks used by the rest of the system
void start_hook(const attotime &endtime);
void stop_hook();
- void interrupt_hook(int irqline);
+ void interrupt_hook(int irqline, offs_t pc);
void exception_hook(int exception);
void privilege_hook();
void instruction_hook(offs_t curpc);
- // hooks into our operations
- void set_instruction_hook(debug_instruction_hook_func hook);
-
// debugger focus
void ignore(bool ignore = true);
bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); }
@@ -82,6 +76,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>
@@ -93,7 +88,7 @@ public:
// breakpoints
const auto &breakpoint_list() const { return m_bplist; }
const debug_breakpoint *breakpoint_find(offs_t address) const;
- int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr);
+ int breakpoint_set(offs_t address, const char *condition = nullptr, std::string_view action = {});
bool breakpoint_clear(int index);
void breakpoint_clear_all();
bool breakpoint_enable(int index, bool enable = true);
@@ -103,7 +98,7 @@ public:
// watchpoints
int watchpoint_space_count() const { return m_wplist.size(); }
const std::vector<std::unique_ptr<debug_watchpoint>> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; }
- int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action);
+ int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition = nullptr, std::string_view action = {});
bool watchpoint_clear(int wpnum);
void watchpoint_clear_all();
bool watchpoint_enable(int index, bool enable = true);
@@ -112,12 +107,20 @@ public:
debug_watchpoint *triggered_watchpoint() { debug_watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; }
// registerpoints
- const std::forward_list<debug_registerpoint> &registerpoint_list() const { return *m_rplist; }
- int registerpoint_set(const char *condition, const char *action = nullptr);
+ const std::forward_list<debug_registerpoint> &registerpoint_list() const { return m_rplist; }
+ int registerpoint_set(const char *condition, std::string_view action = {});
bool registerpoint_clear(int index);
void registerpoint_clear_all();
bool registerpoint_enable(int index, bool enable = true);
- void registerpoint_enable_all(bool enable = true );
+ void registerpoint_enable_all(bool enable = true);
+
+ // exception points
+ const auto &exceptionpoint_list() const { return m_eplist; }
+ int exceptionpoint_set(int exception, const char *condition = nullptr, std::string_view action = {});
+ bool exceptionpoint_clear(int index);
+ void exceptionpoint_clear_all();
+ bool exceptionpoint_enable(int index, bool enable = true);
+ void exceptionpoint_enable_all(bool enable = true);
// comments
void comment_add(offs_t address, const char *comment, rgb_t color);
@@ -146,8 +149,12 @@ public:
void track_mem_data_clear() { m_track_mem_set.clear(); }
// tracing
- void trace(FILE *file, bool trace_over, bool detect_loops, bool logerror, const char *action);
- void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3);
+ void trace(std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
+ template <typename Format, typename... Params> void trace_printf(Format &&fmt, Params &&...args)
+ {
+ if (m_trace != nullptr)
+ m_trace->vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
void trace_flush() { if (m_trace != nullptr) m_trace->flush(); }
void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; }
@@ -158,7 +165,7 @@ public:
void compute_debug_flags();
private:
- void halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args);
+ void halt_on_next_instruction_impl(util::format_argument_pack<char> &&args);
// internal helpers
void prepare_for_step_overout(offs_t pc);
@@ -181,18 +188,18 @@ private:
// global state
u32 m_flags; // debugging flags for this CPU
std::unique_ptr<symbol_table> m_symtable; // symbol table for expression evaluation
- 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
@@ -206,7 +213,8 @@ private:
// breakpoints and watchpoints
std::multimap<offs_t, std::unique_ptr<debug_breakpoint>> m_bplist; // list of breakpoints
std::vector<std::vector<std::unique_ptr<debug_watchpoint>>> m_wplist; // watchpoint lists for each address space
- std::unique_ptr<std::forward_list<debug_registerpoint>> m_rplist; // list of registerpoints
+ std::forward_list<debug_registerpoint> m_rplist; // list of registerpoints
+ std::multimap<offs_t, std::unique_ptr<debug_exceptionpoint>> m_eplist; // list of exception points
debug_breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered
debug_watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered
@@ -215,11 +223,12 @@ private:
class tracer
{
public:
- tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, bool logerror, const char *action);
+ tracer(device_debug &debug, std::unique_ptr<std::ostream> &&file, bool trace_over, bool detect_loops, bool logerror, std::string_view action);
~tracer();
void update(offs_t pc);
- void vprintf(const char *format, va_list va);
+ void interrupt_update(int irqline, offs_t pc);
+ void vprintf(util::format_argument_pack<char> const &args);
void flush();
bool logerror() const { return m_logerror; }
@@ -227,7 +236,7 @@ private:
static const int TRACE_LOOPS = 64;
device_debug & m_debug; // reference to our owner
- FILE & m_file; // tracing file for this CPU
+ std::unique_ptr<std::ostream> m_file; // tracing file for this CPU
std::string m_action; // action to perform during a trace
offs_t m_history[TRACE_LOOPS]; // history of recent PCs
bool m_detect_loops; // whether or not we should detect loops
@@ -239,10 +248,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
@@ -310,7 +319,6 @@ private:
static constexpr u32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history
static constexpr u32 DEBUG_FLAG_TRACING = 0x00000004; // tracing this CPU
static constexpr u32 DEBUG_FLAG_TRACING_OVER = 0x00000008; // tracing this CPU with step over behavior
- static constexpr u32 DEBUG_FLAG_HOOKED = 0x00000010; // per-instruction callback hook
static constexpr u32 DEBUG_FLAG_STEPPING = 0x00000020; // CPU is single stepping
static constexpr u32 DEBUG_FLAG_STEPPING_OVER = 0x00000040; // CPU is stepping over a function
static constexpr u32 DEBUG_FLAG_STEPPING_OUT = 0x00000080; // CPU is stepping out of a function
@@ -322,12 +330,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;
};
//**************************************************************************
@@ -377,6 +390,7 @@ public:
u32 get_breakpoint_index() { return m_bpindex++; }
u32 get_watchpoint_index() { return m_wpindex++; }
u32 get_registerpoint_index() { return m_rpindex++; }
+ u32 get_exceptionpoint_index() { return m_epindex++; }
// setters
void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; }
@@ -392,7 +406,7 @@ public:
void stop_hook(device_t *device);
void go_next_device(device_t *device);
void go_vblank();
- void halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args);
+ void halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args);
void ensure_comments_loaded();
void reset_transient_flags();
@@ -419,6 +433,7 @@ private:
u32 m_bpindex;
u32 m_wpindex;
u32 m_rpindex;
+ u32 m_epindex;
u64 m_wpdata;
u64 m_wpaddr;
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index 87bf8f0f18f..76102402bcb 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -46,6 +46,7 @@ const help_item f_static_help_list[] =
" Breakpoints\n"
" Watchpoints\n"
" Registerpoints\n"
+ " Exception Points\n"
" Expressions\n"
" Comments\n"
" Cheats\n"
@@ -81,6 +82,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,8 +134,12 @@ 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"
+ " gp [<condition>] -- resumes execution, setting temp breakpoint if privilege level changes\n"
" gt[ime] <milliseconds> -- resumes execution until the given delay has elapsed\n"
" gv[blank] -- resumes execution, setting temp breakpoint on the next VBLANK (F8)\n"
" n[ext] -- executes until the next CPU switch (F6)\n"
@@ -187,6 +193,18 @@ const help_item f_static_help_list[] =
" rplist [<CPU>] -- lists all the registerpoints\n"
},
{
+ "exceptionpoints",
+ "\n"
+ "Exception Point Commands\n"
+ "Type help <command> for further details on each command\n"
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]] -- sets exception point on <type>\n"
+ " epclear [<epnum>] -- clears a given exception point or all if no <epnum> specified\n"
+ " epdisable [<epnum>] -- disabled a given exception point or all if no <epnum> specified\n"
+ " epenable [<epnum>] -- enables a given exception point or all if no <epnum> specified\n"
+ " eplist -- lists all the exception points\n"
+ },
+ {
"expressions",
"\n"
"Expressions can be used anywhere a numeric parameter is expected. The syntax for expressions is "
@@ -341,16 +359,20 @@ const help_item f_static_help_list[] =
"The printf command performs a C-style printf to the debugger console. Only a very limited set of "
"formatting options are available:\n"
"\n"
- " %[0][<n>]d -- prints <item> as a decimal value with optional digit count and zero-fill\n"
- " %[0][<n>]x -- prints <item> as a hexadecimal value with optional digit count and zero-fill\n"
+ " %c -- 8-bit character\n"
+ " %[-][0][<n>]d -- decimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]o -- octal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]x -- lowercase hexadecimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][0][<n>]X -- uppercase hexadecimal number with optional left justification, zero fill and minimum width\n"
+ " %[-][<n>][.[<n>]]s -- null-terminated string of 8-bit characters with optional left justification, minimum and maximum width\n"
"\n"
- "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
- "lines can be printed by embedding a \\n in the text.\n"
+ "All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
+ "printed by embedding a \\n in the text.\n"
"\n"
"Examples:\n"
"\n"
"printf \"PC=%04X\",pc\n"
- " Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ " Prints PC=<pcval> where <pcval> is displayed in uppercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
@@ -361,18 +383,12 @@ const help_item f_static_help_list[] =
" logerror <format>[,<item>[,...]]\n"
"\n"
"The logerror command performs a C-style printf to the error log. Only a very limited set of "
- "formatting options are available:\n"
- "\n"
- " %[0][<n>]d -- logs <item> as a decimal value with optional digit count and zero-fill\n"
- " %[0][<n>]x -- logs <item> as a hexadecimal value with optional digit count and zero-fill\n"
- "\n"
- "All remaining formatting options are ignored. Use %% together to output a % character. Multiple "
- "lines can be printed by embedding a \\n in the text.\n"
+ "formatting options are available. See the 'printf' help for details.\n"
"\n"
"Examples:\n"
"\n"
- "logerror \"PC=%04X\",pc\n"
- " Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
+ "logerror \"PC=%04x\",pc\n"
+ " Logs PC=<pcval> where <pcval> is displayed in lowercase hexadecimal with 4 digits and zero fill.\n"
"\n"
"logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
" Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
@@ -578,6 +594,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 +943,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"
@@ -965,6 +1048,27 @@ const help_item f_static_help_list[] =
"acknowledged on the current CPU.\n"
},
{
+ "gp",
+ "\n"
+ " gp [<condition>]\n"
+ "\n"
+ "The gp command resumes execution of the current code. Control will not be returned to "
+ "the debugger until a breakpoint or watchpoint is hit, or the privilege level of the current "
+ "CPU changes. The optional <condition> parameter lets you specify an expression that will "
+ "be evaluated each time the privilege level changes. If the expression evaluates to true "
+ "(non-zero), execution will halt; otherwise, execution will continue with no notification.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "gp\n"
+ " Resume execution until the next break/watchpoint or the privilege level of the current "
+ "CPU changes.\n"
+ "\n"
+ "gp {pc != 1234}\n"
+ " Resume execution until the next break/watchpoint or the privilege level of the current "
+ "CPU changes, disregarding the instruction at address 1234.\n"
+ },
+ {
"gtime",
"\n"
" gt[ime] <milliseconds>\n"
@@ -1484,6 +1588,92 @@ const help_item f_static_help_list[] =
"actions attached to them.\n"
},
{
+ "epset",
+ "\n"
+ " ep[set] <type>[,<condition>[,<action>]]\n"
+ "\n"
+ "Sets a new exception point for exceptions of type <type> on the currently visible CPU. "
+ "The optional <condition> parameter lets you specify an expression that will be evaluated "
+ "each time the exception point is hit. If the result of the expression is true (non-zero), "
+ "the exception point will actually halt execution at the start of the exception handler; "
+ "otherwise, execution will continue with no notification. The optional <action> parameter "
+ "provides a command that is executed whenever the exception point is hit and the "
+ "<condition> is true. 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 epset command "
+ "itself.\n"
+ "\n"
+ "The numbering of exceptions depends upon the CPU type. Causes of exceptions may include "
+ "internally or externally vectored interrupts, errors occurring within instructions and "
+ "system calls.\n"
+ "\n"
+ "Each exception point that is set is assigned an index which can be used in other "
+ "exception point commands to reference this exception point.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "ep 2\n"
+ " Set an exception that will halt execution whenever the visible CPU raises exception "
+ "number 2.\n"
+ },
+ {
+ "epclear",
+ "\n"
+ " epclear [<epnum>[,...]]\n"
+ "\n"
+ "The epclear command clears exception points. If <epnum> is specified, only the requested "
+ "exception points are cleared, otherwise all exception points are cleared.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epclear 3\n"
+ " Clear exception point index 3.\n"
+ "\n"
+ "epclear\n"
+ " Clear all exception points.\n"
+ },
+ {
+ "epdisable",
+ "\n"
+ " epdisable [<epnum>[,...]]\n"
+ "\n"
+ "The epdisable command disables exception points. If <epnum> is specified, only the requested "
+ "exception points are disabled, otherwise all exception points are disabled. Note that "
+ "disabling an exception point does not delete it, it just temporarily marks the exception "
+ "point as inactive.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epdisable 3\n"
+ " Disable exception point index 3.\n"
+ "\n"
+ "epdisable\n"
+ " Disable all exception points.\n"
+ },
+ {
+ "epenable",
+ "\n"
+ " epenable [<epnum>[,...]]\n"
+ "\n"
+ "The epenable command enables exception points. If <epnum> is specified, only the "
+ "requested exception points are enabled, otherwise all exception points are enabled.\n"
+ "\n"
+ "Examples:\n"
+ "\n"
+ "epenable 3\n"
+ " Enable exception point index 3.\n"
+ "\n"
+ "epenable\n"
+ " Enable all exception points.\n"
+ },
+ {
+ "eplist",
+ "\n"
+ " eplist\n"
+ "\n"
+ "The eplist command lists all the current exception points, along with their index and "
+ "any conditions or actions attached to them.\n"
+ },
+ {
"map",
"\n"
" map[{d|i|o}] <address>[:<space>]\n"
@@ -1853,10 +2043,12 @@ private:
help_map m_help_list;
help_item const *m_uncached_help = std::begin(f_static_help_list);
+ util::ovectorstream m_message_buffer;
+
help_manager() = default;
public:
- char const *find(std::string_view tag)
+ std::string_view find(std::string_view tag)
{
// find a cached exact match if possible
std::string const lower = strmakelower(tag);
@@ -1892,16 +2084,17 @@ public:
if ((m_help_list.end() == next) || (next->first.substr(0, lower.length()) != lower))
return candidate->second;
- // TODO: pointers to static strings are bad, mmmkay?
- static char ambig_message[1024];
- int msglen = std::sprintf(ambig_message, "Ambiguous help request, did you mean:\n");
+ m_message_buffer.clear();
+ m_message_buffer.reserve(1024);
+ m_message_buffer.seekp(0, util::ovectorstream::beg);
+ m_message_buffer << "Ambiguous help request, did you mean:\n";
do
{
- msglen += std::sprintf(&ambig_message[msglen], " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]);
+ util::stream_format(m_message_buffer, " help %.*s?\n", int(candidate->first.length()), &candidate->first[0]);
++candidate;
}
while ((m_help_list.end() != candidate) && (candidate->first.substr(0, lower.length()) == lower));
- return ambig_message;
+ return util::buf_to_string_view(m_message_buffer);
}
// take the first help entry if no matches at all
@@ -1923,7 +2116,7 @@ public:
PUBLIC INTERFACE
***************************************************************************/
-const char *debug_get_help(std::string_view tag)
+std::string_view debug_get_help(std::string_view tag)
{
return help_manager::instance().find(tag);
}
diff --git a/src/emu/debug/debughlp.h b/src/emu/debug/debughlp.h
index 495d674eb0d..9efe12acaca 100644
--- a/src/emu/debug/debughlp.h
+++ b/src/emu/debug/debughlp.h
@@ -21,6 +21,6 @@
***************************************************************************/
// help management
-const char *debug_get_help(std::string_view tag);
+std::string_view debug_get_help(std::string_view tag);
#endif // MAME_EMU_DEBUG_DEBUGHLP_H
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/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp
index b42b86a0e90..d7be62c1eaa 100644
--- a/src/emu/debug/dvbpoints.cpp
+++ b/src/emu/debug/dvbpoints.cpp
@@ -71,7 +71,7 @@ static bool cConditionDescending(const debug_breakpoint *a, const debug_breakpoi
static bool cActionAscending(const debug_breakpoint *a, const debug_breakpoint *b)
{
- return strcmp(a->action(), b->action()) < 0;
+ return a->action() < b->action();
}
static bool cActionDescending(const debug_breakpoint *a, const debug_breakpoint *b)
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index 02fcde9cbc3..da792305c0d 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
//**************************************************************************
@@ -295,13 +309,13 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
// generate the address
char addrtext[20];
- sprintf(addrtext, m_addrformat.c_str(), address);
+ snprintf(addrtext, 20, m_addrformat.c_str(), address);
debug_view_char *dest = destrow + m_section[0].m_pos + 1;
for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++)
if (dest >= destmin && dest < destmax)
dest->byte = addrtext[ch];
- // generate the data 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) : '.');
}
}
}
@@ -345,15 +359,15 @@ void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *
switch (m_data_format)
{
case data_format::FLOAT_32BIT:
- sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata)));
+ snprintf(valuetext, 64, "%.8g", u32_to_float(u32(chunkdata)));
break;
case data_format::FLOAT_64BIT:
- sprintf(valuetext, "%.24g", u64_to_double(chunkdata));
+ snprintf(valuetext, 64, "%.24g", u64_to_double(chunkdata));
break;
case data_format::FLOAT_80BIT:
{
float64_t f64 = extF80M_to_f64(&chunkdata80);
- sprintf(valuetext, "%.24g", u64_to_double(f64.v));
+ snprintf(valuetext, 64, "%.24g", u64_to_double(f64.v));
break;
}
default:
@@ -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]];
@@ -856,14 +862,17 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data)
auto dis = machine().disable_side_effects();
bool ismapped = offs <= m_maxaddr;
+ address_space *tspace;
if (ismapped && !m_no_translation)
{
offs_t dummyaddr = offs;
- ismapped = source.m_memintf->translate(source.m_space->spacenum(), TRANSLATE_READ_DEBUG, dummyaddr);
+ ismapped = source.m_memintf->translate(source.m_space->spacenum(), device_memory_interface::TR_READ, dummyaddr, tspace);
}
+ else
+ tspace = source.m_space;
data = ~u64(0);
if (ismapped)
- data = m_expression.context().read_memory(*source.m_space, offs, size, !m_no_translation);
+ data = m_expression.context().read_memory(*tspace, offs, size, !m_no_translation);
return ismapped;
}
@@ -984,6 +993,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/dvrpoints.cpp b/src/emu/debug/dvrpoints.cpp
index 3ecadaec8e5..7295a1b2170 100644
--- a/src/emu/debug/dvrpoints.cpp
+++ b/src/emu/debug/dvrpoints.cpp
@@ -62,7 +62,7 @@ bool cConditionDescending(std::pair<device_t *, debug_registerpoint const *> con
bool cActionAscending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
{
- return strcmp(a.second->action(), b.second->action()) < 0;
+ return a.second->action() < b.second->action();
}
bool cActionDescending(std::pair<device_t *, debug_registerpoint const *> const &a, std::pair<device_t *, debug_registerpoint const *> const &b)
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index 8363928e5cb..9ab75b7b655 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;
}
@@ -482,23 +482,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo
{
u64 result = ~u64(0) >> (64 - 8*size);
+ address_space *tspace = &space;
+
if (apply_translation)
{
// mask against the logical byte mask
address &= space.logaddrmask();
// translate if necessary; if not mapped, return 0xffffffffffffffff
- if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, address))
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_READ, address, tspace))
return result;
}
// otherwise, call the reading function for the translated address
switch (size)
{
- case 1: result = space.read_byte(address); break;
- case 2: result = space.read_word_unaligned(address); break;
- case 4: result = space.read_dword_unaligned(address); break;
- case 8: result = space.read_qword_unaligned(address); break;
+ case 1: result = tspace->read_byte(address); break;
+ case 2: result = tspace->read_word_unaligned(address); break;
+ case 4: result = tspace->read_dword_unaligned(address); break;
+ case 8: result = tspace->read_qword_unaligned(address); break;
}
return result;
}
@@ -511,23 +513,25 @@ u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bo
void symbol_table::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation)
{
+ address_space *tspace = &space;
+
if (apply_translation)
{
// mask against the logical byte mask
address &= space.logaddrmask();
// translate if necessary; if not mapped, we're done
- if (!space.device().memory().translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address))
+ if (!space.device().memory().translate(space.spacenum(), device_memory_interface::TR_WRITE, address, tspace))
return;
}
// otherwise, call the writing function for the translated address
switch (size)
{
- case 1: space.write_byte(address, data); break;
- case 2: space.write_word_unaligned(address, data); break;
- case 4: space.write_dword_unaligned(address, data); break;
- case 8: space.write_qword_unaligned(address, data); break;
+ case 1: tspace->write_byte(address, data); break;
+ case 2: tspace->write_word_unaligned(address, data); break;
+ case 4: tspace->write_dword_unaligned(address, data); break;
+ case 8: tspace->write_qword_unaligned(address, data); break;
}
notify_memory_modified();
@@ -1736,7 +1740,7 @@ void parsed_expression::infix_to_postfix()
else if (token->is_operator())
{
// normalize the operator based on neighbors
- normalize_operator(*token, prev, next != m_tokenlist.end() ? &*next : nullptr, stack, was_rparen);
+ normalize_operator(*token, prev, next != origlist.end() ? &*next : nullptr, stack, was_rparen);
was_rparen = false;
// if the token is an opening parenthesis, push it onto the stack.
diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h
index 23284193f47..251d8b4365c 100644
--- a/src/emu/debug/express.h
+++ b/src/emu/debug/express.h
@@ -86,17 +86,19 @@ public:
};
// construction/destruction
- expression_error(error_code code, int offset = 0, int num = 0)
- : m_code(code),
- m_offset(offset),
- m_num(num) { }
+ constexpr expression_error(error_code code, int offset = 0, int num = 0)
+ : m_code(code)
+ , m_offset(offset)
+ , m_num(num)
+ {
+ }
// operators
- operator error_code() const { return m_code; }
+ constexpr operator error_code() const { return m_code; }
// getters
- error_code code() const { return m_code; }
- int offset() const { return m_offset; }
+ constexpr error_code code() const { return m_code; }
+ constexpr int offset() const { return m_offset; }
std::string code_string() const;
private:
@@ -175,15 +177,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..961488eebb2 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,
+ std::string_view action) :
+ m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_address(address),
+ m_condition(symbols, condition ? condition : "1"),
+ m_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,
+ std::string_view 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),
+ 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;
}
@@ -416,11 +431,11 @@ void debug_watchpoint::triggered(read_or_write type, offs_t address, u64 data, u
// debug_registerpoint - constructor
//-------------------------------------------------
-debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action)
+debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action)
: m_index(index),
m_enabled(true),
m_condition(symbols, (condition != nullptr) ? condition : "1"),
- m_action((action != nullptr) ? action : "")
+ m_action(action)
{
}
@@ -450,3 +465,59 @@ bool debug_registerpoint::hit()
return true;
}
+
+
+//**************************************************************************
+// DEBUG EXCEPTION POINT
+//**************************************************************************
+
+//-------------------------------------------------
+// debug_exceptionpoint - constructor
+//-------------------------------------------------
+
+debug_exceptionpoint::debug_exceptionpoint(
+ device_debug *debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition,
+ std::string_view action)
+ : m_debugInterface(debugInterface),
+ m_index(index),
+ m_enabled(true),
+ m_type(type),
+ m_condition(symbols, (condition != nullptr) ? condition : "1"),
+ m_action(action)
+{
+}
+
+
+//-------------------------------------------------
+// hit - detect a hit
+//-------------------------------------------------
+
+bool debug_exceptionpoint::hit(int exception)
+{
+ // don't hit if disabled
+ if (!m_enabled)
+ return false;
+
+ // must match our type
+ if (m_type != exception)
+ return false;
+
+ // must satisfy the condition
+ if (!m_condition.is_empty())
+ {
+ try
+ {
+ return (m_condition.execute() != 0);
+ }
+ catch (expression_error &)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h
index 84cdad7720b..42abd46398f 100644
--- a/src/emu/debug/points.h
+++ b/src/emu/debug/points.h
@@ -36,7 +36,7 @@ public:
int index,
offs_t address,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
// getters
const device_debug *debugInterface() const { return m_debugInterface; }
@@ -44,7 +44,7 @@ public:
bool enabled() const { return m_enabled; }
offs_t address() const { return m_address; }
const char *condition() const { return m_condition.original_string(); }
- const char *action() const { return m_action.c_str(); }
+ const std::string &action() const { return m_action; }
// setters
void setEnabled(bool value) { m_enabled = value; } // FIXME: need to update breakpoint flags but it's a private method
@@ -77,7 +77,7 @@ public:
offs_t address,
offs_t length,
const char *condition = nullptr,
- const char *action = nullptr);
+ std::string_view action = {});
~debug_watchpoint();
// getters
@@ -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
@@ -128,13 +128,13 @@ class debug_registerpoint
public:
// construction/destruction
- debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr);
+ debug_registerpoint(symbol_table &symbols, int index, const char *condition, std::string_view action = {});
// getters
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.c_str(); }
+ const std::string &action() const { return m_action; }
private:
// internals
@@ -146,4 +146,42 @@ private:
std::string m_action; // action
};
+// ======================> debug_exceptionpoint
+
+class debug_exceptionpoint
+{
+ friend class device_debug;
+
+public:
+ // construction/destruction
+ debug_exceptionpoint(
+ device_debug* debugInterface,
+ symbol_table &symbols,
+ int index,
+ int type,
+ const char *condition = nullptr,
+ std::string_view action = {});
+
+ // getters
+ const device_debug *debugInterface() const { return m_debugInterface; }
+ int index() const { return m_index; }
+ bool enabled() const { return m_enabled; }
+ int type() const { return m_type; }
+ const char *condition() const { return m_condition.original_string(); }
+ const std::string &action() const { return m_action; }
+
+ // setters
+ void setEnabled(bool value) { m_enabled = value; }
+
+private:
+ // internals
+ bool hit(int exception);
+ const device_debug * m_debugInterface; // the interface we were created from
+ int m_index; // user reported index
+ bool m_enabled; // enabled?
+ int m_type; // exception type
+ parsed_expression m_condition; // condition
+ std::string m_action; // action
+};
+
#endif // MAME_EMU_DEBUG_POINTS_H