summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug')
-rw-r--r--src/emu/debug/debugcmd.cpp188
-rw-r--r--src/emu/debug/debugcmd.h5
-rw-r--r--src/emu/debug/debugcpu.cpp217
-rw-r--r--src/emu/debug/debugcpu.h7
-rw-r--r--src/emu/debug/debughlp.cpp82
-rw-r--r--src/emu/debug/debugvw.cpp4
-rw-r--r--src/emu/debug/debugvw.h3
-rw-r--r--src/emu/debug/dvbpoints.cpp3
-rw-r--r--src/emu/debug/dvbpoints.h1
-rw-r--r--src/emu/debug/dvdisasm.cpp47
-rw-r--r--src/emu/debug/dvdisasm.h8
-rw-r--r--src/emu/debug/dvepoints.cpp314
-rw-r--r--src/emu/debug/dvepoints.h49
-rw-r--r--src/emu/debug/dvmemory.cpp1
-rw-r--r--src/emu/debug/dvrpoints.cpp2
-rw-r--r--src/emu/debug/dvrpoints.h1
-rw-r--r--src/emu/debug/dvwpoints.cpp1
-rw-r--r--src/emu/debug/dvwpoints.h1
-rw-r--r--src/emu/debug/express.cpp2
-rw-r--r--src/emu/debug/points.cpp2
-rw-r--r--src/emu/debug/points.h1
21 files changed, 716 insertions, 223 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index 730565494a4..0b7efa44a93 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -469,10 +469,14 @@ void debugger_commands::execute_print(const std::vector<std::string_view> &param
mini_printf - safe printf to a buffer
-------------------------------------------------*/
-bool debugger_commands::mini_printf(std::ostream &stream, std::string_view format, int params, u64 *param)
+bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> &params)
{
+ std::string_view const format(params[0]);
auto f = format.begin();
+ int param = 1;
+ u64 number;
+
// parse the string looking for % signs
while (f != format.end())
{
@@ -495,21 +499,48 @@ bool debugger_commands::mini_printf(std::ostream &stream, std::string_view forma
// 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
- while (f != format.end() && *f >= '0' && *f <= '9')
+ // parse optional left justification flag
+ if (f != format.end() && *f == '-')
{
- c = *f++;
- 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 (f == format.end()) break;
- // get the format
- c = *f++;
switch (c)
{
case '%':
@@ -517,70 +548,89 @@ bool debugger_commands::mini_printf(std::ostream &stream, std::string_view forma
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 false;
}
- if (u32(*param >> 32) != 0)
- util::stream_format(stream, zerofill ? "%0*X" : "%*X", (width <= 8) ? 1 : width - 8, u32(*param >> 32));
- else if (width > 8)
- util::stream_format(stream, zerofill ? "%0*X" : "%*X", width - 8, 0);
- util::stream_format(stream, zerofill ? "%0*X" : "%*X", (width < 8) ? width : 8, u32(*param));
- param++;
- params--;
break;
case 'O':
case 'o':
- if (params == 0)
+ if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
+ util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number);
+ else
{
m_console.printf("Not enough parameters for format!\n");
return false;
}
- if (u32(*param >> 60) != 0)
- {
- util::stream_format(stream, zerofill ? "%0*o" : "%*o", (width <= 20) ? 1 : width - 20, u32(*param >> 60));
- util::stream_format(stream, "%0*o", 10, u32(BIT(*param, 30, 30)));
- }
- else
- {
- if (width > 20)
- util::stream_format(stream, zerofill ? "%0*o" : "%*o", width - 20, 0);
- if (u32(BIT(*param, 30, 30)) != 0)
- util::stream_format(stream, zerofill ? "%0*o" : "%*o", (width <= 10) ? 1 : width - 10, u32(BIT(*param, 30, 30)));
- else if (width > 10)
- util::stream_format(stream, zerofill ? "%0*o" : "%*o", width - 10, 0);
- }
- util::stream_format(stream, 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 false;
}
- util::stream_format(stream, 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 false;
}
- stream << 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;
}
}
@@ -630,15 +680,9 @@ void debugger_commands::execute_index_command(std::vector<std::string_view> cons
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 (!m_console.validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
std::ostringstream buffer;
- if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ if (mini_printf(buffer, params))
m_console.printf("%s\n", std::move(buffer).str());
}
@@ -649,15 +693,9 @@ void debugger_commands::execute_printf(const std::vector<std::string_view> &para
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 (!m_console.validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
std::ostringstream buffer;
- if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ if (mini_printf(buffer, params))
m_machine.logerror("%s", std::move(buffer).str());
}
@@ -668,15 +706,9 @@ void debugger_commands::execute_logerror(const std::vector<std::string_view> &pa
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 (!m_console.validate_number_parameter(params[i], values[i]))
- return;
-
/* then do a printf */
std::ostringstream buffer;
- if (mini_printf(buffer, params[0], params.size() - 1, &values[1]))
+ if (mini_printf(buffer, params))
m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -688,12 +720,11 @@ void debugger_commands::execute_tracelog(const std::vector<std::string_view> &pa
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];
+ std::ostringstream format;
for (int i = 0; i < params.size(); i++)
{
// find this symbol
- symbol_entry *sym = m_console.visible_symtable().find(strmakelower(params[i]).c_str());
+ symbol_entry *const sym = m_console.visible_symtable().find(strmakelower(params[i]).c_str());
if (!sym)
{
m_console.printf("Unknown symbol: %s\n", params[i]);
@@ -704,15 +735,18 @@ void debugger_commands::execute_tracesym(const std::vector<std::string_view> &pa
util::stream_format(format, "%s=%s ",
params[i],
sym->format().empty() ? "%16X" : sym->format());
-
- // validate the parameter
- if (!m_console.validate_number_parameter(params[i], values[i]))
- return;
}
+ // build parameters for printf
+ auto const format_str = std::move(format).str(); // need this to stay put as long as the string_view exists
+ std::vector<std::string_view> printf_params;
+ printf_params.reserve(params.size() + 1);
+ printf_params.emplace_back(format_str);
+ std::copy(params.begin(), params.end(), std::back_inserter(printf_params));
+
// then do a printf
std::ostringstream buffer;
- if (mini_printf(buffer, format.str(), params.size(), values))
+ if (mini_printf(buffer, printf_params))
m_console.get_visible_cpu()->debug()->trace_printf("%s", std::move(buffer).str());
}
@@ -3483,16 +3517,16 @@ void debugger_commands::execute_trace(const std::vector<std::string_view> &param
using namespace std::literals;
if (!util::streqlower(filename, "off"sv))
{
- std::ios_base::openmode mode = std::ios_base::out;
+ std::ios_base::openmode mode;
// opening for append?
if ((filename[0] == '>') && (filename[1] == '>'))
{
- mode |= std::ios_base::ate;
+ mode = std::ios_base::in | std::ios_base::out | std::ios_base::ate;
filename = filename.substr(2);
}
else
- mode |= std::ios_base::trunc;
+ mode = std::ios_base::out | std::ios_base::trunc;
f = std::make_unique<std::ofstream>(filename.c_str(), mode);
if (f->fail())
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index 97d1a628ab5..cf38c6d903a 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -13,9 +13,6 @@
#pragma once
-#include "debugcpu.h"
-#include "debugcon.h"
-
#include <string_view>
@@ -73,7 +70,7 @@ private:
u64 global_get(global_entry *global);
void global_set(global_entry *global, u64 value);
- bool mini_printf(std::ostream &stream, std::string_view 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_view> const &params, T &&apply, char const *unused_message);
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 5c5a186e2aa..968966b1b74 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -25,7 +25,6 @@
#include "uiinput.h"
#include "corestr.h"
-#include "coreutil.h"
#include "osdepend.h"
#include "xmlfile.h"
@@ -410,6 +409,70 @@ void debugger_cpu::halt_on_next_instruction(device_t *device, util::format_argum
}
}
+
+//-------------------------------------------------
+// wait_for_debugger - pause during execution to
+// allow debugging
+//-------------------------------------------------
+
+void debugger_cpu::wait_for_debugger(device_t &device)
+{
+ assert(is_stopped());
+ assert(within_instruction_hook());
+
+ bool firststop = true;
+
+ // load comments if we haven't yet
+ ensure_comments_loaded();
+
+ // reset any transient state
+ reset_transient_flags();
+ set_break_cpu(nullptr);
+
+ // remember the last visible CPU in the debugger
+ m_machine.debugger().console().set_visible_cpu(&device);
+
+ // update all views
+ m_machine.debug_view().update_all();
+ m_machine.debugger().refresh_display();
+
+ // wait for the debugger; during this time, disable sound output
+ m_machine.sound().debugger_mute(true);
+ while (is_stopped())
+ {
+ // flush any pending updates before waiting again
+ m_machine.debug_view().flush_osd_updates();
+
+ emulator_info::periodic_check();
+
+ // clear the memory modified flag and wait
+ set_memory_modified(false);
+ if (m_machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
+ m_machine.osd().wait_for_debugger(device, firststop);
+ firststop = false;
+
+ // if something modified memory, update the screen
+ if (memory_modified())
+ {
+ m_machine.debug_view().update_all(DVT_DISASSEMBLY);
+ m_machine.debug_view().update_all(DVT_STATE);
+ m_machine.debugger().refresh_display();
+ }
+
+ // check for commands in the source file
+ m_machine.debugger().console().process_source_file();
+
+ // if an event got scheduled, resume
+ if (m_machine.scheduled_event_pending())
+ set_execution_running();
+ }
+ m_machine.sound().debugger_mute(false);
+
+ // remember the last visible CPU in the debugger
+ m_machine.debugger().console().set_visible_cpu(&device);
+}
+
+
//**************************************************************************
// DEVICE DEBUG
//**************************************************************************
@@ -436,6 +499,7 @@ device_debug::device_debug(device_t &device)
, m_endexectime(attotime::zero)
, m_total_cycles(0)
, m_last_total_cycles(0)
+ , m_was_waiting(true)
, m_pc_history_index(0)
, m_pc_history_valid(0)
, m_bplist()
@@ -639,6 +703,13 @@ void device_debug::stop_hook()
void device_debug::interrupt_hook(int irqline, offs_t pc)
{
+ // CPU is presumably no longer waiting if it acknowledges an interrupt
+ if (m_was_waiting)
+ {
+ m_was_waiting = false;
+ compute_debug_flags();
+ }
+
// see if this matches a pending interrupt request
if ((m_flags & DEBUG_FLAG_STOP_INTERRUPT) != 0 && (m_stopirq == -1 || m_stopirq == irqline))
{
@@ -773,6 +844,7 @@ void device_debug::privilege_hook()
}
}
+
//-------------------------------------------------
// instruction_hook - called by the CPU cores
// before executing each instruction
@@ -781,7 +853,7 @@ void device_debug::privilege_hook()
void device_debug::instruction_hook(offs_t curpc)
{
running_machine &machine = m_device.machine();
- debugger_cpu& debugcpu = machine.debugger().cpu();
+ debugger_cpu &debugcpu = machine.debugger().cpu();
// note that we are in the debugger code
debugcpu.set_within_instruction(true);
@@ -795,6 +867,11 @@ void device_debug::instruction_hook(offs_t curpc)
// update total cycles
m_last_total_cycles = m_total_cycles;
m_total_cycles = m_exec->total_cycles();
+ if (m_was_waiting)
+ {
+ m_was_waiting = false;
+ compute_debug_flags();
+ }
// are we tracking our recent pc visits?
if (m_track_pc)
@@ -866,7 +943,7 @@ void device_debug::instruction_hook(offs_t curpc)
}
// handle breakpoints
- if (!debugcpu.is_stopped() && (m_flags & (DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0)
+ if (!debugcpu.is_stopped() && (m_flags & (DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP | DEBUG_FLAG_LIVE_RP)) != 0)
{
// see if we hit a target time
if ((m_flags & DEBUG_FLAG_STOP_TIME) != 0 && machine.time() >= m_stoptime)
@@ -886,68 +963,68 @@ void device_debug::instruction_hook(offs_t curpc)
}
// check for execution breakpoints
- else if ((m_flags & DEBUG_FLAG_LIVE_BP) != 0)
- breakpoint_check(curpc);
+ else
+ {
+ if ((m_flags & DEBUG_FLAG_LIVE_BP) != 0)
+ breakpoint_check(curpc);
+ if ((m_flags & DEBUG_FLAG_LIVE_RP) != 0)
+ registerpoint_check();
+ }
}
// if we are supposed to halt, do it now
if (debugcpu.is_stopped())
- {
- bool firststop = true;
-
- // load comments if we haven't yet
- debugcpu.ensure_comments_loaded();
+ debugcpu.wait_for_debugger(m_device);
- // reset any transient state
- debugcpu.reset_transient_flags();
- debugcpu.set_break_cpu(nullptr);
-
- // remember the last visible CPU in the debugger
- machine.debugger().console().set_visible_cpu(&m_device);
+ // handle step out/over on the instruction we are about to execute
+ 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());
- // update all views
- machine.debug_view().update_all();
- machine.debugger().refresh_display();
+ // no longer in debugger code
+ debugcpu.set_within_instruction(false);
+}
- // wait for the debugger; during this time, disable sound output
- m_device.machine().sound().debugger_mute(true);
- while (debugcpu.is_stopped())
- {
- // flush any pending updates before waiting again
- machine.debug_view().flush_osd_updates();
- emulator_info::periodic_check();
+//-------------------------------------------------
+// wait_hook - called by the CPU cores while
+// waiting indefinitely for some kind of event
+//-------------------------------------------------
- // clear the memory modified flag and wait
- debugcpu.set_memory_modified(false);
- if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
- machine.osd().wait_for_debugger(m_device, firststop);
- firststop = false;
+void device_debug::wait_hook()
+{
+ running_machine &machine = m_device.machine();
+ debugger_cpu &debugcpu = machine.debugger().cpu();
- // if something modified memory, update the screen
- if (debugcpu.memory_modified())
- {
- machine.debug_view().update_all(DVT_DISASSEMBLY);
- machine.debug_view().update_all(DVT_STATE);
- machine.debugger().refresh_display();
- }
+ // note that we are in the debugger code
+ debugcpu.set_within_instruction(true);
- // check for commands in the source file
- machine.debugger().console().process_source_file();
+ // update total cycles
+ m_last_total_cycles = m_total_cycles;
+ m_total_cycles = m_exec->total_cycles();
- // if an event got scheduled, resume
- if (machine.scheduled_event_pending())
- debugcpu.set_execution_running();
+ // handle registerpoints (but not breakpoints)
+ if (!debugcpu.is_stopped() && (m_flags & (DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_LIVE_RP)) != 0)
+ {
+ // see if we hit a target time
+ if ((m_flags & DEBUG_FLAG_STOP_TIME) != 0 && machine.time() >= m_stoptime)
+ {
+ machine.debugger().console().printf("Stopped at time interval %.1g\n", machine.time().as_double());
+ debugcpu.set_execution_stopped();
}
- machine.sound().debugger_mute(false);
-
- // remember the last visible CPU in the debugger
- machine.debugger().console().set_visible_cpu(&m_device);
+ else if ((m_flags & DEBUG_FLAG_LIVE_RP) != 0)
+ registerpoint_check();
}
- // handle step out/over on the instruction we are about to execute
- 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());
+ // if we are supposed to halt, do it now
+ if (debugcpu.is_stopped())
+ {
+ if (!m_was_waiting)
+ {
+ machine.debugger().console().printf("CPU waiting after PC=%s\n", m_state->state_string(STATE_GENPCBASE));
+ m_was_waiting = true;
+ }
+ debugcpu.wait_for_debugger(m_device);
+ }
// no longer in debugger code
debugcpu.set_within_instruction(false);
@@ -1727,7 +1804,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());
}
@@ -1754,7 +1831,7 @@ void device_debug::trace(std::unique_ptr<std::ostream> &&file, bool trace_over,
void device_debug::compute_debug_flags()
{
running_machine &machine = m_device.machine();
- debugger_cpu& debugcpu = machine.debugger().cpu();
+ debugger_cpu &debugcpu = machine.debugger().cpu();
// clear out global flags by default, keep DEBUG_FLAG_OSD_ENABLED
machine.debug_flags &= DEBUG_FLAG_OSD_ENABLED;
@@ -1770,7 +1847,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_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 | DEBUG_FLAG_LIVE_RP)) != 0)
machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
// also call if we are tracing
@@ -1780,6 +1857,10 @@ void device_debug::compute_debug_flags()
// if we are stopping at a particular time and that time is within the current timeslice, we need to be called
if ((m_flags & DEBUG_FLAG_STOP_TIME) && m_endexectime <= m_stoptime)
machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
+
+ // if we were waiting, call if only to clear
+ if (m_was_waiting)
+ machine.debug_flags |= DEBUG_FLAG_CALL_HOOK;
}
@@ -1860,7 +1941,7 @@ void device_debug::prepare_for_step_overout(offs_t pc)
void device_debug::breakpoint_update_flags()
{
// see if there are any enabled breakpoints
- m_flags &= ~DEBUG_FLAG_LIVE_BP;
+ m_flags &= ~(DEBUG_FLAG_LIVE_BP | DEBUG_FLAG_LIVE_RP);
for (auto &bpp : m_bplist)
if (bpp.second->m_enabled)
{
@@ -1868,16 +1949,13 @@ void device_debug::breakpoint_update_flags()
break;
}
- if (!(m_flags & DEBUG_FLAG_LIVE_BP))
+ // see if there are any enabled registerpoints
+ for (debug_registerpoint &rp : m_rplist)
{
- // see if there are any enabled registerpoints
- for (debug_registerpoint &rp : m_rplist)
+ if (rp.m_enabled)
{
- if (rp.m_enabled)
- {
- m_flags |= DEBUG_FLAG_LIVE_BP;
- break;
- }
+ m_flags |= DEBUG_FLAG_LIVE_RP;
+ break;
}
}
@@ -1894,8 +1972,6 @@ void device_debug::breakpoint_update_flags()
void device_debug::breakpoint_check(offs_t pc)
{
- debugger_cpu& debugcpu = m_device.machine().debugger().cpu();
-
// see if we match
auto bpitp = m_bplist.equal_range(pc);
for (auto bpit = bpitp.first; bpit != bpitp.second; ++bpit)
@@ -1903,6 +1979,8 @@ void device_debug::breakpoint_check(offs_t pc)
debug_breakpoint &bp = *bpit->second;
if (bp.hit(pc))
{
+ debugger_cpu &debugcpu = m_device.machine().debugger().cpu();
+
// halt in the debugger by default
debugcpu.set_execution_stopped();
@@ -1919,12 +1997,23 @@ void device_debug::breakpoint_check(offs_t pc)
break;
}
}
+}
+
+//-------------------------------------------------
+// registerpoint_check - check the registerpoints
+// for a given device
+//-------------------------------------------------
+
+void device_debug::registerpoint_check()
+{
// see if we have any matching registerpoints
for (debug_registerpoint &rp : m_rplist)
{
if (rp.hit())
{
+ debugger_cpu &debugcpu = m_device.machine().debugger().cpu();
+
// halt in the debugger by default
debugcpu.set_execution_stopped();
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 9a9f6e69f70..631d4c788d9 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -55,6 +55,7 @@ public:
void exception_hook(int exception);
void privilege_hook();
void instruction_hook(offs_t curpc);
+ void wait_hook();
// debugger focus
void ignore(bool ignore = true);
@@ -174,6 +175,7 @@ private:
// breakpoint and watchpoint helpers
void breakpoint_update_flags();
void breakpoint_check(offs_t pc);
+ void registerpoint_check();
void reinstall_all(read_or_write mode);
void reinstall(address_space &space, read_or_write mode);
void write_tracking(address_space &space, offs_t address, u64 data);
@@ -204,6 +206,7 @@ private:
attotime m_endexectime; // ending time of the current execution
u64 m_total_cycles; // current total cycles
u64 m_last_total_cycles; // last total cycles
+ bool m_was_waiting; // true if no instruction executed since last wait
// history
offs_t m_pc_history[HISTORY_SIZE]; // history of recent PCs
@@ -328,7 +331,8 @@ private:
static constexpr u32 DEBUG_FLAG_STOP_VBLANK = 0x00001000; // there is a pending stop on the next VBLANK
static constexpr u32 DEBUG_FLAG_STOP_TIME = 0x00002000; // there is a pending stop at cpu->stoptime
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_LIVE_BP = 0x00008000; // there are live breakpoints for this CPU
+ static constexpr u32 DEBUG_FLAG_LIVE_RP = 0x00010000; // there are live registerpoints 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
@@ -409,6 +413,7 @@ public:
void halt_on_next_instruction(device_t *device, util::format_argument_pack<char> &&args);
void ensure_comments_loaded();
void reset_transient_flags();
+ void wait_for_debugger(device_t &device);
private:
static const size_t NUM_TEMP_VARIABLES;
diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp
index ee455bd84f8..8e5fa1b9c64 100644
--- a/src/emu/debug/debughlp.cpp
+++ b/src/emu/debug/debughlp.cpp
@@ -46,7 +46,7 @@ const help_item f_static_help_list[] =
" Breakpoints\n"
" Watchpoints\n"
" Registerpoints\n"
- " Exception Points\n"
+ " Exceptionpoints\n"
" Expressions\n"
" Comments\n"
" Cheats\n"
@@ -195,14 +195,14 @@ const help_item f_static_help_list[] =
{
"exceptionpoints",
"\n"
- "Exception Point Commands\n"
+ "Exceptionpoint 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"
+ " ep[set] <type>[,<condition>[,<action>]] -- sets exceptionpoint on <type>\n"
+ " epclear [<epnum>] -- clears a given exceptionpoint or all if no <epnum> specified\n"
+ " epdisable [<epnum>] -- disabled a given exceptionpoint or all if no <epnum> specified\n"
+ " epenable [<epnum>] -- enables a given exceptionpoint or all if no <epnum> specified\n"
+ " eplist -- lists all the exceptionpoints\n"
},
{
"expressions",
@@ -359,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"
@@ -379,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"
@@ -1594,12 +1592,12 @@ const help_item f_static_help_list[] =
"\n"
" ep[set] <type>[,<condition>[,<action>]]\n"
"\n"
- "Sets a new exception point for exceptions of type <type> on the currently visible CPU. "
+ "Sets a new exceptionpoint 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; "
+ "each time the exceptionpoint is hit. If the result of the expression is true (non-zero), "
+ "the exceptionpoint 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 "
+ "provides a command that is executed whenever the exceptionpoint 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"
@@ -1608,8 +1606,8 @@ const help_item f_static_help_list[] =
"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"
+ "Each exceptionpoint that is set is assigned an index which can be used in other "
+ "exceptionpoint commands to reference this exceptionpoint.\n"
"\n"
"Examples:\n"
"\n"
@@ -1622,57 +1620,57 @@ const help_item f_static_help_list[] =
"\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"
+ "The epclear command clears exceptionpoints. If <epnum> is specified, only the requested "
+ "exceptionpoints are cleared, otherwise all exceptionpoints are cleared.\n"
"\n"
"Examples:\n"
"\n"
"epclear 3\n"
- " Clear exception point index 3.\n"
+ " Clear exceptionpoint index 3.\n"
"\n"
"epclear\n"
- " Clear all exception points.\n"
+ " Clear all exceptionpoints.\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"
+ "The epdisable command disables exceptionpoints. If <epnum> is specified, only the requested "
+ "exceptionpoints are disabled, otherwise all exceptionpoints are disabled. Note that "
+ "disabling an exceptionpoint does not delete it, it just temporarily marks the "
+ "exceptionpoint as inactive.\n"
"\n"
"Examples:\n"
"\n"
"epdisable 3\n"
- " Disable exception point index 3.\n"
+ " Disable exceptionpoint index 3.\n"
"\n"
"epdisable\n"
- " Disable all exception points.\n"
+ " Disable all exceptionpoints.\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"
+ "The epenable command enables exceptionpoints. If <epnum> is specified, only the "
+ "requested exceptionpoints are enabled, otherwise all exceptionpoints are enabled.\n"
"\n"
"Examples:\n"
"\n"
"epenable 3\n"
- " Enable exception point index 3.\n"
+ " Enable exceptionpoint index 3.\n"
"\n"
"epenable\n"
- " Enable all exception points.\n"
+ " Enable all exceptionpoints.\n"
},
{
"eplist",
"\n"
" eplist\n"
"\n"
- "The eplist command lists all the current exception points, along with their index and "
+ "The eplist command lists all the current exceptionpoints, along with their index and "
"any conditions or actions attached to them.\n"
},
{
diff --git a/src/emu/debug/debugvw.cpp b/src/emu/debug/debugvw.cpp
index 54fe57ecf5a..7412ddd2f60 100644
--- a/src/emu/debug/debugvw.cpp
+++ b/src/emu/debug/debugvw.cpp
@@ -14,6 +14,7 @@
#include "debugcpu.h"
#include "dvbpoints.h"
#include "dvdisasm.h"
+#include "dvepoints.h"
#include "dvmemory.h"
#include "dvrpoints.h"
#include "dvstate.h"
@@ -369,6 +370,9 @@ debug_view *debug_view_manager::alloc_view(debug_view_type type, debug_view_osd_
case DVT_REGISTER_POINTS:
return append(new debug_view_registerpoints(machine(), osdupdate, osdprivate));
+ case DVT_EXCEPTION_POINTS:
+ return append(new debug_view_exceptionpoints(machine(), osdupdate, osdprivate));
+
default:
fatalerror("Attempt to create invalid debug view type %d\n", type);
}
diff --git a/src/emu/debug/debugvw.h b/src/emu/debug/debugvw.h
index 73f93d14f32..64bd5dac10a 100644
--- a/src/emu/debug/debugvw.h
+++ b/src/emu/debug/debugvw.h
@@ -35,7 +35,8 @@ enum debug_view_type
DVT_LOG,
DVT_BREAK_POINTS,
DVT_WATCH_POINTS,
- DVT_REGISTER_POINTS
+ DVT_REGISTER_POINTS,
+ DVT_EXCEPTION_POINTS
};
diff --git a/src/emu/debug/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp
index d7be62c1eaa..0290f8719dc 100644
--- a/src/emu/debug/dvbpoints.cpp
+++ b/src/emu/debug/dvbpoints.cpp
@@ -9,8 +9,9 @@
***************************************************************************/
#include "emu.h"
-#include "debugger.h"
#include "dvbpoints.h"
+
+#include "debugcpu.h"
#include "points.h"
#include <algorithm>
diff --git a/src/emu/debug/dvbpoints.h b/src/emu/debug/dvbpoints.h
index 1bf365f521e..be291fa66d8 100644
--- a/src/emu/debug/dvbpoints.h
+++ b/src/emu/debug/dvbpoints.h
@@ -12,7 +12,6 @@
#pragma once
-#include "debugcpu.h"
#include "debugvw.h"
#include <vector>
diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp
index 0dcc0b98982..17cc766ef94 100644
--- a/src/emu/debug/dvdisasm.cpp
+++ b/src/emu/debug/dvdisasm.cpp
@@ -9,10 +9,11 @@
***************************************************************************/
#include "emu.h"
-#include "debugvw.h"
#include "dvdisasm.h"
+
+#include "debugbuf.h"
#include "debugcpu.h"
-#include "debugger.h"
+
//**************************************************************************
// DEBUG VIEW DISASM SOURCE
@@ -394,25 +395,25 @@ void debug_view_disasm::view_update()
// print - print a string in the disassembly view
//-------------------------------------------------
-void debug_view_disasm::print(int row, std::string text, int start, int end, u8 attrib)
+void debug_view_disasm::print(u32 row, std::string text, s32 start, s32 end, u8 attrib)
{
- int view_end = end - m_topleft.x;
+ s32 view_end = end - m_topleft.x;
if(view_end < 0)
return;
- int string_0 = start - m_topleft.x;
+ s32 string_0 = start - m_topleft.x;
if(string_0 >= m_visible.x)
return;
- int view_start = string_0 > 0 ? string_0 : 0;
+ s32 view_start = string_0 > 0 ? string_0 : 0;
debug_view_char *dest = &m_viewdata[row * m_visible.x + view_start];
if(view_end >= m_visible.x)
view_end = m_visible.x;
- for(int pos = view_start; pos < view_end; pos++) {
- int spos = pos - string_0;
- if(spos >= int(text.size()))
+ for(s32 pos = view_start; pos < view_end; pos++) {
+ s32 spos = pos - string_0;
+ if(spos >= s32(text.size()))
*dest++ = { ' ', attrib };
else
*dest++ = { u8(text[spos]), attrib };
@@ -427,13 +428,15 @@ void debug_view_disasm::print(int row, std::string text, int start, int end, u8
void debug_view_disasm::redraw()
{
// determine how many characters we need for an address and set the divider
- int m_divider1 = 1 + m_dasm[0].m_tadr.size() + 1;
+ s32 divider1 = 1 + m_dasm[0].m_tadr.size() + 1;
// assume a fixed number of characters for the disassembly
- int m_divider2 = m_divider1 + 1 + m_dasm_width + 1;
+ s32 divider2 = divider1 + 1 + m_dasm_width + 1;
// set the width of the third column to max comment length
- m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH
+ m_total.x = divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH
+
+ const s32 max_visible_col = m_topleft.x + m_visible.x;
// loop over visible rows
for(u32 row = 0; row < m_visible.y; row++)
@@ -460,22 +463,22 @@ void debug_view_disasm::redraw()
if(m_dasm[effrow].m_is_visited)
attrib |= DCA_VISITED;
- print(row, ' ' + m_dasm[effrow].m_tadr, 0, m_divider1, attrib | DCA_ANCILLARY);
- print(row, ' ' + m_dasm[effrow].m_dasm, m_divider1, m_divider2, attrib);
+ print(row, ' ' + m_dasm[effrow].m_tadr, 0, divider1, attrib | DCA_ANCILLARY);
+ print(row, ' ' + m_dasm[effrow].m_dasm, divider1, divider2, attrib);
if(m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) {
std::string text = ' ' +(m_right_column == DASM_RIGHTCOL_RAW ? m_dasm[effrow].m_topcodes : m_dasm[effrow].m_tparams);
- print(row, text, m_divider2, m_visible.x, attrib | DCA_ANCILLARY);
- if(int(text.size()) > m_visible.x - m_divider2) {
- int base = m_total.x - 3;
- if(base < m_divider2)
- base = m_divider2;
- print(row, "...", base, m_visible.x, attrib | DCA_ANCILLARY);
+ print(row, text, divider2, max_visible_col, attrib | DCA_ANCILLARY);
+ if(s32(text.size()) > max_visible_col - divider2) {
+ s32 base = max_visible_col - 3;
+ if(base < divider2)
+ base = divider2;
+ print(row, "...", base, max_visible_col, attrib | DCA_ANCILLARY);
}
} else if(!m_dasm[effrow].m_comment.empty())
- print(row, " // " + m_dasm[effrow].m_comment, m_divider2, m_visible.x, attrib | DCA_COMMENT | DCA_ANCILLARY);
+ print(row, " // " + m_dasm[effrow].m_comment, divider2, max_visible_col, attrib | DCA_COMMENT | DCA_ANCILLARY);
else
- print(row, "", m_divider2, m_visible.x, attrib | DCA_COMMENT | DCA_ANCILLARY);
+ print(row, "", divider2, max_visible_col, attrib | DCA_COMMENT | DCA_ANCILLARY);
}
}
}
diff --git a/src/emu/debug/dvdisasm.h b/src/emu/debug/dvdisasm.h
index 0a16f95d5fe..ef4c5e9cf87 100644
--- a/src/emu/debug/dvdisasm.h
+++ b/src/emu/debug/dvdisasm.h
@@ -14,9 +14,6 @@
#pragma once
#include "debugvw.h"
-#include "debugbuf.h"
-
-#include "vecstream.h"
//**************************************************************************
@@ -38,6 +35,9 @@ enum disasm_right_column
// TYPE DEFINITIONS
//**************************************************************************
+// forward declaration
+class debug_disasm_buffer;
+
// a disassembly view_source
class debug_view_disasm_source : public debug_view_source
{
@@ -119,7 +119,7 @@ private:
void complete_information(const debug_view_disasm_source &source, debug_disasm_buffer &buffer, offs_t pc);
void enumerate_sources();
- void print(int row, std::string text, int start, int end, u8 attrib);
+ void print(u32 row, std::string text, s32 start, s32 end, u8 attrib);
void redraw();
// internal state
diff --git a/src/emu/debug/dvepoints.cpp b/src/emu/debug/dvepoints.cpp
new file mode 100644
index 00000000000..2ebc53a6609
--- /dev/null
+++ b/src/emu/debug/dvepoints.cpp
@@ -0,0 +1,314 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrew Gardner, Vas Crabb
+/*********************************************************************
+
+ dvepoints.cpp
+
+ Exceptionpoint debugger view.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "dvepoints.h"
+
+#include "debugcpu.h"
+#include "points.h"
+
+#include <algorithm>
+#include <iomanip>
+
+
+
+// Sorting functors for the qsort function
+static bool cIndexAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return a->index() < b->index();
+}
+
+static bool cIndexDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cIndexAscending(b, a);
+}
+
+static bool cEnabledAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return !a->enabled() && b->enabled();
+}
+
+static bool cEnabledDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cEnabledAscending(b, a);
+}
+
+static bool cCpuAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return strcmp(a->debugInterface()->device().tag(), b->debugInterface()->device().tag()) < 0;
+}
+
+static bool cCpuDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cCpuAscending(b, a);
+}
+
+static bool cTypeAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return a->type() < b->type();
+}
+
+static bool cTypeDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cTypeAscending(b, a);
+}
+
+static bool cConditionAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return strcmp(a->condition(), b->condition()) < 0;
+}
+
+static bool cConditionDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cConditionAscending(b, a);
+}
+
+static bool cActionAscending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return a->action() < b->action();
+}
+
+static bool cActionDescending(const debug_exceptionpoint *a, const debug_exceptionpoint *b)
+{
+ return cActionAscending(b, a);
+}
+
+
+//**************************************************************************
+// DEBUG VIEW BREAK POINTS
+//**************************************************************************
+
+static const int tableBreaks[] = { 5, 9, 31, 45, 63, 80 };
+
+
+//-------------------------------------------------
+// debug_view_exceptionpoints - constructor
+//-------------------------------------------------
+
+debug_view_exceptionpoints::debug_view_exceptionpoints(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
+ : debug_view(machine, DVT_EXCEPTION_POINTS, osdupdate, osdprivate)
+ , m_sortType(cIndexAscending)
+{
+ // fail if no available sources
+ enumerate_sources();
+ if (m_source_list.empty())
+ throw std::bad_alloc();
+}
+
+
+//-------------------------------------------------
+// ~debug_view_exceptionpoints - destructor
+//-------------------------------------------------
+
+debug_view_exceptionpoints::~debug_view_exceptionpoints()
+{
+}
+
+
+//-------------------------------------------------
+// enumerate_sources - enumerate all possible
+// sources for a disassembly view
+//-------------------------------------------------
+
+void debug_view_exceptionpoints::enumerate_sources()
+{
+ // start with an empty list
+ m_source_list.clear();
+
+ // iterate over devices with disassembly interfaces
+ for (device_disasm_interface &dasm : disasm_interface_enumerator(machine().root_device()))
+ {
+ m_source_list.emplace_back(
+ std::make_unique<debug_view_source>(
+ util::string_format("%s '%s'", dasm.device().name(), dasm.device().tag()),
+ &dasm.device()));
+ }
+
+ // reset the source to a known good entry
+ if (!m_source_list.empty())
+ set_source(*m_source_list[0]);
+}
+
+
+//-------------------------------------------------
+// view_click - handle a mouse click within the
+// current view
+//-------------------------------------------------
+
+void debug_view_exceptionpoints::view_click(const int button, const debug_view_xy& pos)
+{
+ bool clickedTopRow = (m_topleft.y == pos.y);
+
+ if (clickedTopRow)
+ {
+ if (pos.x < tableBreaks[0])
+ m_sortType = (m_sortType == &cIndexAscending) ? &cIndexDescending : &cIndexAscending;
+ else if (pos.x < tableBreaks[1])
+ m_sortType = (m_sortType == &cEnabledAscending) ? &cEnabledDescending : &cEnabledAscending;
+ else if (pos.x < tableBreaks[2])
+ m_sortType = (m_sortType == &cCpuAscending) ? &cCpuDescending : &cCpuAscending;
+ else if (pos.x < tableBreaks[3])
+ m_sortType = (m_sortType == &cTypeAscending) ? &cTypeDescending : &cTypeAscending;
+ else if (pos.x < tableBreaks[4])
+ m_sortType = (m_sortType == &cConditionAscending) ? &cConditionDescending : &cConditionAscending;
+ else if (pos.x < tableBreaks[5])
+ m_sortType = (m_sortType == &cActionAscending) ? &cActionDescending : &cActionAscending;
+ }
+ else
+ {
+ // Gather a sorted list of all the exceptionpoints for all the CPUs
+ gather_exceptionpoints();
+
+ int epIndex = pos.y - 1;
+ if ((epIndex >= m_buffer.size()) || (epIndex < 0))
+ return;
+
+ // Enable / disable
+ const_cast<debug_exceptionpoint &>(*m_buffer[epIndex]).setEnabled(!m_buffer[epIndex]->enabled());
+
+ machine().debug_view().update_all(DVT_DISASSEMBLY);
+ }
+
+ begin_update();
+ m_update_pending = true;
+ end_update();
+}
+
+
+void debug_view_exceptionpoints::pad_ostream_to_length(std::ostream& str, int len)
+{
+ auto const current = str.tellp();
+ if (current < decltype(current)(len))
+ str << std::setw(decltype(current)(len) - current) << "";
+}
+
+
+void debug_view_exceptionpoints::gather_exceptionpoints()
+{
+ m_buffer.resize(0);
+ for (auto &source : m_source_list)
+ {
+ // Collect
+ device_debug &debugInterface = *source->device()->debug();
+ for (const auto &epp : debugInterface.exceptionpoint_list())
+ m_buffer.push_back(epp.second.get());
+ }
+
+ // And now for the sort
+ if (!m_buffer.empty())
+ std::stable_sort(m_buffer.begin(), m_buffer.end(), m_sortType);
+}
+
+
+//-------------------------------------------------
+// view_update - update the contents of the
+// exceptionpoints view
+//-------------------------------------------------
+
+void debug_view_exceptionpoints::view_update()
+{
+ // Gather a list of all the exceptionpoints for all the CPUs
+ gather_exceptionpoints();
+
+ // Set the view region so the scroll bars update
+ m_total.x = tableBreaks[std::size(tableBreaks) - 1];
+ m_total.y = m_buffer.size() + 1;
+ if (m_total.y < 10)
+ m_total.y = 10;
+
+ // Draw
+ debug_view_char *dest = &m_viewdata[0];
+ util::ovectorstream linebuf;
+ linebuf.reserve(std::size(tableBreaks) - 1);
+
+ // Header
+ if (m_visible.y > 0)
+ {
+ linebuf.clear();
+ linebuf.rdbuf()->clear();
+ linebuf << "ID";
+ if (m_sortType == &cIndexAscending) linebuf.put('\\');
+ else if (m_sortType == &cIndexDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[0]);
+ linebuf << "En";
+ if (m_sortType == &cEnabledAscending) linebuf.put('\\');
+ else if (m_sortType == &cEnabledDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[1]);
+ linebuf << "CPU";
+ if (m_sortType == &cCpuAscending) linebuf.put('\\');
+ else if (m_sortType == &cCpuDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[2]);
+ linebuf << "Type";
+ if (m_sortType == &cTypeAscending) linebuf.put('\\');
+ else if (m_sortType == &cTypeDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[3]);
+ linebuf << "Condition";
+ if (m_sortType == &cConditionAscending) linebuf.put('\\');
+ else if (m_sortType == &cConditionDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[4]);
+ linebuf << "Action";
+ if (m_sortType == &cActionAscending) linebuf.put('\\');
+ else if (m_sortType == &cActionDescending) linebuf.put('/');
+ pad_ostream_to_length(linebuf, tableBreaks[5]);
+
+ auto const &text(linebuf.vec());
+ for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
+ {
+ dest->byte = (i < text.size()) ? text[i] : ' ';
+ dest->attrib = DCA_ANCILLARY;
+ }
+ }
+
+ for (int row = 1; row < m_visible.y; row++)
+ {
+ // Breakpoints
+ int epi = row + m_topleft.y - 1;
+ if ((epi < m_buffer.size()) && (epi >= 0))
+ {
+ const debug_exceptionpoint *const ep = m_buffer[epi];
+
+ linebuf.clear();
+ linebuf.rdbuf()->clear();
+ util::stream_format(linebuf, "%2X", ep->index());
+ pad_ostream_to_length(linebuf, tableBreaks[0]);
+ linebuf.put(ep->enabled() ? 'X' : 'O');
+ pad_ostream_to_length(linebuf, tableBreaks[1]);
+ linebuf << ep->debugInterface()->device().tag();
+ pad_ostream_to_length(linebuf, tableBreaks[2]);
+ util::stream_format(linebuf, "%X", ep->type());
+ pad_ostream_to_length(linebuf, tableBreaks[3]);
+ if (strcmp(ep->condition(), "1"))
+ linebuf << ep->condition();
+ pad_ostream_to_length(linebuf, tableBreaks[4]);
+ linebuf << ep->action();
+ pad_ostream_to_length(linebuf, tableBreaks[5]);
+
+ auto const &text(linebuf.vec());
+ for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
+ {
+ dest->byte = (i < text.size()) ? text[i] : ' ';
+ dest->attrib = DCA_NORMAL;
+
+ // Color disabled exceptionpoints red
+ if ((i >= tableBreaks[0]) && (i < tableBreaks[1]) && !ep->enabled())
+ dest->attrib |= DCA_CHANGED;
+ }
+ }
+ else
+ {
+ // Fill the remaining vertical space
+ for (u32 i = m_topleft.x; i < (m_topleft.x + m_visible.x); i++, dest++)
+ {
+ dest->byte = ' ';
+ dest->attrib = DCA_NORMAL;
+ }
+ }
+ }
+}
diff --git a/src/emu/debug/dvepoints.h b/src/emu/debug/dvepoints.h
new file mode 100644
index 00000000000..3b042218e2a
--- /dev/null
+++ b/src/emu/debug/dvepoints.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrew Gardner, Vas Crabb
+/*********************************************************************
+
+ dvepoints.h
+
+ Exceptionpoint debugger view.
+
+***************************************************************************/
+#ifndef MAME_EMU_DEBUG_DVEPOINTS_H
+#define MAME_EMU_DEBUG_DVEPOINTS_H
+
+#pragma once
+
+#include "debugvw.h"
+
+#include <vector>
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// debug view for exceptionpoints
+class debug_view_exceptionpoints : public debug_view
+{
+ friend class debug_view_manager;
+
+ // construction/destruction
+ debug_view_exceptionpoints(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate);
+ virtual ~debug_view_exceptionpoints();
+
+protected:
+ // view overrides
+ virtual void view_update() override;
+ virtual void view_click(const int button, const debug_view_xy& pos) override;
+
+private:
+ // internal helpers
+ void enumerate_sources();
+ void pad_ostream_to_length(std::ostream& str, int len);
+ void gather_exceptionpoints();
+
+ // internal state
+ bool (*m_sortType)(const debug_exceptionpoint *, const debug_exceptionpoint *);
+ std::vector<const debug_exceptionpoint *> m_buffer;
+};
+
+#endif // MAME_EMU_DEBUG_DVEPOINTS_H
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index da792305c0d..7c10407822b 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -12,7 +12,6 @@
#include "dvmemory.h"
#include "debugcpu.h"
-#include "debugger.h"
#include <algorithm>
#include <cctype>
diff --git a/src/emu/debug/dvrpoints.cpp b/src/emu/debug/dvrpoints.cpp
index 7295a1b2170..a36f42bd1d0 100644
--- a/src/emu/debug/dvrpoints.cpp
+++ b/src/emu/debug/dvrpoints.cpp
@@ -11,7 +11,7 @@
#include "emu.h"
#include "dvrpoints.h"
-#include "debugger.h"
+#include "debugcpu.h"
#include "points.h"
#include <algorithm>
diff --git a/src/emu/debug/dvrpoints.h b/src/emu/debug/dvrpoints.h
index 307ccbc212e..31b821d7fae 100644
--- a/src/emu/debug/dvrpoints.h
+++ b/src/emu/debug/dvrpoints.h
@@ -12,7 +12,6 @@
#pragma once
-#include "debugcpu.h"
#include "debugvw.h"
#include <utility>
diff --git a/src/emu/debug/dvwpoints.cpp b/src/emu/debug/dvwpoints.cpp
index 21d3f30c5ca..116904232a1 100644
--- a/src/emu/debug/dvwpoints.cpp
+++ b/src/emu/debug/dvwpoints.cpp
@@ -11,6 +11,7 @@
#include "emu.h"
#include "dvwpoints.h"
+#include "debugcpu.h"
#include "points.h"
#include <algorithm>
diff --git a/src/emu/debug/dvwpoints.h b/src/emu/debug/dvwpoints.h
index 650a0aefad5..df1145742b6 100644
--- a/src/emu/debug/dvwpoints.h
+++ b/src/emu/debug/dvwpoints.h
@@ -12,7 +12,6 @@
#pragma once
-#include "debugcpu.h"
#include "debugvw.h"
diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp
index 0d711d676d2..9ab75b7b655 100644
--- a/src/emu/debug/express.cpp
+++ b/src/emu/debug/express.cpp
@@ -1740,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/points.cpp b/src/emu/debug/points.cpp
index 961488eebb2..12e4b614843 100644
--- a/src/emu/debug/points.cpp
+++ b/src/emu/debug/points.cpp
@@ -10,8 +10,10 @@
#include "emu.h"
#include "points.h"
+
#include "debugger.h"
#include "debugcon.h"
+#include "debugcpu.h"
//**************************************************************************
diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h
index 42abd46398f..cf9e5bfc44d 100644
--- a/src/emu/debug/points.h
+++ b/src/emu/debug/points.h
@@ -13,7 +13,6 @@
#pragma once
-#include "debugcpu.h"
#include "express.h"