diff options
Diffstat (limited to 'src/emu/debug')
-rw-r--r-- | src/emu/debug/debugcmd.cpp | 188 | ||||
-rw-r--r-- | src/emu/debug/debugcmd.h | 5 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.cpp | 217 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.h | 7 | ||||
-rw-r--r-- | src/emu/debug/debughlp.cpp | 82 | ||||
-rw-r--r-- | src/emu/debug/debugvw.cpp | 4 | ||||
-rw-r--r-- | src/emu/debug/debugvw.h | 3 | ||||
-rw-r--r-- | src/emu/debug/dvbpoints.cpp | 3 | ||||
-rw-r--r-- | src/emu/debug/dvbpoints.h | 1 | ||||
-rw-r--r-- | src/emu/debug/dvdisasm.cpp | 47 | ||||
-rw-r--r-- | src/emu/debug/dvdisasm.h | 8 | ||||
-rw-r--r-- | src/emu/debug/dvepoints.cpp | 314 | ||||
-rw-r--r-- | src/emu/debug/dvepoints.h | 49 | ||||
-rw-r--r-- | src/emu/debug/dvmemory.cpp | 1 | ||||
-rw-r--r-- | src/emu/debug/dvrpoints.cpp | 2 | ||||
-rw-r--r-- | src/emu/debug/dvrpoints.h | 1 | ||||
-rw-r--r-- | src/emu/debug/dvwpoints.cpp | 1 | ||||
-rw-r--r-- | src/emu/debug/dvwpoints.h | 1 | ||||
-rw-r--r-- | src/emu/debug/express.cpp | 2 | ||||
-rw-r--r-- | src/emu/debug/points.cpp | 2 | ||||
-rw-r--r-- | src/emu/debug/points.h | 1 |
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> ¶m 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> ¶ms) { + 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> ¶ms) { - /* 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> ¶ void debugger_commands::execute_logerror(const std::vector<std::string_view> ¶ms) { - /* 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> ¶ms) { - /* 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> ¶ms) { // 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> ¶m 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> ¶ms); template <typename T> void execute_index_command(std::vector<std::string_view> const ¶ms, 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" |