From 0fa6e7eb86d3b247c46f840ef230c9331f3cc948 Mon Sep 17 00:00:00 2001 From: AJR Date: Mon, 25 May 2020 11:15:39 -0400 Subject: Debugger expression and memory access overhaul - Memory references in expressions no longer default to the console's visible CPU if no device name was specified, except when entered through the console itself. Expressions in view windows now use the context of the currently selected device instead. - The pcatmem debug command and similar qt mouseover function now produce an error message if the initial address translation fails. Related internal changes (nw) - The debugger_cpu class no longer interprets memory accesses. The existing routines have been moved into symbol_table (which used to invoke them as callbacks), and reimplemented in most other places. Thecode duplication is a bit messy, but could be potentially improved in the future with new utility classes. - The cheat engine no longer needs to hook into the debugger_cpu class or instantiate a dummy instance of it. - The inclusion of debug/express.h within emu.h has been undone. Some debugging structures now need unique_ptr to wrap the resulting incomplete classes; hopefully the performance impact of this is negligible. Another direct consequence is that the breakpoint, watchpoint and registerpoint classes are no longer inside device_debug and have their own source file. - The breakpoint list is now a std::multimap, using the addresses as keys to hopefully expedite lookup. - The visible CPU pointer has been removed from the debugger_cpu class, being now considered a property of the console instead. - Many minor bits of code have been simplified. --- src/emu/debug/debugcmd.cpp | 165 ++- src/emu/debug/debugcmd.h | 1 + src/emu/debug/debugcon.cpp | 26 +- src/emu/debug/debugcon.h | 7 + src/emu/debug/debugcpu.cpp | 1529 ++------------------ src/emu/debug/debugcpu.h | 209 +-- src/emu/debug/dvbpoints.cpp | 33 +- src/emu/debug/dvbpoints.h | 4 +- src/emu/debug/dvdisasm.cpp | 8 +- src/emu/debug/dvmemory.cpp | 230 +-- src/emu/debug/dvmemory.h | 1 + src/emu/debug/dvwpoints.cpp | 35 +- src/emu/debug/dvwpoints.h | 4 +- src/emu/debug/express.cpp | 594 +++++++- src/emu/debug/express.h | 26 +- src/emu/debug/points.cpp | 441 ++++++ src/emu/debug/points.h | 149 ++ src/emu/debugger.cpp | 2 +- src/emu/emufwd.h | 5 + src/frontend/mame/cheat.cpp | 19 +- src/frontend/mame/cheat.h | 2 - src/frontend/mame/luaengine.cpp | 10 +- src/mame/drivers/chihiro.cpp | 7 +- src/mame/drivers/konamim2.cpp | 63 +- src/mame/machine/fddebug.cpp | 12 +- src/mame/machine/xbox.cpp | 121 +- src/osd/modules/debugger/debuggdbstub.cpp | 21 +- src/osd/modules/debugger/debugimgui.cpp | 36 +- src/osd/modules/debugger/debugwin.cpp | 2 +- src/osd/modules/debugger/none.cpp | 3 +- src/osd/modules/debugger/osx/debugconsole.mm | 21 +- src/osd/modules/debugger/osx/debugview.mm | 3 +- src/osd/modules/debugger/osx/debugwindowhandler.mm | 21 +- src/osd/modules/debugger/osx/disassemblyviewer.mm | 9 +- src/osd/modules/debugger/osx/memoryview.mm | 1 - src/osd/modules/debugger/osx/memoryviewer.mm | 4 +- src/osd/modules/debugger/osx/registersview.mm | 4 +- src/osd/modules/debugger/qt/dasmwindow.cpp | 9 +- src/osd/modules/debugger/qt/mainwindow.cpp | 17 +- src/osd/modules/debugger/qt/memorywindow.cpp | 60 +- src/osd/modules/debugger/qt/windowqt.cpp | 18 +- src/osd/modules/debugger/win/consolewininfo.cpp | 4 +- src/osd/modules/debugger/win/debugviewinfo.cpp | 5 +- src/osd/modules/debugger/win/debugwininfo.cpp | 19 +- src/osd/modules/debugger/win/disasmbasewininfo.cpp | 7 +- 45 files changed, 1886 insertions(+), 2081 deletions(-) create mode 100644 src/emu/debug/points.cpp create mode 100644 src/emu/debug/points.h (limited to 'src') diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 01d2f462d50..d8e1c985d27 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles /********************************************************************* - debugcmd.c + debugcmd.cpp Debugger command interface engine. @@ -18,6 +18,7 @@ #include "express.h" #include "debughlp.h" #include "debugvw.h" +#include "points.h" #include "natkeyboard.h" #include "render.h" #include @@ -58,9 +59,9 @@ u64 debugger_commands::cheat_sign_extend(const cheat_system *cheatsys, u64 value { switch (cheatsys->width) { - case 1: value = s8(value); break; - case 2: value = s16(value); break; - case 4: value = s32(value); break; + case 1: value = s8(value); break; + case 2: value = s16(value); break; + case 4: value = s32(value); break; } } return value; @@ -76,10 +77,9 @@ u64 debugger_commands::cheat_byte_swap(const cheat_system *cheatsys, u64 value) { switch (cheatsys->width) { - case 2: value = ((value >> 8) & 0x00ff) | ((value << 8) & 0xff00); break; - case 4: value = ((value >> 24) & 0x000000ff) | ((value >> 8) & 0x0000ff00) | ((value << 8) & 0x00ff0000) | ((value << 24) & 0xff000000); break; - case 8: value = ((value >> 56) & 0x00000000000000ffU) | ((value >> 40) & 0x000000000000ff00U) | ((value >> 24) & 0x0000000000ff0000U) | ((value >> 8) & 0x00000000ff000000U) | - ((value << 8) & 0x000000ff00000000U) | ((value << 24) & 0x0000ff0000000000U) | ((value << 40) & 0x00ff000000000000U) | ((value << 56) & 0xff00000000000000U); break; + case 2: value = swapendian_int16(value); break; + case 4: value = swapendian_int32(value); break; + case 8: value = swapendian_int64(value); break; } } return value; @@ -93,7 +93,19 @@ u64 debugger_commands::cheat_byte_swap(const cheat_system *cheatsys, u64 value) u64 debugger_commands::cheat_read_extended(const cheat_system *cheatsys, address_space &space, offs_t address) { - return cheat_sign_extend(cheatsys, cheat_byte_swap(cheatsys, m_cpu.read_memory(space, address, cheatsys->width, true))); + address &= space.logaddrmask(); + u64 value = space.unmap(); + if (space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + { + switch (cheatsys->width) + { + case 1: value = space.read_byte(address); break; + case 2: value = space.read_word_unaligned(address); break; + case 4: value = space.read_dword_unaligned(address); break; + case 8: value = space.read_qword_unaligned(address); break; + } + } + return cheat_sign_extend(cheatsys, cheat_byte_swap(cheatsys, value)); } debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu, debugger_console& console) @@ -110,6 +122,7 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu symtable.add("min", 2, 2, std::bind(&debugger_commands::execute_min, this, _1, _2)); symtable.add("max", 2, 2, std::bind(&debugger_commands::execute_max, this, _1, _2)); symtable.add("if", 3, 3, std::bind(&debugger_commands::execute_if, this, _1, _2)); + symtable.add("cpunum", std::bind(&debugger_commands::get_cpunum, this)); /* add all single-entry save state globals */ for (int itemnum = 0; itemnum < MAX_GLOBALS; itemnum++) @@ -332,6 +345,17 @@ u64 debugger_commands::execute_if(int params, const u64 *param) } +//------------------------------------------------- +// get_cpunum - getter callback for the +// 'cpunum' symbol +//------------------------------------------------- + +u64 debugger_commands::get_cpunum() +{ + execute_interface_iterator iter(m_machine.root_device()); + return iter.indexof(m_console.get_visible_cpu()->execute()); +} + /*************************************************************************** GLOBAL ACCESSORS @@ -385,7 +409,7 @@ bool debugger_commands::validate_number_parameter(const std::string ¶m, u64 /* evaluate the expression; success if no error */ try { - result = parsed_expression(m_cpu.visible_symtable(), param.c_str()).execute(); + result = parsed_expression(m_console.visible_symtable(), param.c_str()).execute(); return true; } catch (expression_error &error) @@ -436,7 +460,7 @@ bool debugger_commands::validate_cpu_parameter(const char *param, device_t *&res /* if no parameter, use the visible CPU */ if (param == nullptr) { - result = m_cpu.get_visible_cpu(); + result = m_console.get_visible_cpu(); if (!result) { m_console.printf("No valid CPU is currently selected\n"); @@ -454,7 +478,7 @@ bool debugger_commands::validate_cpu_parameter(const char *param, device_t *&res u64 cpunum; try { - cpunum = parsed_expression(m_cpu.visible_symtable(), param).execute(); + cpunum = parsed_expression(m_console.visible_symtable(), param).execute(); } catch (expression_error &) { @@ -743,7 +767,7 @@ void debugger_commands::execute_tracelog(int ref, const std::vector /* then do a printf */ char buffer[1024]; if (mini_printf(buffer, params[0].c_str(), params.size() - 1, &values[1])) - m_cpu.get_visible_cpu()->debug()->trace_printf("%s", buffer); + m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer); } @@ -759,7 +783,7 @@ void debugger_commands::execute_tracesym(int ref, const std::vector for (int i = 0; i < params.size(); i++) { // find this symbol - symbol_entry *sym = m_cpu.visible_symtable().find(params[i].c_str()); + symbol_entry *sym = m_console.visible_symtable().find(params[i].c_str()); if (!sym) { m_console.printf("Unknown symbol: %s\n", params[i].c_str()); @@ -779,7 +803,7 @@ void debugger_commands::execute_tracesym(int ref, const std::vector // then do a printf char buffer[1024]; if (mini_printf(buffer, format.str().c_str(), params.size(), values)) - m_cpu.get_visible_cpu()->debug()->trace_printf("%s", buffer); + m_console.get_visible_cpu()->debug()->trace_printf("%s", buffer); } @@ -816,7 +840,7 @@ void debugger_commands::execute_step(int ref, const std::vector &pa if (params.size() > 0 && !validate_number_parameter(params[0], steps)) return; - m_cpu.get_visible_cpu()->debug()->single_step(steps); + m_console.get_visible_cpu()->debug()->single_step(steps); } @@ -831,7 +855,7 @@ void debugger_commands::execute_over(int ref, const std::vector &pa if (params.size() > 0 && !validate_number_parameter(params[0], steps)) return; - m_cpu.get_visible_cpu()->debug()->single_step_over(steps); + m_console.get_visible_cpu()->debug()->single_step_over(steps); } @@ -841,7 +865,7 @@ void debugger_commands::execute_over(int ref, const std::vector &pa void debugger_commands::execute_out(int ref, const std::vector ¶ms) { - m_cpu.get_visible_cpu()->debug()->single_step_out(); + m_console.get_visible_cpu()->debug()->single_step_out(); } @@ -857,7 +881,7 @@ void debugger_commands::execute_go(int ref, const std::vector ¶ if (params.size() > 0 && !validate_number_parameter(params[0], addr)) return; - m_cpu.get_visible_cpu()->debug()->go(addr); + m_console.get_visible_cpu()->debug()->go(addr); } @@ -868,7 +892,7 @@ void debugger_commands::execute_go(int ref, const std::vector ¶ void debugger_commands::execute_go_vblank(int ref, const std::vector ¶ms) { - m_cpu.get_visible_cpu()->debug()->go_vblank(); + m_console.get_visible_cpu()->debug()->go_vblank(); } @@ -884,7 +908,7 @@ void debugger_commands::execute_go_interrupt(int ref, const std::vector 0 && !validate_number_parameter(params[0], irqline)) return; - m_cpu.get_visible_cpu()->debug()->go_interrupt(irqline); + m_console.get_visible_cpu()->debug()->go_interrupt(irqline); } /*------------------------------------------------- @@ -899,11 +923,11 @@ void debugger_commands::execute_go_exception(int ref, const std::vector 0 && !validate_number_parameter(params[0], exception)) return; - parsed_expression condition(m_cpu.get_visible_cpu()->debug()->symtable()); + parsed_expression condition(m_console.visible_symtable()); if (params.size() > 1 && !debug_command_parameter_expression(params[1], condition)) return; - m_cpu.get_visible_cpu()->debug()->go_exception(exception, (condition.is_empty()) ? "1" : condition.original_string()); + m_console.get_visible_cpu()->debug()->go_exception(exception, (condition.is_empty()) ? "1" : condition.original_string()); } @@ -919,7 +943,7 @@ void debugger_commands::execute_go_time(int ref, const std::vector if (params.size() > 0 && !validate_number_parameter(params[0], milliseconds)) return; - m_cpu.get_visible_cpu()->debug()->go_milliseconds(milliseconds); + m_console.get_visible_cpu()->debug()->go_milliseconds(milliseconds); } @@ -929,11 +953,11 @@ void debugger_commands::execute_go_time(int ref, const std::vector -------------------------------------------------*/ void debugger_commands::execute_go_privilege(int ref, const std::vector ¶ms) { - parsed_expression condition(m_cpu.get_visible_cpu()->debug()->symtable()); + parsed_expression condition(m_console.visible_symtable()); if (params.size() > 0 && !debug_command_parameter_expression(params[0], condition)) return; - m_cpu.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string()); + m_console.get_visible_cpu()->debug()->go_privilege((condition.is_empty()) ? "1" : condition.original_string()); } /*------------------------------------------------- @@ -942,7 +966,7 @@ void debugger_commands::execute_go_privilege(int ref, const std::vector ¶ms) { - m_cpu.get_visible_cpu()->debug()->go_next_device(); + m_console.get_visible_cpu()->debug()->go_next_device(); } @@ -1194,7 +1218,7 @@ void debugger_commands::execute_cpulist(int ref, const std::vector { device_state_interface *state; if (exec.device().interface(state) && state->state_find_entry(STATE_GENPCBASE) != nullptr) - m_console.printf("[%s%d] %s\n", &exec.device() == m_cpu.get_visible_cpu() ? "*" : "", index++, exec.device().tag()); + m_console.printf("[%s%d] %s\n", &exec.device() == m_console.get_visible_cpu() ? "*" : "", index++, exec.device().tag()); } } @@ -1425,8 +1449,9 @@ void debugger_commands::execute_bplist(int ref, const std::vector & m_console.printf("Device '%s' breakpoints:\n", device.tag()); /* loop over the breakpoints */ - for (const device_debug::breakpoint &bp : device.debug()->breakpoint_list()) + for (const auto &bpp : device.debug()->breakpoint_list()) { + debug_breakpoint &bp = *bpp.second; buffer = string_format("%c%4X @ %0*X", bp.enabled() ? ' ' : 'D', bp.index(), device.debug()->logaddrchars(), bp.address()); if (std::string(bp.condition()).compare("1") != 0) buffer.append(string_format(" if %s", bp.condition())); @@ -1725,7 +1750,7 @@ void debugger_commands::execute_rplist(int ref, const std::vector & m_console.printf("Device '%s' registerpoints:\n", device.tag()); /* loop over the breakpoints */ - for (const device_debug::registerpoint &rp : device.debug()->registerpoint_list()) + for (const debug_registerpoint &rp : device.debug()->registerpoint_list()) { buffer = string_format("%c%4X if %s", rp.enabled() ? ' ' : 'D', rp.index(), rp.condition()); if (rp.action() != nullptr) @@ -2655,7 +2680,6 @@ void debugger_commands::execute_find(int ref, const std::vector &pa int cur_data_size; int data_count = 0; int found = 0; - int j; /* validate parameters */ if (!validate_number_parameter(params[0], offset)) @@ -2681,7 +2705,7 @@ void debugger_commands::execute_find(int ref, const std::vector &pa /* check for a string */ if (pdata[0] == '"' && pdata[pdatalen] == '"') { - for (j = 1; j < pdatalen; j++) + for (int j = 1; j < pdatalen; j++) { data_to_find[data_count] = pdata[j]; data_size[data_count++] = 1; @@ -2709,21 +2733,54 @@ void debugger_commands::execute_find(int ref, const std::vector &pa } /* now search */ + device_memory_interface &memory = space->device().memory(); + auto dis = space->device().machine().disable_side_effects(); for (u64 i = offset; i <= endoffset; i += data_size[0]) { int suboffset = 0; bool match = true; /* find the entire string */ - for (j = 0; j < data_count && match; j++) + for (int j = 0; j < data_count && match; j++) { + offs_t address = space->byte_to_address(i + suboffset); switch (data_size[j]) { - case 1: match = (u8(m_cpu.read_byte(*space, space->byte_to_address(i + suboffset), true)) == u8(data_to_find[j])); break; - case 2: match = (u16(m_cpu.read_word(*space, space->byte_to_address(i + suboffset), true)) == u16(data_to_find[j])); break; - case 4: match = (u32(m_cpu.read_dword(*space, space->byte_to_address(i + suboffset), true)) == u32(data_to_find[j])); break; - case 8: match = (u64(m_cpu.read_qword(*space, space->byte_to_address(i + suboffset), true)) == u64(data_to_find[j])); break; - default: /* all other cases are wildcards */ break; + case 1: + address &= space->logaddrmask(); + if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) + match = space->read_byte(address) == u8(data_to_find[j]); + else + match = false; + break; + + case 2: + address &= space->logaddrmask(); + if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) + match = space->read_word_unaligned(address) == u16(data_to_find[j]); + else + match = false; + break; + + case 4: + address &= space->logaddrmask(); + if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) + match = space->read_dword_unaligned(address) == u32(data_to_find[j]); + else + match = false; + break; + + case 8: + address &= space->logaddrmask(); + if (memory.translate(space->spacenum(), TRANSLATE_READ_DEBUG, address)) + match = space->read_qword_unaligned(address) == u64(data_to_find[j]); + else + match = false; + break; + + default: + /* all other cases are wildcards */ + break; } suboffset += data_size[j] & 0x0f; } @@ -3010,7 +3067,7 @@ void debugger_commands::execute_trackpc(int ref, const std::vector if (turnOn) { // Insert current pc - if (m_cpu.get_visible_cpu() == cpu) + if (m_console.get_visible_cpu() == cpu) { const offs_t pc = cpu->state().pcbase(); cpu->debug()->set_track_pc_visited(pc); @@ -3083,9 +3140,35 @@ void debugger_commands::execute_pcatmem(int ref, const std::vector if (!validate_cpu_space_parameter((params.size() > 1) ? params[1].c_str() : nullptr, ref, space)) return; + // Translate the address + offs_t a = address & space->logaddrmask(); + if (!space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, a)) + { + m_console.printf("Bad address\n"); + return; + } + // Get the value of memory at the address - const int native_data_width = space->data_width() / 8; - const u64 data = m_cpu.read_memory(*space, space->address_to_byte(address), native_data_width, true); + u64 data = space->unmap(); + auto dis = space->device().machine().disable_side_effects(); + switch (space->data_width()) + { + case 8: + data = space->read_byte(a); + break; + + case 16: + data = space->read_word_unaligned(a); + break; + + case 32: + data = space->read_dword_unaligned(a); + break; + + case 64: + data = space->read_qword_unaligned(a); + break; + } // Recover the pc & print const int space_num = (int)ref; diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index 62e8008c322..a47378765ff 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -84,6 +84,7 @@ private: u64 execute_min(int params, const u64 *param); u64 execute_max(int params, const u64 *param); u64 execute_if(int params, const u64 *param); + u64 get_cpunum(); u64 global_get(global_entry *global); void global_set(global_entry *global, u64 value); diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 2c5989a8faa..e9c08268338 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -35,6 +35,7 @@ debugger_console::debugger_console(running_machine &machine) : m_machine(machine) + , m_visiblecpu(nullptr) , m_console_textbuf(nullptr) , m_errorlog_textbuf(nullptr) { @@ -60,6 +61,17 @@ debugger_console::debugger_console(running_machine &machine) /* register our own custom-command help */ register_command("helpcustom", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_console::execute_help_custom, this, _1, _2)); + + /* first CPU is visible by default */ + for (device_t &device : device_iterator(m_machine.root_device())) + { + auto *cpu = dynamic_cast(&device); + if (cpu != nullptr) + { + m_visiblecpu = cpu; + break; + } + } } @@ -121,6 +133,18 @@ void debugger_console::execute_help_custom(int ref, const std::vectordebug()->symtable(); +} + + + /*------------------------------------------------- trim_parameter - executes a command @@ -334,7 +358,7 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm { try { - parsed_expression(m_machine.debugger().cpu().visible_symtable(), command_start).execute(); + parsed_expression(visible_symtable(), command_start).execute(); } catch (expression_error &err) { diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index e57b06a7378..cabff196d9f 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -107,6 +107,10 @@ public: vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward(fmt), std::forward(args)...)); } + device_t *get_visible_cpu() { return m_visiblecpu; } + void set_visible_cpu(device_t *visiblecpu) { m_visiblecpu = visiblecpu; } + symbol_table &visible_symtable(); + static std::string cmderr_to_string(CMDERR error); private: @@ -134,6 +138,9 @@ private: running_machine &m_machine; + // visible CPU device (the one that commands should apply to) + device_t *m_visiblecpu; + text_buffer *m_console_textbuf; text_buffer *m_errorlog_textbuf; diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index fb5db3ffb89..afdef1362d1 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -13,6 +13,7 @@ #include "debugbuf.h" #include "express.h" +#include "points.h" #include "debugcon.h" #include "debugvw.h" @@ -36,7 +37,6 @@ const size_t debugger_cpu::NUM_TEMP_VARIABLES = 10; debugger_cpu::debugger_cpu(running_machine &machine) : m_machine(machine) , m_livecpu(nullptr) - , m_visiblecpu(nullptr) , m_breakcpu(nullptr) , m_symtable(nullptr) , m_vblank_occurred(false) @@ -53,17 +53,13 @@ debugger_cpu::debugger_cpu(running_machine &machine) m_tempvar = make_unique_clear(NUM_TEMP_VARIABLES); /* create a global symbol table */ - m_symtable = std::make_unique(); + m_symtable = std::make_unique(machine); + m_symtable->set_memory_modified_func([this]() { set_memory_modified(true); }); - // configure our base memory accessors - configure_memory(*m_symtable); - - /* add "wpaddr", "wpdata", "cycles", "cpunum", "logunmap" to the global symbol table */ + /* add "wpaddr", "wpdata" to the global symbol table */ m_symtable->add("wpaddr", symbol_table::READ_ONLY, &m_wpaddr); m_symtable->add("wpdata", symbol_table::READ_ONLY, &m_wpdata); - m_symtable->add("cpunum", std::bind(&debugger_cpu::get_cpunum, this)); - screen_device_iterator screen_iterator = screen_device_iterator(m_machine.root_device()); screen_device_iterator::auto_iterator iter = screen_iterator.begin(); const uint32_t count = (uint32_t)screen_iterator.count(); @@ -74,7 +70,7 @@ debugger_cpu::debugger_cpu(running_machine &machine) m_symtable->add("beamx", [&screen]() { return screen.hpos(); }); m_symtable->add("beamy", [&screen]() { return screen.vpos(); }); m_symtable->add("frame", [&screen]() { return screen.frame_number(); }); - iter.current()->register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this)); + screen.register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this)); } else if (count > 1) { @@ -84,7 +80,7 @@ debugger_cpu::debugger_cpu(running_machine &machine) m_symtable->add(string_format("beamx%d", i).c_str(), [&screen]() { return screen.hpos(); }); m_symtable->add(string_format("beamy%d", i).c_str(), [&screen]() { return screen.vpos(); }); m_symtable->add(string_format("frame%d", i).c_str(), [&screen]() { return screen.frame_number(); }); - iter.current()->register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this)); + screen.register_vblank_callback(vblank_state_delegate(&debugger_cpu::on_vblank, this)); } } @@ -95,27 +91,8 @@ debugger_cpu::debugger_cpu(running_machine &machine) sprintf(symname, "temp%d", regnum); m_symtable->add(symname, symbol_table::READ_WRITE, &m_tempvar[regnum]); } - - /* first CPU is visible by default */ - for (device_t &device : device_iterator(m_machine.root_device())) - { - auto *cpu = dynamic_cast(&device); - if (cpu != nullptr) - { - m_visiblecpu = cpu; - break; - } - } } -void debugger_cpu::configure_memory(symbol_table &table) -{ - using namespace std::placeholders; - table.configure_memory( - std::bind(&debugger_cpu::expression_validate, this, _1, _2), - std::bind(&debugger_cpu::expression_read_memory, this, _1, _2, _3, _4, _5), - std::bind(&debugger_cpu::expression_write_memory, this, _1, _2, _3, _4, _5, _6)); -} /*------------------------------------------------- flush_traces - flushes all traces; this is @@ -134,22 +111,6 @@ void debugger_cpu::flush_traces() -//************************************************************************** -// SYMBOL TABLE INTERFACES -//************************************************************************** - -//------------------------------------------------- -// visible_symtable - return the locally-visible -// symbol table -//------------------------------------------------- - -symbol_table &debugger_cpu::visible_symtable() -{ - return m_visiblecpu->debug()->symtable(); -} - - - //************************************************************************** // MEMORY AND DISASSEMBLY HELPERS //************************************************************************** @@ -223,916 +184,97 @@ bool debugger_cpu::comment_save() //------------------------------------------------- // comment_load - load all comments for the given -// machine -//------------------------------------------------- - -bool debugger_cpu::comment_load(bool is_inline) -{ - // open the file - emu_file file(m_machine.options().comment_directory(), OPEN_FLAG_READ); - osd_file::error filerr = file.open(m_machine.basename() + ".cmt"); - - // if an error, just return false - if (filerr != osd_file::error::NONE) - return false; - - // wrap in a try/catch to handle errors - util::xml::file::ptr const root = util::xml::file::read(file, nullptr); - try - { - // read the file - if (!root) - throw emu_exception(); - - // find the config node - util::xml::data_node const *const commentnode = root->get_child("mamecommentfile"); - if (commentnode == nullptr) - throw emu_exception(); - - // validate the config data version - int version = commentnode->get_attribute_int("version", 0); - if (version != COMMENT_VERSION) - throw emu_exception(); - - // check to make sure the file is applicable - util::xml::data_node const *const systemnode = commentnode->get_child("system"); - const char *const name = systemnode->get_attribute_string("name", ""); - if (strcmp(name, m_machine.system().name) != 0) - throw emu_exception(); - - // iterate over devices - for (util::xml::data_node const *cpunode = systemnode->get_child("cpu"); cpunode; cpunode = cpunode->get_next_sibling("cpu")) - { - const char *cputag_name = cpunode->get_attribute_string("tag", ""); - device_t *device = m_machine.root_device().subdevice(cputag_name); - if (device != nullptr) - { - if(is_inline == false) - m_machine.debugger().console().printf("@%s\n", cputag_name); - - if (!device->debug()->comment_import(*cpunode,is_inline)) - throw emu_exception(); - } - } - } - catch (emu_exception &) - { - // clean up in case of error - return false; - } - - // success! - return true; -} - - - -/*************************************************************************** - DEBUGGER MEMORY ACCESSORS -***************************************************************************/ - -/*------------------------------------------------- - read_byte - return a byte from the specified - memory space --------------------------------------------------*/ - -u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, return 0xff */ - if (!memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - return 0xff; - } - - /* otherwise, call the byte reading function for the translated address */ - return space.read_byte(address); -} - - -/*------------------------------------------------- - read_word - return a word from the specified - memory space --------------------------------------------------*/ - -u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, return 0xffff */ - if (!memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - return 0xffff; - } - - /* otherwise, call the byte reading function for the translated address */ - return space.read_word_unaligned(address); -} - - -/*------------------------------------------------- - read_dword - return a dword from the specified - memory space --------------------------------------------------*/ - -u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, return 0xffffffff */ - if (!memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - return 0xffffffff; - } - - /* otherwise, call the byte reading function for the translated address */ - return space.read_dword_unaligned(address); -} - - -/*------------------------------------------------- - read_qword - return a qword from the specified - memory space --------------------------------------------------*/ - -u64 debugger_cpu::read_qword(address_space &space, offs_t address, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - /* translate if necessary; if not mapped, return 0xffffffffffffffff */ - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, return 0xffffffff */ - if (!memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - return ~u64(0); - } - - /* otherwise, call the byte reading function for the translated address */ - return space.read_qword_unaligned(address); -} - - -/*------------------------------------------------- - read_memory - return 1,2,4 or 8 bytes - from the specified memory space --------------------------------------------------*/ - -u64 debugger_cpu::read_memory(address_space &space, offs_t address, int size, bool apply_translation) -{ - u64 result = ~u64(0) >> (64 - 8*size); - switch (size) - { - case 1: result = read_byte(space, address, apply_translation); break; - case 2: result = read_word(space, address, apply_translation); break; - case 4: result = read_dword(space, address, apply_translation); break; - case 8: result = read_qword(space, address, apply_translation); break; - } - return result; -} - - -/*------------------------------------------------- - write_byte - write a byte to the specified - memory space --------------------------------------------------*/ - -void debugger_cpu::write_byte(address_space &space, offs_t address, u8 data, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, we're done */ - if (!memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) - return; - } - - /* otherwise, call the byte reading function for the translated address */ - space.write_byte(address, data); - - m_memory_modified = true; -} - - -/*------------------------------------------------- - write_word - write a word to the specified - memory space --------------------------------------------------*/ - -void debugger_cpu::write_word(address_space &space, offs_t address, u16 data, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, we're done */ - if (!memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) - return; - } - - /* otherwise, call the byte reading function for the translated address */ - space.write_word_unaligned(address, data); - - m_memory_modified = true; -} - - -/*------------------------------------------------- - write_dword - write a dword to the specified - memory space --------------------------------------------------*/ - -void debugger_cpu::write_dword(address_space &space, offs_t address, u32 data, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, we're done */ - if (!memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) - return; - } - - /* otherwise, call the byte reading function for the translated address */ - space.write_dword_unaligned(address, data); - - m_memory_modified = true; -} - - -/*------------------------------------------------- - write_qword - write a qword to the specified - memory space --------------------------------------------------*/ - -void debugger_cpu::write_qword(address_space &space, offs_t address, u64 data, bool apply_translation) -{ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation) - { - /* mask against the logical byte mask */ - address &= space.logaddrmask(); - - /* translate if necessary; if not mapped, we're done */ - if (!memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) - return; - } - - /* otherwise, call the byte reading function for the translated address */ - space.write_qword_unaligned(address, data); - - m_memory_modified = true; -} - - -/*------------------------------------------------- - write_memory - write 1,2,4 or 8 bytes to the - specified memory space --------------------------------------------------*/ - -void debugger_cpu::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation) -{ - switch (size) - { - case 1: write_byte(space, address, data, apply_translation); break; - case 2: write_word(space, address, data, apply_translation); break; - case 4: write_dword(space, address, data, apply_translation); break; - case 8: write_qword(space, address, data, apply_translation); break; - } -} - - -/*------------------------------------------------- - read_opcode - read 1,2,4 or 8 bytes at the - given offset from opcode space --------------------------------------------------*/ - -u64 debugger_cpu::read_opcode(address_space &space, offs_t address, int size) -{ - device_memory_interface &memory = space.device().memory(); - - u64 result = ~u64(0) & (~u64(0) >> (64 - 8*size)); - - /* keep in logical range */ - address &= space.logaddrmask(); - - /* translate to physical first */ - if (!memory.translate(space.spacenum(), TRANSLATE_FETCH_DEBUG, address)) - return result; - - /* keep in physical range */ - address &= space.addrmask(); - - /* switch off the size and handle unaligned accesses */ - switch (size) - { - case 1: - result = space.read_byte(address); - break; - - case 2: - result = space.read_word_unaligned(address); - break; - - case 4: - result = space.read_dword_unaligned(address); - break; - - case 6: - case 8: - result = space.read_qword_unaligned(address); - break; - } - - return result; -} - - - -/*************************************************************************** - INTERNAL HELPERS -***************************************************************************/ - -/*------------------------------------------------- - on_vblank - called when a VBLANK hits --------------------------------------------------*/ - -void debugger_cpu::on_vblank(screen_device &device, bool vblank_state) -{ - /* just set a global flag to be consumed later */ - if (vblank_state) - m_vblank_occurred = true; -} - - -/*------------------------------------------------- - reset_transient_flags - reset the transient - flags on all CPUs --------------------------------------------------*/ - -void debugger_cpu::reset_transient_flags() -{ - /* loop over CPUs and reset the transient flags */ - for (device_t &device : device_iterator(m_machine.root_device())) - device.debug()->reset_transient_flag(); - m_stop_when_not_device = nullptr; -} - - - -/*************************************************************************** - EXPRESSION HANDLERS -***************************************************************************/ - -/*------------------------------------------------- - expression_get_device - return a device - based on a case insensitive tag search --------------------------------------------------*/ - -device_t* debugger_cpu::expression_get_device(const char *tag) -{ - // convert to lowercase then lookup the name (tags are enforced to be all lower case) - std::string fullname(tag); - strmakelower(fullname); - return m_machine.root_device().subdevice(fullname.c_str()); -} - - -/*------------------------------------------------- - expression_read_memory - read 1,2,4 or 8 bytes - at the given offset in the given address - space --------------------------------------------------*/ - -u64 debugger_cpu::expression_read_memory(const char *name, expression_space spacenum, u32 address, int size, bool disable_se) -{ - switch (spacenum) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - { - device_t *device = nullptr; - device_memory_interface *memory; - - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - if (memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) - { - address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); - auto dis = m_machine.disable_side_effects(disable_se); - return read_memory(space, address, size, true); - } - break; - } - - case EXPSPACE_PROGRAM_PHYSICAL: - case EXPSPACE_DATA_PHYSICAL: - case EXPSPACE_IO_PHYSICAL: - case EXPSPACE_SPACE3_PHYSICAL: - { - device_t *device = nullptr; - device_memory_interface *memory; - - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - if (memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) - { - address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); - auto dis = m_machine.disable_side_effects(disable_se); - return read_memory(space, address, size, false); - } - break; - } - - case EXPSPACE_RAMWRITE: - { - device_t *device = nullptr; - device_memory_interface *memory; - - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - auto dis = m_machine.disable_side_effects(disable_se); - return expression_read_program_direct(memory->space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size); - break; - } - - case EXPSPACE_OPCODE: - { - device_t *device = nullptr; - device_memory_interface *memory; - - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - auto dis = m_machine.disable_side_effects(disable_se); - return expression_read_program_direct(memory->space(AS_OPCODES), (spacenum == EXPSPACE_OPCODE), address, size); - break; - } - - case EXPSPACE_REGION: - if (name == nullptr) - break; - return expression_read_memory_region(name, address, size); - break; - - default: - break; - } - - return 0; -} - - -/*------------------------------------------------- - expression_read_program_direct - read memory - directly from an opcode or RAM pointer --------------------------------------------------*/ - -u64 debugger_cpu::expression_read_program_direct(address_space &space, int opcode, offs_t address, int size) -{ - u8 *base; - - /* adjust the address into a byte address, but not if being called recursively */ - if ((opcode & 2) == 0) - address = space.address_to_byte(address); - - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; - - /* read each half, from lower address to upper address */ - u64 r0 = expression_read_program_direct(space, opcode | 2, address + 0, halfsize); - u64 r1 = expression_read_program_direct(space, opcode | 2, address + halfsize, halfsize); - - /* assemble based on the target endianness */ - if (space.endianness() == ENDIANNESS_LITTLE) - return r0 | (r1 << (8 * halfsize)); - else - return r1 | (r0 << (8 * halfsize)); - } - - /* handle the byte-sized final requests */ - else - { - /* lowmask specified which address bits are within the databus width */ - offs_t lowmask = space.data_width() / 8 - 1; - - /* get the base of memory, aligned to the address minus the lowbits */ - base = (u8 *)space.get_read_ptr(address & ~lowmask); - - /* if we have a valid base, return the appropriate byte */ - if (base != nullptr) - { - if (space.endianness() == ENDIANNESS_LITTLE) - return base[BYTE8_XOR_LE(address) & lowmask]; - else - return base[BYTE8_XOR_BE(address) & lowmask]; - } - } - - return 0; -} - - -/*------------------------------------------------- - expression_read_memory_region - read memory - from a memory region --------------------------------------------------*/ - -u64 debugger_cpu::expression_read_memory_region(const char *rgntag, offs_t address, int size) -{ - memory_region *region = m_machine.root_device().memregion(rgntag); - u64 result = ~u64(0) >> (64 - 8*size); - - /* make sure we get a valid base before proceeding */ - if (region != nullptr) - { - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; - u64 r0, r1; - - /* read each half, from lower address to upper address */ - r0 = expression_read_memory_region(rgntag, address + 0, halfsize); - r1 = expression_read_memory_region(rgntag, address + halfsize, halfsize); - - /* assemble based on the target endianness */ - if (region->endianness() == ENDIANNESS_LITTLE) - result = r0 | (r1 << (8 * halfsize)); - else - result = r1 | (r0 << (8 * halfsize)); - } - - /* only process if we're within range */ - else if (address < region->bytes()) - { - /* lowmask specified which address bits are within the databus width */ - u32 lowmask = region->bytewidth() - 1; - u8 *base = region->base() + (address & ~lowmask); - - /* if we have a valid base, return the appropriate byte */ - if (region->endianness() == ENDIANNESS_LITTLE) - result = base[BYTE8_XOR_LE(address) & lowmask]; - else - result = base[BYTE8_XOR_BE(address) & lowmask]; - } - } - return result; -} - - -/*------------------------------------------------- - expression_write_memory - write 1,2,4 or 8 - bytes at the given offset in the given address - space --------------------------------------------------*/ - -void debugger_cpu::expression_write_memory(const char *name, expression_space spacenum, u32 address, int size, u64 data, bool disable_se) -{ - device_t *device = nullptr; - device_memory_interface *memory; - - switch (spacenum) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - if (memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) - { - address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); - auto dis = m_machine.disable_side_effects(disable_se); - write_memory(space, address, data, size, true); - } - break; - - case EXPSPACE_PROGRAM_PHYSICAL: - case EXPSPACE_DATA_PHYSICAL: - case EXPSPACE_IO_PHYSICAL: - case EXPSPACE_SPACE3_PHYSICAL: - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - if (memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) - { - address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); - auto dis = m_machine.disable_side_effects(disable_se); - write_memory(space, address, data, size, false); - } - break; - - case EXPSPACE_RAMWRITE: { - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - auto dis = m_machine.disable_side_effects(disable_se); - expression_write_program_direct(memory->space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size, data); - break; - } - - case EXPSPACE_OPCODE: { - if (name != nullptr) - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - { - device = get_visible_cpu(); - memory = &device->memory(); - } - auto dis = m_machine.disable_side_effects(disable_se); - expression_write_program_direct(memory->space(AS_OPCODES), (spacenum == EXPSPACE_OPCODE), address, size, data); - break; - } - - case EXPSPACE_REGION: - if (name == nullptr) - break; - expression_write_memory_region(name, address, size, data); - break; - - default: - break; - } -} - - -/*------------------------------------------------- - expression_write_program_direct - write memory - directly to an opcode or RAM pointer --------------------------------------------------*/ - -void debugger_cpu::expression_write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data) -{ - /* adjust the address into a byte address, but not if being called recursively */ - if ((opcode & 2) == 0) - address = space.address_to_byte(address); - - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; - - /* break apart based on the target endianness */ - u64 halfmask = ~u64(0) >> (64 - 8 * halfsize); - u64 r0, r1; - if (space.endianness() == ENDIANNESS_LITTLE) - { - r0 = data & halfmask; - r1 = (data >> (8 * halfsize)) & halfmask; - } - else - { - r0 = (data >> (8 * halfsize)) & halfmask; - r1 = data & halfmask; - } - - /* write each half, from lower address to upper address */ - expression_write_program_direct(space, opcode | 2, address + 0, halfsize, r0); - expression_write_program_direct(space, opcode | 2, address + halfsize, halfsize, r1); - } - - /* handle the byte-sized final case */ - else - { - /* lowmask specified which address bits are within the databus width */ - offs_t lowmask = space.data_width() / 8 - 1; - - /* get the base of memory, aligned to the address minus the lowbits */ - u8 *base = (u8 *)space.get_read_ptr(address & ~lowmask); - - /* if we have a valid base, write the appropriate byte */ - if (base != nullptr) - { - if (space.endianness() == ENDIANNESS_LITTLE) - base[BYTE8_XOR_LE(address) & lowmask] = data; - else - base[BYTE8_XOR_BE(address) & lowmask] = data; - m_memory_modified = true; - } - } -} - - -/*------------------------------------------------- - expression_write_memory_region - write memory - from a memory region --------------------------------------------------*/ +// machine +//------------------------------------------------- -void debugger_cpu::expression_write_memory_region(const char *rgntag, offs_t address, int size, u64 data) +bool debugger_cpu::comment_load(bool is_inline) { - memory_region *region = m_machine.root_device().memregion(rgntag); + // open the file + emu_file file(m_machine.options().comment_directory(), OPEN_FLAG_READ); + osd_file::error filerr = file.open(m_machine.basename() + ".cmt"); + + // if an error, just return false + if (filerr != osd_file::error::NONE) + return false; - /* make sure we get a valid base before proceeding */ - if (region != nullptr) + // wrap in a try/catch to handle errors + util::xml::file::ptr const root = util::xml::file::read(file, nullptr); + try { - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; + // read the file + if (!root) + throw emu_exception(); - /* break apart based on the target endianness */ - u64 halfmask = ~u64(0) >> (64 - 8 * halfsize); - u64 r0, r1; - if (region->endianness() == ENDIANNESS_LITTLE) - { - r0 = data & halfmask; - r1 = (data >> (8 * halfsize)) & halfmask; - } - else - { - r0 = (data >> (8 * halfsize)) & halfmask; - r1 = data & halfmask; - } + // find the config node + util::xml::data_node const *const commentnode = root->get_child("mamecommentfile"); + if (commentnode == nullptr) + throw emu_exception(); - /* write each half, from lower address to upper address */ - expression_write_memory_region(rgntag, address + 0, halfsize, r0); - expression_write_memory_region(rgntag, address + halfsize, halfsize, r1); - } + // validate the config data version + int version = commentnode->get_attribute_int("version", 0); + if (version != COMMENT_VERSION) + throw emu_exception(); - /* only process if we're within range */ - else if (address < region->bytes()) - { - /* lowmask specified which address bits are within the databus width */ - u32 lowmask = region->bytewidth() - 1; - u8 *base = region->base() + (address & ~lowmask); + // check to make sure the file is applicable + util::xml::data_node const *const systemnode = commentnode->get_child("system"); + const char *const name = systemnode->get_attribute_string("name", ""); + if (strcmp(name, m_machine.system().name) != 0) + throw emu_exception(); - /* if we have a valid base, set the appropriate byte */ - if (region->endianness() == ENDIANNESS_LITTLE) - { - base[BYTE8_XOR_LE(address) & lowmask] = data; - } - else + // iterate over devices + for (util::xml::data_node const *cpunode = systemnode->get_child("cpu"); cpunode; cpunode = cpunode->get_next_sibling("cpu")) + { + const char *cputag_name = cpunode->get_attribute_string("tag", ""); + device_t *device = m_machine.root_device().subdevice(cputag_name); + if (device != nullptr) { - base[BYTE8_XOR_BE(address) & lowmask] = data; + if(is_inline == false) + m_machine.debugger().console().printf("@%s\n", cputag_name); + + if (!device->debug()->comment_import(*cpunode,is_inline)) + throw emu_exception(); } - m_memory_modified = true; } } + catch (emu_exception &) + { + // clean up in case of error + return false; + } + + // success! + return true; } + +/*************************************************************************** + INTERNAL HELPERS +***************************************************************************/ + /*------------------------------------------------- - expression_validate - validate that the - provided expression references an - appropriate name + on_vblank - called when a VBLANK hits -------------------------------------------------*/ -expression_error::error_code debugger_cpu::expression_validate(const char *name, expression_space space) +void debugger_cpu::on_vblank(screen_device &device, bool vblank_state) { - device_t *device = nullptr; - device_memory_interface *memory; - - switch (space) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - if (name) - { - device = expression_get_device(name); - if (device == nullptr) - return expression_error::INVALID_MEMORY_NAME; - } - if (!device) - device = get_visible_cpu(); - if (!device->interface(memory) || !memory->has_space(AS_PROGRAM + (space - EXPSPACE_PROGRAM_LOGICAL))) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_PROGRAM_PHYSICAL: - case EXPSPACE_DATA_PHYSICAL: - case EXPSPACE_IO_PHYSICAL: - case EXPSPACE_SPACE3_PHYSICAL: - if (name) - { - device = expression_get_device(name); - if (device == nullptr) - return expression_error::INVALID_MEMORY_NAME; - } - if (!device) - device = get_visible_cpu(); - if (!device->interface(memory) || !memory->has_space(AS_PROGRAM + (space - EXPSPACE_PROGRAM_PHYSICAL))) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_RAMWRITE: - if (name) - { - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - return expression_error::INVALID_MEMORY_NAME; - } - if (!device) - device = get_visible_cpu(); - if (!device->interface(memory) || !memory->has_space(AS_PROGRAM)) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_OPCODE: - if (name) - { - device = expression_get_device(name); - if (device == nullptr || !device->interface(memory)) - return expression_error::INVALID_MEMORY_NAME; - } - if (!device) - device = get_visible_cpu(); - if (!device->interface(memory) || !memory->has_space(AS_OPCODES)) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_REGION: - if (!name) - return expression_error::MISSING_MEMORY_NAME; - if (!m_machine.root_device().memregion(name) || !m_machine.root_device().memregion(name)->base()) - return expression_error::INVALID_MEMORY_NAME; - break; - - default: - return expression_error::NO_SUCH_MEMORY_SPACE; - } - return expression_error::NONE; + /* just set a global flag to be consumed later */ + if (vblank_state) + m_vblank_occurred = true; } +/*------------------------------------------------- + reset_transient_flags - reset the transient + flags on all CPUs +-------------------------------------------------*/ -//************************************************************************** -// VARIABLE GETTERS/SETTERS -//************************************************************************** - -//------------------------------------------------- -// get_cpunum - getter callback for the -// 'cpunum' symbol -//------------------------------------------------- - -u64 debugger_cpu::get_cpunum() +void debugger_cpu::reset_transient_flags() { - execute_interface_iterator iter(m_machine.root_device()); - return iter.indexof(m_visiblecpu->execute()); + /* loop over CPUs and reset the transient flags */ + for (device_t &device : device_iterator(m_machine.root_device())) + device.debug()->reset_transient_flag(); + m_stop_when_not_device = nullptr; } @@ -1164,7 +306,8 @@ void debugger_cpu::start_hook(device_t *device, bool stop_on_vblank) // if we're running, do some periodic updating if (m_execution_state != exec_state::STOPPED) { - if (device == m_visiblecpu && osd_ticks() > m_last_periodic_update_time + osd_ticks_per_second() / 4) + device_t *visiblecpu = m_machine.debugger().console().get_visible_cpu(); + if (device == visiblecpu && osd_ticks() > m_last_periodic_update_time + osd_ticks_per_second() / 4) { // check for periodic updates m_machine.debug_view().update_all(); m_machine.debug_view().flush_osd_updates(); @@ -1191,8 +334,8 @@ void debugger_cpu::start_hook(device_t *device, bool stop_on_vblank) // check for debug keypresses if (m_machine.ui_input().pressed(IPT_UI_DEBUG_BREAK)) { - m_visiblecpu->debug()->ignore(false); - m_visiblecpu->debug()->halt_on_next_instruction("User-initiated break\n"); + visiblecpu->debug()->ignore(false); + visiblecpu->debug()->halt_on_next_instruction("User-initiated break\n"); } } } @@ -1276,7 +419,7 @@ device_debug::device_debug(device_t &device) , m_state(nullptr) , m_disasm(nullptr) , m_flags(0) - , m_symtable(&device.machine().debugger().cpu().global_symtable()) + , m_symtable(std::make_unique(device.machine(), &device.machine().debugger().cpu().global_symtable(), &device)) , m_instrhook(nullptr) , m_stepaddr(0) , m_stepsleft(0) @@ -1289,7 +432,7 @@ device_debug::device_debug(device_t &device) , m_last_total_cycles(0) , m_pc_history_index(0) , m_bplist() - , m_rplist() + , m_rplist(std::make_unique>()) , m_triggered_breakpoint(nullptr) , m_triggered_watchpoint(nullptr) , m_trace(nullptr) @@ -1329,31 +472,31 @@ device_debug::device_debug(device_t &device) // add global symbol for cycles and totalcycles if (m_exec != nullptr) { - m_symtable.add("cycles", [this]() { return m_exec->cycles_remaining(); }); - m_symtable.add("totalcycles", symbol_table::READ_ONLY, &m_total_cycles); - m_symtable.add("lastinstructioncycles", [this]() { return m_total_cycles - m_last_total_cycles; }); + m_symtable->add("cycles", [this]() { return m_exec->cycles_remaining(); }); + m_symtable->add("totalcycles", symbol_table::READ_ONLY, &m_total_cycles); + m_symtable->add("lastinstructioncycles", [this]() { return m_total_cycles - m_last_total_cycles; }); } // add entries to enable/disable unmap reporting for each space if (m_memory != nullptr) { if (m_memory->has_space(AS_PROGRAM)) - m_symtable.add( + m_symtable->add( "logunmap", [&space = m_memory->space(AS_PROGRAM)] () { return space.log_unmap(); }, [&space = m_memory->space(AS_PROGRAM)] (u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_DATA)) - m_symtable.add( + m_symtable->add( "logunmap", [&space = m_memory->space(AS_DATA)] () { return space.log_unmap(); }, [&space = m_memory->space(AS_DATA)] (u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_IO)) - m_symtable.add( + m_symtable->add( "logunmap", [&space = m_memory->space(AS_IO)] () { return space.log_unmap(); }, [&space = m_memory->space(AS_IO)] (u64 value) { return space.set_log_unmap(bool(value)); }); if (m_memory->has_space(AS_OPCODES)) - m_symtable.add( + m_symtable->add( "logunmap", [&space = m_memory->space(AS_OPCODES)] () { return space.log_unmap(); }, [&space = m_memory->space(AS_OPCODES)] (u64 value) { return space.set_log_unmap(bool(value)); }); @@ -1368,7 +511,7 @@ device_debug::device_debug(device_t &device) { using namespace std::placeholders; strmakelower(tempstr.assign(entry->symbol())); - m_symtable.add( + m_symtable->add( tempstr.c_str(), std::bind(&device_state_interface::state_int, m_state, entry->index()), entry->writeable() ? std::bind(&device_state_interface::set_state_int, m_state, entry->index(), _1) : symbol_table::setter_func(nullptr), @@ -1383,8 +526,8 @@ device_debug::device_debug(device_t &device) m_flags = DEBUG_FLAG_OBSERVING | DEBUG_FLAG_HISTORY; // if no curpc, add one - if (m_state && !m_symtable.find("curpc")) - m_symtable.add("curpc", std::bind(&device_state_interface::pcbase, m_state)); + if (m_state && !m_symtable->find("curpc")) + m_symtable->add("curpc", std::bind(&device_state_interface::pcbase, m_state)); } // set up trace @@ -1657,7 +800,7 @@ void device_debug::instruction_hook(offs_t curpc) debugcpu.set_break_cpu(nullptr); // remember the last visible CPU in the debugger - debugcpu.set_visible_cpu(&m_device); + machine.debugger().console().set_visible_cpu(&m_device); // update all views machine.debug_view().update_all(); @@ -1692,10 +835,10 @@ void device_debug::instruction_hook(offs_t curpc) if (machine.scheduled_event_pending()) debugcpu.set_execution_running(); } - m_device.machine().sound().debugger_mute(false); + machine.sound().debugger_mute(false); // remember the last visible CPU in the debugger - debugcpu.set_visible_cpu(&m_device); + machine.debugger().console().set_visible_cpu(&m_device); } // handle step out/over on the instruction we are about to execute @@ -1879,7 +1022,7 @@ void device_debug::go_exception(int exception, const char *condition) m_device.machine().rewind_invalidate(); m_stopexception = exception; - m_exception_condition = std::make_unique(m_symtable, condition); + m_exception_condition = std::make_unique(*m_symtable, condition); m_flags |= DEBUG_FLAG_STOP_EXCEPTION; m_device.machine().debugger().cpu().set_execution_running(); } @@ -1910,7 +1053,7 @@ void device_debug::go_privilege(const char *condition) { assert(m_exec != nullptr); m_device.machine().rewind_invalidate(); - m_privilege_condition = std::make_unique(m_symtable, condition); + m_privilege_condition = std::make_unique(*m_symtable, condition); m_flags |= DEBUG_FLAG_STOP_PRIVILEGE; m_device.machine().debugger().cpu().set_execution_running(); } @@ -1934,11 +1077,11 @@ void device_debug::halt_on_next_instruction_impl(util::format_argument_packsecond.get(); return nullptr; } @@ -1952,11 +1095,11 @@ int device_debug::breakpoint_set(offs_t address, const char *condition, const ch { // allocate a new one and hook it into our list u32 id = m_device.machine().debugger().cpu().get_breakpoint_index(); - m_bplist.emplace_front(this, m_symtable, id, address, condition, action); + m_bplist.emplace(address, std::make_unique(this, *m_symtable, id, address, condition, action)); // update the flags and return the index breakpoint_update_flags(); - return m_bplist.front().m_index; + return id; } @@ -1968,10 +1111,10 @@ int device_debug::breakpoint_set(offs_t address, const char *condition, const ch bool device_debug::breakpoint_clear(int index) { // scan the list to see if we own this breakpoint - for (auto bbp = m_bplist.before_begin(); std::next(bbp) != m_bplist.end(); ++bbp) - if (std::next(bbp)->m_index == index) + for (auto bpit = m_bplist.begin(); bpit != m_bplist.end(); ++bpit) + if (bpit->second->m_index == index) { - m_bplist.erase_after(bbp); + m_bplist.erase(bpit); breakpoint_update_flags(); return true; } @@ -2001,13 +1144,16 @@ void device_debug::breakpoint_clear_all() bool device_debug::breakpoint_enable(int index, bool enable) { // scan the list to see if we own this breakpoint - for (breakpoint &bp : m_bplist) + for (auto &bpp : m_bplist) + { + debug_breakpoint &bp = *bpp.second; if (bp.m_index == index) { bp.m_enabled = enable; breakpoint_update_flags(); return true; } + } // we don't own it, return false return false; @@ -2022,8 +1168,8 @@ bool device_debug::breakpoint_enable(int index, bool enable) void device_debug::breakpoint_enable_all(bool enable) { // apply the enable to all breakpoints we own - for (breakpoint &bp : m_bplist) - breakpoint_enable(bp.index(), enable); + for (auto &bpp : m_bplist) + breakpoint_enable(bpp.second->index(), enable); } @@ -2039,7 +1185,7 @@ int device_debug::watchpoint_set(address_space &space, read_or_write type, offs_ // allocate a new one u32 id = m_device.machine().debugger().cpu().get_watchpoint_index(); - m_wplist[space.spacenum()].emplace_back(std::make_unique(this, m_symtable, id, space, type, address, length, condition, action)); + m_wplist[space.spacenum()].emplace_back(std::make_unique(this, *m_symtable, id, space, type, address, length, condition, action)); return id; } @@ -2123,11 +1269,11 @@ int device_debug::registerpoint_set(const char *condition, const char *action) { // allocate a new one u32 id = m_device.machine().debugger().cpu().get_registerpoint_index(); - m_rplist.emplace_front(m_symtable, id, condition, action); + m_rplist->emplace_front(*m_symtable, id, condition, action); // update the flags and return the index breakpoint_update_flags(); - return m_rplist.front().m_index; + return m_rplist->front().m_index; } @@ -2139,10 +1285,10 @@ int device_debug::registerpoint_set(const char *condition, const char *action) bool device_debug::registerpoint_clear(int index) { // scan the list to see if we own this registerpoint - for (auto brp = m_rplist.before_begin(); std::next(brp) != m_rplist.end(); ++brp) + for (auto brp = m_rplist->before_begin(); std::next(brp) != m_rplist->end(); ++brp) if (std::next(brp)->m_index == index) { - m_rplist.erase_after(brp); + m_rplist->erase_after(brp); breakpoint_update_flags(); return true; } @@ -2159,7 +1305,7 @@ bool device_debug::registerpoint_clear(int index) void device_debug::registerpoint_clear_all() { // clear the list - m_rplist.clear(); + m_rplist->clear(); breakpoint_update_flags(); } @@ -2172,7 +1318,7 @@ void device_debug::registerpoint_clear_all() bool device_debug::registerpoint_enable(int index, bool enable) { // scan the list to see if we own this conditionpoint - for (registerpoint &rp : m_rplist) + for (debug_registerpoint &rp : *m_rplist) if (rp.m_index == index) { rp.m_enabled = enable; @@ -2193,7 +1339,7 @@ bool device_debug::registerpoint_enable(int index, bool enable) void device_debug::registerpoint_enable_all(bool enable) { // apply the enable to all registerpoints we own - for (registerpoint &rp : m_rplist) + for (debug_registerpoint &rp : *m_rplist) registerpoint_enable(rp.index(), enable); } @@ -2516,8 +1662,8 @@ void device_debug::breakpoint_update_flags() { // see if there are any enabled breakpoints m_flags &= ~DEBUG_FLAG_LIVE_BP; - for (breakpoint &bp : m_bplist) - if (bp.m_enabled) + for (auto &bpp : m_bplist) + if (bpp.second->m_enabled) { m_flags |= DEBUG_FLAG_LIVE_BP; break; @@ -2526,7 +1672,7 @@ void device_debug::breakpoint_update_flags() if ( ! ( m_flags & DEBUG_FLAG_LIVE_BP ) ) { // see if there are any enabled registerpoints - for (registerpoint &rp : m_rplist) + for (debug_registerpoint &rp : *m_rplist) { if (rp.m_enabled) { @@ -2551,7 +1697,10 @@ void device_debug::breakpoint_check(offs_t pc) debugger_cpu& debugcpu = m_device.machine().debugger().cpu(); // see if we match - for (breakpoint &bp : m_bplist) + auto bpitp = m_bplist.equal_range(pc); + for (auto bpit = bpitp.first; bpit != bpitp.second; ++bpit) + { + debug_breakpoint &bp = *bpit->second; if (bp.hit(pc)) { // halt in the debugger by default @@ -2569,9 +1718,10 @@ void device_debug::breakpoint_check(offs_t pc) } break; } + } // see if we have any matching registerpoints - for (registerpoint &rp : m_rplist) + for (debug_registerpoint &rp : *m_rplist) { if (rp.hit()) { @@ -2645,433 +1795,6 @@ void device_debug::hotspot_check(address_space &space, offs_t address) } -//************************************************************************** -// DEBUG BREAKPOINT -//************************************************************************** - -//------------------------------------------------- -// breakpoint - constructor -//------------------------------------------------- - -device_debug::breakpoint::breakpoint(device_debug* debugInterface, - symbol_table &symbols, - int index, - offs_t address, - const char *condition, - const char *action) - : m_debugInterface(debugInterface), - m_index(index), - m_enabled(true), - m_address(address), - m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : "") -{ -} - - -//------------------------------------------------- -// hit - detect a hit -//------------------------------------------------- - -bool device_debug::breakpoint::hit(offs_t pc) -{ - // don't hit if disabled - if (!m_enabled) - return false; - - // must match our address - if (m_address != pc) - return false; - - // must satisfy the condition - if (!m_condition.is_empty()) - { - try - { - return (m_condition.execute() != 0); - } - catch (expression_error &) - { - return false; - } - } - - return true; -} - - - -//************************************************************************** -// DEBUG WATCHPOINT -//************************************************************************** - -//------------------------------------------------- -// watchpoint - constructor -//------------------------------------------------- - -device_debug::watchpoint::watchpoint(device_debug* debugInterface, - symbol_table &symbols, - int index, - address_space &space, - read_or_write type, - offs_t address, - offs_t length, - const char *condition, - const char *action) - : m_debugInterface(debugInterface), - m_phr(nullptr), - m_phw(nullptr), - m_space(space), - m_index(index), - m_enabled(true), - m_type(type), - m_address(address & space.addrmask()), - m_length(length), - m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : ""), - m_installing(false) -{ - std::fill(std::begin(m_start_address), std::end(m_start_address), 0); - std::fill(std::begin(m_end_address), std::end(m_end_address), 0); - std::fill(std::begin(m_masks), std::end(m_masks), 0); - - int ashift = m_space.addr_shift(); - endianness_t endian = m_space.endianness(); - offs_t subamask = m_space.alignment() - 1; - offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; - offs_t start = m_address; - offs_t end = (m_address + m_length - 1) & space.addrmask(); - if (end < start) - end = space.addrmask(); - offs_t rstart = start & ~subamask; - offs_t rend = end | subamask; - u64 smask, mmask, emask; - smask = mmask = emask = make_bitmask(m_space.data_width()); - if (start != rstart) - { - if (endian == ENDIANNESS_LITTLE) - smask &= ~make_bitmask((start - rstart) * unit_size); - else - smask &= make_bitmask((rstart + subamask + 1 - start) * unit_size); - } - if (end != rend) - { - if (endian == ENDIANNESS_LITTLE) - emask &= make_bitmask((subamask + 1 + end - rend) * unit_size); - else - emask &= ~make_bitmask((rend - end) * unit_size); - } - - if (rend == (rstart | subamask) || smask == emask) - { - m_start_address[0] = rstart; - m_end_address[0] = rend; - m_masks[0] = smask & emask; - } - else - { - int idx = 0; - if (smask != mmask) - { - m_start_address[idx] = rstart; - m_end_address[idx] = rstart | subamask; - m_masks[idx] = smask; - idx++; - rstart += subamask + 1; - } - if (mmask == emask) - { - m_start_address[idx] = rstart; - m_end_address[idx] = rend; - m_masks[idx] = emask; - } - else - { - if (rstart < rend - subamask) - { - m_start_address[idx] = rstart; - m_end_address[idx] = rend - subamask - 1; - m_masks[idx] = mmask; - idx++; - } - m_start_address[idx] = rend - subamask; - m_end_address[idx] = rend; - m_masks[idx] = emask; - } - } - - install(read_or_write::READWRITE); - m_notifier = m_space.add_change_notifier([this](read_or_write mode) { - if (m_enabled) - { - install(mode); - } - }); -} - -device_debug::watchpoint::~watchpoint() -{ - m_space.remove_change_notifier(m_notifier); - if (m_phr) - m_phr->remove(); - if (m_phw) - m_phw->remove(); -} - -void device_debug::watchpoint::setEnabled(bool value) -{ - if (m_enabled != value) - { - m_enabled = value; - if (m_enabled) - install(read_or_write::READWRITE); - else - { - m_installing = true; - if(m_phr) - m_phr->remove(); - if(m_phw) - m_phw->remove(); - m_installing = false; - } - } -} - -void device_debug::watchpoint::install(read_or_write mode) -{ - if (m_installing) - return; - m_installing = true; - if ((u32(mode) & u32(read_or_write::READ)) && m_phr) - m_phr->remove(); - if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw) - m_phw->remove(); - std::string name = util::string_format("wp@%x", m_address); - switch (m_space.data_width()) - { - case 8: - if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name, - [this](offs_t offset, u8 &data, u8 mem_mask) { - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); - if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name, - [this](offs_t offset, u8 &data, u8 mem_mask) { - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); - break; - - case 16: - for (int i=0; i != 3; i++) - if (m_masks[i]) - { - u16 mask = m_masks[i]; - if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u16 &data, u16 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); - if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u16 &data, u16 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); - } - break; - - case 32: - for (int i=0; i != 3; i++) - if (m_masks[i]) - { - u32 mask = m_masks[i]; - if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u32 &data, u32 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); - if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u32 &data, u32 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); - } - break; - - case 64: - for (int i=0; i != 3; i++) - if (m_masks[i]) - { - u64 mask = m_masks[i]; - if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) - m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u64 &data, u64 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::READ, offset, data, mem_mask); - }, m_phr); - if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) - m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, - [this, mask](offs_t offset, u64 &data, u64 mem_mask) { - if (mem_mask & mask) - triggered(read_or_write::WRITE, offset, data, mem_mask); - }, m_phw); - } - break; - } - m_installing = false; -} - -void device_debug::watchpoint::triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask) -{ - auto &machine = m_debugInterface->m_device.machine(); - auto &debug = machine.debugger(); - - // if we're within debugger code, don't trigger - if (debug.cpu().within_instruction_hook() || machine.side_effects_disabled()) - return; - - // adjust address, size & value_to_write based on mem_mask. - offs_t size = 0; - int ashift = m_space.addr_shift(); - offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; - u64 unit_mask = make_bitmask(unit_size); - - offs_t address_offset = 0; - - if(!mem_mask) - mem_mask = 0xff; - - while (!(mem_mask & unit_mask)) - { - address_offset++; - data >>= unit_size; - mem_mask >>= unit_size; - } - - while (mem_mask) - { - size++; - mem_mask >>= unit_size; - } - - data &= make_bitmask(size * unit_size); - - if (m_space.endianness() == ENDIANNESS_LITTLE) - address += address_offset; - else - address += m_space.alignment() - size - address_offset; - - // stash the value that will be written or has just been read - debug.cpu().set_wpinfo(address, data); - - // protect against recursion - debug.cpu().set_within_instruction(true); - - // must satisfy the condition - if (!m_condition.is_empty()) - { - try - { - if (!m_condition.execute()) - { - debug.cpu().set_within_instruction(false); - return; - } - } - catch (expression_error &) - { - debug.cpu().set_within_instruction(false); - return; - } - } - - // halt in the debugger by default - bool was_stopped = debug.cpu().is_stopped(); - debug.cpu().set_execution_stopped(); - - // evaluate the action - if (!m_action.empty()) - debug.console().execute_command(m_action, false); - - // print a notification, unless the action made us go again - if (debug.cpu().is_stopped()) - { - std::string buffer; - - buffer = string_format(type == read_or_write::READ ? - "Stopped at watchpoint %X reading %0*X from %08X" : - "Stopped at watchpoint %X writing %0*X to %08X", - m_index, - size * unit_size / 4, - data, - address); - - if (debug.cpu().live_cpu() == &m_space.device()) - { - offs_t pc = m_space.device().state().pcbase(); - debug.console().printf("%s (PC=%X)\n", buffer, pc); - m_debugInterface->compute_debug_flags(); - } - else if (!was_stopped) - { - debug.console().printf("%s\n", buffer); - debug.cpu().set_execution_running(); - debug.cpu().set_break_cpu(&m_space.device()); - } - m_debugInterface->set_triggered_watchpoint(this); - } - - debug.cpu().set_within_instruction(false); -} - -//************************************************************************** -// DEBUG REGISTERPOINT -//************************************************************************** - -//------------------------------------------------- -// registerpoint - constructor -//------------------------------------------------- - -device_debug::registerpoint::registerpoint(symbol_table &symbols, int index, const char *condition, const char *action) - : m_index(index), - m_enabled(true), - m_condition(symbols, (condition != nullptr) ? condition : "1"), - m_action((action != nullptr) ? action : "") -{ -} - - -//------------------------------------------------- -// hit - detect a hit -//------------------------------------------------- - -bool device_debug::registerpoint::hit() -{ - // don't hit if disabled - if (!m_enabled) - return false; - - // must satisfy the condition - if (!m_condition.is_empty()) - { - try - { - return (m_condition.execute() != 0); - } - catch (expression_error &) - { - return false; - } - } - - return true; -} - - //************************************************************************** // TRACER diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 36b718c6a16..b21bd72b122 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -13,8 +13,6 @@ #pragma once -#include "express.h" - #include @@ -39,134 +37,13 @@ typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc); class device_debug { -public: - // breakpoint class - class breakpoint - { - friend class device_debug; - - public: - // construction/destruction - breakpoint( - device_debug* debugInterface, - symbol_table &symbols, - int index, - offs_t address, - const char *condition = nullptr, - const char *action = nullptr); - - // getters - const device_debug *debugInterface() const { return m_debugInterface; } - int index() const { return m_index; } - bool enabled() const { return m_enabled; } - offs_t address() const { return m_address; } - const char *condition() const { return m_condition.original_string(); } - const char *action() const { return m_action.c_str(); } - - // setters - void setEnabled(bool value) { m_enabled = value; } - - private: - // internals - bool hit(offs_t pc); - const device_debug * m_debugInterface; // the interface we were created from - int m_index; // user reported index - bool m_enabled; // enabled? - offs_t m_address; // execution address - parsed_expression m_condition; // condition - std::string m_action; // action - }; - - // watchpoint class - class watchpoint - { - friend class device_debug; - - public: - // construction/destruction - watchpoint( - device_debug* debugInterface, - symbol_table &symbols, - int index, - address_space &space, - read_or_write type, - offs_t address, - offs_t length, - const char *condition = nullptr, - const char *action = nullptr); - ~watchpoint(); - - // getters - const device_debug *debugInterface() const { return m_debugInterface; } - address_space &space() const { return m_space; } - int index() const { return m_index; } - read_or_write type() const { return m_type; } - bool enabled() const { return m_enabled; } - offs_t address() const { return m_address; } - offs_t length() const { return m_length; } - const char *condition() const { return m_condition.original_string(); } - const std::string &action() const { return m_action; } - - // setters - void setEnabled(bool value); - - // internals - bool hit(int type, offs_t address, int size); - - private: - device_debug * m_debugInterface; // the interface we were created from - memory_passthrough_handler *m_phr; // passthrough handler reference, read access - memory_passthrough_handler *m_phw; // passthrough handler reference, write access - address_space & m_space; // address space - int m_index; // user reported index - bool m_enabled; // enabled? - read_or_write m_type; // type (read/write) - offs_t m_address; // start address - offs_t m_length; // length of watch area - parsed_expression m_condition; // condition - std::string m_action; // action - int m_notifier; // address map change notifier id - - offs_t m_start_address[3]; // the start addresses of the checks to install - offs_t m_end_address[3]; // the end addresses - u64 m_masks[3]; // the access masks - bool m_installing; // prevent recursive multiple installs - void install(read_or_write mode); - void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask); - }; - - // registerpoint class - class registerpoint - { - friend class device_debug; - - public: - // construction/destruction - registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr); - - // getters - int index() const { return m_index; } - bool enabled() const { return m_enabled; } - const char *condition() const { return m_condition.original_string(); } - const char *action() const { return m_action.c_str(); } - - private: - // internals - bool hit(); - - int m_index; // user reported index - bool m_enabled; // enabled? - parsed_expression m_condition; // condition - std::string m_action; // action - }; - public: // construction/destruction device_debug(device_t &device); ~device_debug(); // getters - symbol_table &symtable() { return m_symtable; } + symbol_table &symtable() { return *m_symtable; } // commonly-used pass-throughs int logaddrchars() const { return (m_memory != nullptr && m_memory->has_space(AS_PROGRAM)) ? m_memory->space(AS_PROGRAM).logaddrchars() : 8; } @@ -213,28 +90,28 @@ public: } // breakpoints - const std::forward_list &breakpoint_list() const { return m_bplist; } - const breakpoint *breakpoint_find(offs_t address) const; + const auto &breakpoint_list() const { return m_bplist; } + const debug_breakpoint *breakpoint_find(offs_t address) const; int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr); bool breakpoint_clear(int index); void breakpoint_clear_all(); bool breakpoint_enable(int index, bool enable = true); void breakpoint_enable_all(bool enable = true); - breakpoint *triggered_breakpoint(void) { breakpoint *ret = m_triggered_breakpoint; m_triggered_breakpoint = nullptr; return ret; } + debug_breakpoint *triggered_breakpoint() { debug_breakpoint *ret = m_triggered_breakpoint; m_triggered_breakpoint = nullptr; return ret; } // watchpoints int watchpoint_space_count() const { return m_wplist.size(); } - const std::vector> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; } + const std::vector> &watchpoint_vector(int spacenum) const { return m_wplist[spacenum]; } int watchpoint_set(address_space &space, read_or_write type, offs_t address, offs_t length, const char *condition, const char *action); bool watchpoint_clear(int wpnum); void watchpoint_clear_all(); bool watchpoint_enable(int index, bool enable = true); void watchpoint_enable_all(bool enable = true); - void set_triggered_watchpoint(watchpoint *wp) { m_triggered_watchpoint = wp; } - watchpoint *triggered_watchpoint(void) { watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; } + void set_triggered_watchpoint(debug_watchpoint *wp) { m_triggered_watchpoint = wp; } + debug_watchpoint *triggered_watchpoint() { debug_watchpoint *ret = m_triggered_watchpoint; m_triggered_watchpoint = nullptr; return ret; } // registerpoints - const std::forward_list ®isterpoint_list() const { return m_rplist; } + const std::forward_list ®isterpoint_list() const { return *m_rplist; } int registerpoint_set(const char *condition, const char *action = nullptr); bool registerpoint_clear(int index); void registerpoint_clear_all(); @@ -307,7 +184,7 @@ private: // global state u32 m_flags; // debugging flags for this CPU - symbol_table m_symtable; // symbol table for expression evaluation + std::unique_ptr m_symtable; // symbol table for expression evaluation debug_instruction_hook_func m_instrhook; // per-instruction callback hook // stepping information @@ -330,12 +207,12 @@ private: u32 m_pc_history_index; // current history index // breakpoints and watchpoints - std::forward_list m_bplist; // list of breakpoints - std::vector>> m_wplist; // watchpoint lists for each address space - std::forward_list m_rplist; // list of registerpoints + std::multimap> m_bplist; // list of breakpoints + std::vector>> m_wplist; // watchpoint lists for each address space + std::unique_ptr> m_rplist; // list of registerpoints - breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered - watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered + debug_breakpoint * m_triggered_breakpoint; // latest breakpoint that was triggered + debug_watchpoint * m_triggered_watchpoint; // latest watchpoint that was triggered // tracing class tracer @@ -484,14 +361,9 @@ public: /* flushes all traces; this is useful if a trace is going on when we fatalerror */ void flush_traces(); - void configure_memory(symbol_table &table); - /* ----- debugging status & information ----- */ - /* return the visible CPU device (the one that commands should apply to) */ - device_t *get_visible_cpu() { return m_visiblecpu; } - /* return true if the current execution state is stopped */ bool is_stopped() const { return m_execution_state == exec_state::STOPPED; } bool is_running() const { return m_execution_state == exec_state::RUNNING; } @@ -502,9 +374,6 @@ public: /* return the global symbol table */ symbol_table &global_symtable() { return *m_symtable; } - /* return the locally-visible symbol table */ - symbol_table &visible_symtable(); - /* ----- debugger comment helpers ----- */ @@ -515,41 +384,6 @@ public: bool comment_load(bool is_inline); - /* ----- debugger memory accessors ----- */ - - /* return a byte from the specified memory space */ - u8 read_byte(address_space &space, offs_t address, bool apply_translation); - - /* return a word from the specified memory space */ - u16 read_word(address_space &space, offs_t address, bool apply_translation); - - /* return a dword from the specified memory space */ - u32 read_dword(address_space &space, offs_t address, bool apply_translation); - - /* return a qword from the specified memory space */ - u64 read_qword(address_space &space, offs_t address, bool apply_translation); - - /* return 1,2,4 or 8 bytes from the specified memory space */ - u64 read_memory(address_space &space, offs_t address, int size, bool apply_translation); - - /* write a byte to the specified memory space */ - void write_byte(address_space &space, offs_t address, u8 data, bool apply_translation); - - /* write a word to the specified memory space */ - void write_word(address_space &space, offs_t address, u16 data, bool apply_translation); - - /* write a dword to the specified memory space */ - void write_dword(address_space &space, offs_t address, u32 data, bool apply_translation); - - /* write a qword to the specified memory space */ - void write_qword(address_space &space, offs_t address, u64 data, bool apply_translation); - - /* write 1,2,4 or 8 bytes to the specified memory space */ - void write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation); - - /* read 1,2,4 or 8 bytes at the given offset from opcode space */ - u64 read_opcode(address_space &space, offs_t offset, int size); - // getters bool within_instruction_hook() const { return m_within_instruction_hook; } bool memory_modified() const { return m_memory_modified; } @@ -560,7 +394,6 @@ public: u32 get_registerpoint_index() { return m_rpindex++; } // setters - void set_visible_cpu(device_t * visiblecpu) { m_visiblecpu = visiblecpu; } void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; } void set_within_instruction(bool within_instruction) { m_within_instruction_hook = within_instruction; } void set_memory_modified(bool memory_modified) { m_memory_modified = memory_modified; } @@ -581,26 +414,12 @@ public: private: static const size_t NUM_TEMP_VARIABLES; - /* expression handlers */ - u64 expression_read_memory(const char *name, expression_space space, u32 address, int size, bool disable_se); - u64 expression_read_program_direct(address_space &space, int opcode, offs_t address, int size); - u64 expression_read_memory_region(const char *rgntag, offs_t address, int size); - void expression_write_memory(const char *name, expression_space space, u32 address, int size, u64 data, bool disable_se); - void expression_write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data); - void expression_write_memory_region(const char *rgntag, offs_t address, int size, u64 data); - expression_error::error_code expression_validate(const char *name, expression_space space); - device_t* expression_get_device(const char *tag); - - // variable getters/setters - u64 get_cpunum(); - // internal helpers void on_vblank(screen_device &device, bool vblank_state); running_machine& m_machine; device_t * m_livecpu; - device_t * m_visiblecpu; device_t * m_breakcpu; std::unique_ptr m_symtable; // global symbol table diff --git a/src/emu/debug/dvbpoints.cpp b/src/emu/debug/dvbpoints.cpp index 2ab47b906f2..b4b03f75681 100644 --- a/src/emu/debug/dvbpoints.cpp +++ b/src/emu/debug/dvbpoints.cpp @@ -11,6 +11,7 @@ #include "emu.h" #include "debugger.h" #include "dvbpoints.h" +#include "points.h" #include #include @@ -18,62 +19,62 @@ // Sorting functors for the qsort function -static bool cIndexAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cIndexAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return a->index() < b->index(); } -static bool cIndexDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cIndexDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cIndexAscending(b, a); } -static bool cEnabledAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cEnabledAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return !a->enabled() && b->enabled(); } -static bool cEnabledDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cEnabledDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cEnabledAscending(b, a); } -static bool cCpuAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cCpuAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return strcmp(a->debugInterface()->device().tag(), b->debugInterface()->device().tag()) < 0; } -static bool cCpuDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cCpuDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cCpuAscending(b, a); } -static bool cAddressAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cAddressAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return a->address() < b->address(); } -static bool cAddressDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cAddressDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cAddressAscending(b, a); } -static bool cConditionAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cConditionAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return strcmp(a->condition(), b->condition()) < 0; } -static bool cConditionDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cConditionDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cConditionAscending(b, a); } -static bool cActionAscending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cActionAscending(const debug_breakpoint *a, const debug_breakpoint *b) { return strcmp(a->action(), b->action()) < 0; } -static bool cActionDescending(const device_debug::breakpoint *a, const device_debug::breakpoint *b) +static bool cActionDescending(const debug_breakpoint *a, const debug_breakpoint *b) { return cActionAscending(b, a); } @@ -169,7 +170,7 @@ void debug_view_breakpoints::view_click(const int button, const debug_view_xy& p return; // Enable / disable - const_cast(*m_buffer[bpIndex]).setEnabled(!m_buffer[bpIndex]->enabled()); + const_cast(*m_buffer[bpIndex]).setEnabled(!m_buffer[bpIndex]->enabled()); machine().debug_view().update_all(DVT_DISASSEMBLY); } @@ -195,8 +196,8 @@ void debug_view_breakpoints::gather_breakpoints() { // Collect device_debug &debugInterface = *source->device()->debug(); - for (const device_debug::breakpoint &bp : debugInterface.breakpoint_list()) - m_buffer.push_back(&bp); + for (const auto &bpp : debugInterface.breakpoint_list()) + m_buffer.push_back(bpp.second.get()); } // And now for the sort @@ -270,7 +271,7 @@ void debug_view_breakpoints::view_update() int bpi = row + m_topleft.y - 1; if ((bpi < m_buffer.size()) && (bpi >= 0)) { - const device_debug::breakpoint *const bp = m_buffer[bpi]; + const debug_breakpoint *const bp = m_buffer[bpi]; linebuf.clear(); linebuf.rdbuf()->clear(); diff --git a/src/emu/debug/dvbpoints.h b/src/emu/debug/dvbpoints.h index 2cba6cd3081..18419434c03 100644 --- a/src/emu/debug/dvbpoints.h +++ b/src/emu/debug/dvbpoints.h @@ -48,8 +48,8 @@ private: // internal state - bool (*m_sortType)(const device_debug::breakpoint *, const device_debug::breakpoint *); - std::vector m_buffer; + bool (*m_sortType)(const debug_breakpoint *, const debug_breakpoint *); + std::vector m_buffer; }; #endif // MAME_EMU_DEBUG_DVBPOINTS_H diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp index 95d72e5cda8..385a0c98a65 100644 --- a/src/emu/debug/dvdisasm.cpp +++ b/src/emu/debug/dvdisasm.cpp @@ -360,13 +360,7 @@ void debug_view_disasm::complete_information(const debug_view_disasm_source &sou dasm.m_is_pc = adr == pc; - dasm.m_is_bp = false; - for(const device_debug::breakpoint &bp : source.device()->debug()->breakpoint_list()) - if(adr == (bp.address() & source.m_space.logaddrmask())) { - dasm.m_is_bp = true; - break; - } - + dasm.m_is_bp = source.device()->debug()->breakpoint_find(adr) != nullptr; dasm.m_is_visited = source.device()->debug()->track_pc_visited(adr); const char *comment = source.device()->debug()->comment_text(adr); diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp index e4daaff1a80..eaffcac33b8 100644 --- a/src/emu/debug/dvmemory.cpp +++ b/src/emu/debug/dvmemory.cpp @@ -256,6 +256,118 @@ static inline float u64_to_double(u64 value) return v.f; } +//------------------------------------------------- +// generate_row - read one row of data and make a +// text representation of the chunks +//------------------------------------------------- + +void debug_view_memory::generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address) +{ + // get positional data + const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; + int spacing = posdata.m_spacing; + + // generate the address + char addrtext[20]; + sprintf(addrtext, m_addrformat.c_str(), address); + debug_view_char *dest = destrow + m_section[0].m_pos + 1; + for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = addrtext[ch]; + + // generate the data and the ascii string + std::string chunkascii; + if (m_data_format <= 8) + { + for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) + { + u64 chunkdata; + bool ismapped = read_chunk(address, chunknum, chunkdata); + + int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; + dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; + for (int ch = 0; ch < spacing; ch++, dest++) + if (dest >= destmin && dest < destmax) + { + u8 shift = posdata.m_shift[ch]; + if (shift < 64) + dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*'; + } + + for (int i = 0; i < m_bytes_per_chunk; i++) + { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + } + } + } + else + { + for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) + { + char valuetext[64]; + u64 chunkdata = 0; + extFloat80_t chunkdata80 = { 0, 0 }; + bool ismapped; + + if (m_data_format != 11) + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); + else + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80); + + if (ismapped) + switch (m_data_format) + { + case 9: + sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata))); + break; + case 10: + sprintf(valuetext, "%.24g", u64_to_double(chunkdata)); + break; + case 11: + float64_t f64 = extF80M_to_f64(&chunkdata80); + sprintf(valuetext, "%.24g", u64_to_double(f64.v)); + break; + } + else + { + valuetext[0] = '*'; + valuetext[1] = 0; + } + + int ch; + int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; + dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; + // first copy the text + for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = valuetext[ch]; + // then fill with spaces + for (; ch < spacing; ch++, dest++) + if (dest >= destmin && dest < destmax) + dest->byte = ' '; + + for (int i = 0; i < m_bytes_per_chunk; i++) + { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + } + } + } + + // generate the ASCII data, but follow the chunks + if (m_section[2].m_width > 0) + { + dest = destrow + m_section[2].m_pos + 1; + for (size_t i = 0; i != chunkascii.size(); i++) + { + if (dest >= destmin && dest < destmax) + dest->byte = chunkascii[i]; + dest++; + } + } +} + //------------------------------------------------- // view_update - update the contents of the // memory view @@ -269,9 +381,6 @@ void debug_view_memory::view_update() if (needs_recompute()) recompute(); - // get positional data - const memory_view_pos &posdata = s_memory_pos_table[m_data_format]; - // loop over visible rows for (u32 row = 0; row < m_visible.y; row++) { @@ -281,10 +390,9 @@ void debug_view_memory::view_update() u32 effrow = m_topleft.y + row; // reset the line of data; section 1 is normal, others are ancillary, cursor is selected - debug_view_char *dest = destmin; - for (int ch = 0; ch < m_visible.x; ch++, dest++) + u32 effcol = m_topleft.x; + for (debug_view_char *dest = destmin; dest != destmax; dest++, effcol++) { - u32 effcol = m_topleft.x + ch; dest->byte = ' '; dest->attrib = DCA_ANCILLARY; if (m_section[1].contains(effcol)) @@ -300,96 +408,7 @@ void debug_view_memory::view_update() { offs_t addrbyte = m_byte_offset + effrow * m_bytes_per_row; offs_t address = (source.m_space != nullptr) ? source.m_space->byte_to_address(addrbyte) : addrbyte; - char addrtext[20]; - - // generate the address - sprintf(addrtext, m_addrformat.c_str(), address); - dest = destrow + m_section[0].m_pos + 1; - for (int ch = 0; addrtext[ch] != 0 && ch < m_section[0].m_width - 1; ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = addrtext[ch]; - - // generate the data and the ascii string - std::string chunkascii; - for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) - { - int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; - int spacing = posdata.m_spacing; - - if (m_data_format <= 8) { - u64 chunkdata; - bool ismapped = read_chunk(address, chunknum, chunkdata); - dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; - for (int ch = 0; ch < posdata.m_spacing; ch++, dest++) - if (dest >= destmin && dest < destmax) - { - u8 shift = posdata.m_shift[ch]; - if (shift < 64) - dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*'; - } - for (int i=0; i < m_bytes_per_chunk; i++) { - u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); - } - } - else { - int ch; - char valuetext[64]; - u64 chunkdata = 0; - extFloat80_t chunkdata80 = { 0, 0 }; - bool ismapped; - - if (m_data_format != 11) - ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); - else - ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80); - - if (ismapped) - switch (m_data_format) - { - case 9: - sprintf(valuetext, "%.8g", u32_to_float(u32(chunkdata))); - break; - case 10: - sprintf(valuetext, "%.24g", u64_to_double(chunkdata)); - break; - case 11: - float64_t f64 = extF80M_to_f64(&chunkdata80); - sprintf(valuetext, "%.24g", u64_to_double(f64.v)); - break; - } - else { - valuetext[0] = '*'; - valuetext[1] = 0; - } - - dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; - // first copy the text - for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = valuetext[ch]; - // then fill with spaces - for (; ch < spacing; ch++, dest++) - if (dest >= destmin && dest < destmax) - dest->byte = ' '; - - for (int i=0; i < m_bytes_per_chunk; i++) { - u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); - chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); - } - } - } - - // generate the ASCII data, but follow the chunks - if (m_section[2].m_width > 0) - { - dest = destrow + m_section[2].m_pos + 1; - for (size_t i = 0; i != chunkascii.size(); i++) { - if (dest >= destmin && dest < destmax) - dest->byte = chunkascii[i]; - dest++; - } - } + generate_row(destmin, destmax, destrow, address); } } } @@ -784,15 +803,7 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) } data = ~u64(0); if (ismapped) - { - switch (size) - { - case 1: data = machine().debugger().cpu().read_byte(*source.m_space, offs, !m_no_translation); break; - case 2: data = machine().debugger().cpu().read_word(*source.m_space, offs, !m_no_translation); break; - case 4: data = machine().debugger().cpu().read_dword(*source.m_space, offs, !m_no_translation); break; - case 8: data = machine().debugger().cpu().read_qword(*source.m_space, offs, !m_no_translation); break; - } - } + data = m_expression.context().read_memory(*source.m_space, offs, size, !m_no_translation); return ismapped; } @@ -883,14 +894,7 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data) if (source.m_space) { auto dis = machine().disable_side_effects(); - - switch (size) - { - case 1: machine().debugger().cpu().write_byte(*source.m_space, offs, data, !m_no_translation); break; - case 2: machine().debugger().cpu().write_word(*source.m_space, offs, data, !m_no_translation); break; - case 4: machine().debugger().cpu().write_dword(*source.m_space, offs, data, !m_no_translation); break; - case 8: machine().debugger().cpu().write_qword(*source.m_space, offs, data, !m_no_translation); break; - } + m_expression.context().write_memory(*source.m_space, offs, data, size, !m_no_translation); return; } diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h index 05138c2ba0c..8aa5df7cbeb 100644 --- a/src/emu/debug/dvmemory.h +++ b/src/emu/debug/dvmemory.h @@ -104,6 +104,7 @@ private: void write(u8 size, offs_t offs, u64 data); bool read(u8 size, offs_t offs, extFloat80_t &data); bool read_chunk(offs_t address, int chunknum, u64 &chunkdata); + void generate_row(debug_view_char *destmin, debug_view_char *destmax, debug_view_char *destrow, offs_t address); // internal state debug_view_expression m_expression; // expression describing the start address diff --git a/src/emu/debug/dvwpoints.cpp b/src/emu/debug/dvwpoints.cpp index fb713ac58e7..28f2740a2f5 100644 --- a/src/emu/debug/dvwpoints.cpp +++ b/src/emu/debug/dvwpoints.cpp @@ -10,88 +10,89 @@ #include "emu.h" #include "dvwpoints.h" +#include "points.h" #include #include -static bool cIndexAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cIndexAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return a->index() < b->index(); } -static bool cIndexDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cIndexDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cIndexAscending(b, a); } -static bool cEnabledAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cEnabledAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return !a->enabled() && b->enabled(); } -static bool cEnabledDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cEnabledDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cEnabledAscending(b, a); } -static bool cCpuAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cCpuAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return strcmp(a->debugInterface()->device().tag(), b->debugInterface()->device().tag()) < 0; } -static bool cCpuDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cCpuDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cCpuAscending(b, a); } -static bool cSpaceAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cSpaceAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return strcmp(a->space().name(), b->space().name()) < 0; } -static bool cSpaceDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cSpaceDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cSpaceAscending(b, a); } -static bool cAddressAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cAddressAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return a->address() < b->address(); } -static bool cAddressDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cAddressDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cAddressAscending(b, a); } -static bool cTypeAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cTypeAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return int(a->type()) < int(b->type()); } -static bool cTypeDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cTypeDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cTypeAscending(b, a); } -static bool cConditionAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cConditionAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return strcmp(a->condition(), b->condition()) < 0; } -static bool cConditionDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cConditionDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cConditionAscending(b, a); } -static bool cActionAscending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cActionAscending(const debug_watchpoint *a, const debug_watchpoint *b) { return a->action() < b->action(); } -static bool cActionDescending(const device_debug::watchpoint *a, const device_debug::watchpoint *b) +static bool cActionDescending(const debug_watchpoint *a, const debug_watchpoint *b) { return cActionAscending(b, a); } @@ -301,7 +302,7 @@ void debug_view_watchpoints::view_update() if ((wpi < m_buffer.size()) && wpi >= 0) { static char const *const types[] = { "unkn ", "read ", "write", "r/w " }; - device_debug::watchpoint *const wp = m_buffer[wpi]; + debug_watchpoint *const wp = m_buffer[wpi]; linebuf.clear(); linebuf.rdbuf()->clear(); diff --git a/src/emu/debug/dvwpoints.h b/src/emu/debug/dvwpoints.h index 26b7c676e0e..753cbe62356 100644 --- a/src/emu/debug/dvwpoints.h +++ b/src/emu/debug/dvwpoints.h @@ -43,8 +43,8 @@ private: // internal state - bool (*m_sortType)(const device_debug::watchpoint *, const device_debug::watchpoint *); - std::vector m_buffer; + bool (*m_sortType)(const debug_watchpoint *, const debug_watchpoint *); + std::vector m_buffer; }; #endif // MAME_EMU_DEBUG_DVWPOINTS_H diff --git a/src/emu/debug/express.cpp b/src/emu/debug/express.cpp index bb1f17e05f3..2f5da8d0dea 100644 --- a/src/emu/debug/express.cpp +++ b/src/emu/debug/express.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles /*************************************************************************** - express.c + express.cpp Generic expressions engine. @@ -358,24 +358,23 @@ u64 function_symbol_entry::execute(int numparams, const u64 *paramlist) // symbol_table - constructor //------------------------------------------------- -symbol_table::symbol_table(symbol_table *parent) - : m_parent(parent), - m_memory_valid(nullptr), - m_memory_read(nullptr), - m_memory_write(nullptr) +symbol_table::symbol_table(running_machine &machine, symbol_table *parent, device_t *device) + : m_machine(machine) + , m_parent(parent) + , m_memintf(dynamic_cast(device)) + , m_memory_modified(nullptr) { } //------------------------------------------------- -// add - add a new u64 pointer symbol +// set_memory_modified_func - install notifier +// for when memory is modified in debugger //------------------------------------------------- -void symbol_table::configure_memory(valid_func valid, read_func read, write_func write) +void symbol_table::set_memory_modified_func(memory_modified_func modified) { - m_memory_valid = std::move(valid); - m_memory_read = std::move(read); - m_memory_write = std::move(write); + m_memory_modified = std::move(modified); } @@ -464,59 +463,580 @@ void symbol_table::set_value(const char *symbol, u64 value) } + +//************************************************************************** +// EXPRESSION MEMORY HANDLERS +//************************************************************************** + //------------------------------------------------- -// memory_valid - return true if the given -// memory name/space/offset combination is valid +// read_memory - return 1,2,4 or 8 bytes +// from the specified memory space //------------------------------------------------- -expression_error::error_code symbol_table::memory_valid(const char *name, expression_space space) +u64 symbol_table::read_memory(address_space &space, offs_t address, int size, bool apply_translation) +{ + u64 result = ~u64(0) >> (64 - 8*size); + + if (apply_translation) + { + // mask against the logical byte mask + address &= space.logaddrmask(); + + // translate if necessary; if not mapped, return 0xffffffffffffffff + if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + return result; + } + + // otherwise, call the reading function for the translated address + switch (size) + { + case 1: result = space.read_byte(address); break; + case 2: result = space.read_word_unaligned(address); break; + case 4: result = space.read_dword_unaligned(address); break; + case 8: result = space.read_qword_unaligned(address); break; + } + return result; +} + + +//------------------------------------------------- +// write_memory - write 1,2,4 or 8 bytes to the +// specified memory space +//------------------------------------------------- + +void symbol_table::write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation) +{ + if (apply_translation) + { + // mask against the logical byte mask + address &= space.logaddrmask(); + + // translate if necessary; if not mapped, we're done + if (!space.device().memory().translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address)) + return; + } + + // otherwise, call the writing function for the translated address + switch (size) + { + case 1: space.write_byte(address, data); break; + case 2: space.write_word_unaligned(address, data); break; + case 4: space.write_dword_unaligned(address, data); break; + case 8: space.write_qword_unaligned(address, data); break; + } + + notify_memory_modified(); +} + + +//------------------------------------------------- +// expression_get_device - return a device +// based on a case insensitive tag search +//------------------------------------------------- + +device_t *symbol_table::expression_get_device(const char *tag) +{ + // convert to lowercase then lookup the name (tags are enforced to be all lower case) + std::string fullname(tag); + strmakelower(fullname); + return m_machine.root_device().subdevice(fullname.c_str()); +} + + +//------------------------------------------------- +// notify_memory_modified - notify that memory +// has been changed +//------------------------------------------------- + +void symbol_table::notify_memory_modified() { // walk up the table hierarchy to find the owner for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent) - if (symtable->m_memory_valid != nullptr) + if (symtable->m_memory_modified != nullptr) + m_memory_modified(); +} + + +//------------------------------------------------- +// memory_value - read 1,2,4 or 8 bytes at the +// given offset in the given address space +//------------------------------------------------- + +u64 symbol_table::memory_value(const char *name, expression_space spacenum, u32 address, int size, bool disable_se) +{ + device_memory_interface *memory = m_memintf; + + switch (spacenum) + { + case EXPSPACE_PROGRAM_LOGICAL: + case EXPSPACE_DATA_LOGICAL: + case EXPSPACE_IO_LOGICAL: + case EXPSPACE_SPACE3_LOGICAL: + if (name != nullptr) { - expression_error::error_code err = symtable->m_memory_valid(name, space); - if (err != expression_error::NO_SUCH_MEMORY_SPACE) - return err; + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); } - return expression_error::NO_SUCH_MEMORY_SPACE; + if (memory != nullptr && memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) + { + address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); + auto dis = m_machine.disable_side_effects(disable_se); + return read_memory(space, address, size, true); + } + break; + + case EXPSPACE_PROGRAM_PHYSICAL: + case EXPSPACE_DATA_PHYSICAL: + case EXPSPACE_IO_PHYSICAL: + case EXPSPACE_SPACE3_PHYSICAL: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) + { + address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); + auto dis = m_machine.disable_side_effects(disable_se); + return read_memory(space, address, size, false); + } + break; + + case EXPSPACE_RAMWRITE: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_PROGRAM)) + { + auto dis = m_machine.disable_side_effects(disable_se); + return read_program_direct(memory->space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size); + } + break; + + case EXPSPACE_OPCODE: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_OPCODES)) + { + auto dis = m_machine.disable_side_effects(disable_se); + return read_program_direct(memory->space(AS_OPCODES), (spacenum == EXPSPACE_OPCODE), address, size); + } + break; + + case EXPSPACE_REGION: + if (name == nullptr) + break; + return read_memory_region(name, address, size); + + default: + break; + } + + return 0; } //------------------------------------------------- -// memory_value - return a value read from memory +// read_program_direct - read memory directly +// from an opcode or RAM pointer //------------------------------------------------- -u64 symbol_table::memory_value(const char *name, expression_space space, u32 offset, int size, bool disable_se) +u64 symbol_table::read_program_direct(address_space &space, int opcode, offs_t address, int size) { - // walk up the table hierarchy to find the owner - for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent) - if (symtable->m_memory_valid != nullptr) + u8 *base; + + // adjust the address into a byte address, but not if being called recursively + if ((opcode & 2) == 0) + address = space.address_to_byte(address); + + // call ourself recursively until we are byte-sized + if (size > 1) + { + int halfsize = size / 2; + + // read each half, from lower address to upper address + u64 r0 = read_program_direct(space, opcode | 2, address + 0, halfsize); + u64 r1 = read_program_direct(space, opcode | 2, address + halfsize, halfsize); + + // assemble based on the target endianness + if (space.endianness() == ENDIANNESS_LITTLE) + return r0 | (r1 << (8 * halfsize)); + else + return r1 | (r0 << (8 * halfsize)); + } + + // handle the byte-sized final requests + else + { + // lowmask specified which address bits are within the databus width + offs_t lowmask = space.data_width() / 8 - 1; + + // get the base of memory, aligned to the address minus the lowbits + base = (u8 *)space.get_read_ptr(address & ~lowmask); + + // if we have a valid base, return the appropriate byte + if (base != nullptr) { - expression_error::error_code err = symtable->m_memory_valid(name, space); - if (err != expression_error::NO_SUCH_MEMORY_SPACE && symtable->m_memory_read != nullptr) - return symtable->m_memory_read(name, space, offset, size, disable_se); - return 0; + if (space.endianness() == ENDIANNESS_LITTLE) + return base[BYTE8_XOR_LE(address) & lowmask]; + else + return base[BYTE8_XOR_BE(address) & lowmask]; } + } + return 0; } //------------------------------------------------- -// set_memory_value - write a value to memory +// read_memory_region - read memory from a +// memory region //------------------------------------------------- -void symbol_table::set_memory_value(const char *name, expression_space space, u32 offset, int size, u64 value, bool disable_se) +u64 symbol_table::read_memory_region(const char *rgntag, offs_t address, int size) { - // walk up the table hierarchy to find the owner - for (symbol_table *symtable = this; symtable != nullptr; symtable = symtable->m_parent) - if (symtable->m_memory_valid != nullptr) + memory_region *region = m_machine.root_device().memregion(rgntag); + u64 result = ~u64(0) >> (64 - 8*size); + + // make sure we get a valid base before proceeding + if (region != nullptr) + { + // call ourself recursively until we are byte-sized + if (size > 1) { - expression_error::error_code err = symtable->m_memory_valid(name, space); - if (err != expression_error::NO_SUCH_MEMORY_SPACE && symtable->m_memory_write != nullptr) - symtable->m_memory_write(name, space, offset, size, value, disable_se); - return; + int halfsize = size / 2; + u64 r0, r1; + + // read each half, from lower address to upper address + r0 = read_memory_region(rgntag, address + 0, halfsize); + r1 = read_memory_region(rgntag, address + halfsize, halfsize); + + // assemble based on the target endianness + if (region->endianness() == ENDIANNESS_LITTLE) + result = r0 | (r1 << (8 * halfsize)); + else + result = r1 | (r0 << (8 * halfsize)); } + + // only process if we're within range + else if (address < region->bytes()) + { + // lowmask specified which address bits are within the databus width + u32 lowmask = region->bytewidth() - 1; + u8 *base = region->base() + (address & ~lowmask); + + // if we have a valid base, return the appropriate byte + if (region->endianness() == ENDIANNESS_LITTLE) + result = base[BYTE8_XOR_LE(address) & lowmask]; + else + result = base[BYTE8_XOR_BE(address) & lowmask]; + } + } + return result; +} + + +//------------------------------------------------- +// set_memory_value - write 1,2,4 or 8 bytes at +// the given offset in the given address space +//------------------------------------------------- + +void symbol_table::set_memory_value(const char *name, expression_space spacenum, u32 address, int size, u64 data, bool disable_se) +{ + device_memory_interface *memory = m_memintf; + + switch (spacenum) + { + case EXPSPACE_PROGRAM_LOGICAL: + case EXPSPACE_DATA_LOGICAL: + case EXPSPACE_IO_LOGICAL: + case EXPSPACE_SPACE3_LOGICAL: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) + { + address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); + auto dis = m_machine.disable_side_effects(disable_se); + write_memory(space, address, data, size, true); + } + break; + + case EXPSPACE_PROGRAM_PHYSICAL: + case EXPSPACE_DATA_PHYSICAL: + case EXPSPACE_IO_PHYSICAL: + case EXPSPACE_SPACE3_PHYSICAL: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) + { + address_space &space = memory->space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); + auto dis = m_machine.disable_side_effects(disable_se); + write_memory(space, address, data, size, false); + } + break; + + case EXPSPACE_RAMWRITE: { + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_PROGRAM)) + { + auto dis = m_machine.disable_side_effects(disable_se); + write_program_direct(memory->space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size, data); + } + break; + } + + case EXPSPACE_OPCODE: { + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device != nullptr) + device->interface(memory); + } + if (memory != nullptr && memory->has_space(AS_OPCODES)) + { + auto dis = m_machine.disable_side_effects(disable_se); + write_program_direct(memory->space(AS_OPCODES), (spacenum == EXPSPACE_OPCODE), address, size, data); + } + break; + } + + case EXPSPACE_REGION: + if (name == nullptr) + break; + write_memory_region(name, address, size, data); + break; + + default: + break; + } +} + + +//------------------------------------------------- +// write_program_direct - write memory directly +// to an opcode or RAM pointer +//------------------------------------------------- + +void symbol_table::write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data) +{ + // adjust the address into a byte address, but not if being called recursively + if ((opcode & 2) == 0) + address = space.address_to_byte(address); + + // call ourself recursively until we are byte-sized + if (size > 1) + { + int halfsize = size / 2; + + // break apart based on the target endianness + u64 halfmask = ~u64(0) >> (64 - 8 * halfsize); + u64 r0, r1; + if (space.endianness() == ENDIANNESS_LITTLE) + { + r0 = data & halfmask; + r1 = (data >> (8 * halfsize)) & halfmask; + } + else + { + r0 = (data >> (8 * halfsize)) & halfmask; + r1 = data & halfmask; + } + + // write each half, from lower address to upper address + write_program_direct(space, opcode | 2, address + 0, halfsize, r0); + write_program_direct(space, opcode | 2, address + halfsize, halfsize, r1); + } + + // handle the byte-sized final case + else + { + // lowmask specified which address bits are within the databus width + offs_t lowmask = space.data_width() / 8 - 1; + + // get the base of memory, aligned to the address minus the lowbits + u8 *base = (u8 *)space.get_read_ptr(address & ~lowmask); + + // if we have a valid base, write the appropriate byte + if (base != nullptr) + { + if (space.endianness() == ENDIANNESS_LITTLE) + base[BYTE8_XOR_LE(address) & lowmask] = data; + else + base[BYTE8_XOR_BE(address) & lowmask] = data; + notify_memory_modified(); + } + } +} + + +//------------------------------------------------- +// write_memory_region - write memory to a +// memory region +//------------------------------------------------- + +void symbol_table::write_memory_region(const char *rgntag, offs_t address, int size, u64 data) +{ + memory_region *region = m_machine.root_device().memregion(rgntag); + + // make sure we get a valid base before proceeding + if (region != nullptr) + { + // call ourself recursively until we are byte-sized + if (size > 1) + { + int halfsize = size / 2; + + // break apart based on the target endianness + u64 halfmask = ~u64(0) >> (64 - 8 * halfsize); + u64 r0, r1; + if (region->endianness() == ENDIANNESS_LITTLE) + { + r0 = data & halfmask; + r1 = (data >> (8 * halfsize)) & halfmask; + } + else + { + r0 = (data >> (8 * halfsize)) & halfmask; + r1 = data & halfmask; + } + + // write each half, from lower address to upper address + write_memory_region(rgntag, address + 0, halfsize, r0); + write_memory_region(rgntag, address + halfsize, halfsize, r1); + } + + // only process if we're within range + else if (address < region->bytes()) + { + // lowmask specified which address bits are within the databus width + u32 lowmask = region->bytewidth() - 1; + u8 *base = region->base() + (address & ~lowmask); + + // if we have a valid base, set the appropriate byte + if (region->endianness() == ENDIANNESS_LITTLE) + { + base[BYTE8_XOR_LE(address) & lowmask] = data; + } + else + { + base[BYTE8_XOR_BE(address) & lowmask] = data; + } + notify_memory_modified(); + } + } +} + + +//------------------------------------------------- +// memory_valid - return true if the given +// memory name/space/offset combination is valid +//------------------------------------------------- + +expression_error::error_code symbol_table::memory_valid(const char *name, expression_space space) +{ + device_memory_interface *memory = m_memintf; + + switch (space) + { + case EXPSPACE_PROGRAM_LOGICAL: + case EXPSPACE_DATA_LOGICAL: + case EXPSPACE_IO_LOGICAL: + case EXPSPACE_SPACE3_LOGICAL: + if (name != nullptr) + { + device_t *device = expression_get_device(name); + if (device == nullptr) + return expression_error::INVALID_MEMORY_NAME; + if (!device->interface(memory)) + return expression_error::NO_SUCH_MEMORY_SPACE; + } + else if (memory == nullptr) + return expression_error::MISSING_MEMORY_NAME; + if (!memory->has_space(AS_PROGRAM + (space - EXPSPACE_PROGRAM_LOGICAL))) + return expression_error::NO_SUCH_MEMORY_SPACE; + break; + + case EXPSPACE_PROGRAM_PHYSICAL: + case EXPSPACE_DATA_PHYSICAL: + case EXPSPACE_IO_PHYSICAL: + case EXPSPACE_SPACE3_PHYSICAL: + if (name) + { + device_t *device = expression_get_device(name); + if (device == nullptr) + return expression_error::INVALID_MEMORY_NAME; + if (!device->interface(memory)) + return expression_error::NO_SUCH_MEMORY_SPACE; + } + else if (memory == nullptr) + return expression_error::MISSING_MEMORY_NAME; + if (!memory->has_space(AS_PROGRAM + (space - EXPSPACE_PROGRAM_PHYSICAL))) + return expression_error::NO_SUCH_MEMORY_SPACE; + break; + + case EXPSPACE_RAMWRITE: + if (name) + { + device_t *device = expression_get_device(name); + if (device == nullptr) + return expression_error::INVALID_MEMORY_NAME; + if (!device->interface(memory)) + return expression_error::NO_SUCH_MEMORY_SPACE; + } + else if (memory == nullptr) + return expression_error::MISSING_MEMORY_NAME; + if (!memory->has_space(AS_PROGRAM)) + return expression_error::NO_SUCH_MEMORY_SPACE; + break; + + case EXPSPACE_OPCODE: + if (name) + { + device_t *device = expression_get_device(name); + if (device == nullptr) + return expression_error::INVALID_MEMORY_NAME; + if (!device->interface(memory)) + return expression_error::NO_SUCH_MEMORY_SPACE; + } + else if (memory == nullptr) + return expression_error::MISSING_MEMORY_NAME; + if (!memory->has_space(AS_OPCODES)) + return expression_error::NO_SUCH_MEMORY_SPACE; + break; + + case EXPSPACE_REGION: + if (!name) + return expression_error::MISSING_MEMORY_NAME; + if (!m_machine.root_device().memregion(name) || !m_machine.root_device().memregion(name)->base()) + return expression_error::INVALID_MEMORY_NAME; + break; + + default: + return expression_error::NO_SUCH_MEMORY_SPACE; + } + return expression_error::NONE; } diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index 6b3ac6afa84..1caee590d5a 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -49,6 +49,8 @@ enum expression_space // TYPE DEFINITIONS //************************************************************************** +using offs_t = u32; + // ======================> expression_error // an expression_error holds an error code and a string offset @@ -154,9 +156,7 @@ public: typedef std::function execute_func; // callback functions for memory reads/writes - typedef std::function valid_func; - typedef std::function read_func; - typedef std::function write_func; + typedef std::function memory_modified_func; enum read_write { @@ -165,14 +165,14 @@ public: }; // construction/destruction - symbol_table(symbol_table *parent = nullptr); + symbol_table(running_machine &machine, symbol_table *parent = nullptr, device_t *device = nullptr); // getters const std::unordered_map> &entries() const { return m_symlist; } symbol_table *parent() const { return m_parent; } // setters - void configure_memory(valid_func valid, read_func read, write_func write); + void set_memory_modified_func(memory_modified_func modified); // symbol access void add(const char *name, read_write rw, u64 *ptr = nullptr); @@ -190,14 +190,24 @@ public: expression_error::error_code memory_valid(const char *name, expression_space space); u64 memory_value(const char *name, expression_space space, u32 offset, int size, bool disable_se); void set_memory_value(const char *name, expression_space space, u32 offset, int size, u64 value, bool disable_se); + u64 read_memory(address_space &space, offs_t address, int size, bool apply_translation); + void write_memory(address_space &space, offs_t address, u64 data, int size, bool apply_translation); private: + // memory helpers + u64 read_program_direct(address_space &space, int opcode, offs_t address, int size); + u64 read_memory_region(const char *rgntag, offs_t address, int size); + void write_program_direct(address_space &space, int opcode, offs_t address, int size, u64 data); + void write_memory_region(const char *rgntag, offs_t address, int size, u64 data); + device_t *expression_get_device(const char *tag); + void notify_memory_modified(); + // internal state + running_machine & m_machine; // reference to the machine symbol_table * m_parent; // pointer to the parent symbol table std::unordered_map> m_symlist; // list of symbols - valid_func m_memory_valid; // validation callback - read_func m_memory_read; // read callback - write_func m_memory_write; // write callback + device_memory_interface *const m_memintf; // pointer to the local memory interface (if any) + memory_modified_func m_memory_modified; // memory modified callback }; diff --git a/src/emu/debug/points.cpp b/src/emu/debug/points.cpp new file mode 100644 index 00000000000..1cde2bbf486 --- /dev/null +++ b/src/emu/debug/points.cpp @@ -0,0 +1,441 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + points.cpp + + Debugger breakpoints, watchpoints, etc. + +***************************************************************************/ + +#include "emu.h" +#include "points.h" +#include "debugger.h" +#include "debugcon.h" + + +//************************************************************************** +// DEBUG BREAKPOINT +//************************************************************************** + +//------------------------------------------------- +// debug_breakpoint - constructor +//------------------------------------------------- + +debug_breakpoint::debug_breakpoint(device_debug* debugInterface, + symbol_table &symbols, + int index, + offs_t address, + const char *condition, + const char *action) + : m_debugInterface(debugInterface), + m_index(index), + m_enabled(true), + m_address(address), + m_condition(symbols, (condition != nullptr) ? condition : "1"), + m_action((action != nullptr) ? action : "") +{ +} + + +//------------------------------------------------- +// hit - detect a hit +//------------------------------------------------- + +bool debug_breakpoint::hit(offs_t pc) +{ + // don't hit if disabled + if (!m_enabled) + return false; + + // must match our address + if (m_address != pc) + return false; + + // must satisfy the condition + if (!m_condition.is_empty()) + { + try + { + return (m_condition.execute() != 0); + } + catch (expression_error &) + { + return false; + } + } + + return true; +} + + + +//************************************************************************** +// DEBUG WATCHPOINT +//************************************************************************** + +//------------------------------------------------- +// debug_watchpoint - constructor +//------------------------------------------------- + +debug_watchpoint::debug_watchpoint(device_debug* debugInterface, + symbol_table &symbols, + int index, + address_space &space, + read_or_write type, + offs_t address, + offs_t length, + const char *condition, + const char *action) + : m_debugInterface(debugInterface), + m_phr(nullptr), + m_phw(nullptr), + m_space(space), + m_index(index), + m_enabled(true), + m_type(type), + m_address(address & space.addrmask()), + m_length(length), + m_condition(symbols, (condition != nullptr) ? condition : "1"), + m_action((action != nullptr) ? action : ""), + m_installing(false) +{ + std::fill(std::begin(m_start_address), std::end(m_start_address), 0); + std::fill(std::begin(m_end_address), std::end(m_end_address), 0); + std::fill(std::begin(m_masks), std::end(m_masks), 0); + + int ashift = m_space.addr_shift(); + endianness_t endian = m_space.endianness(); + offs_t subamask = m_space.alignment() - 1; + offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; + offs_t start = m_address; + offs_t end = (m_address + m_length - 1) & space.addrmask(); + if (end < start) + end = space.addrmask(); + offs_t rstart = start & ~subamask; + offs_t rend = end | subamask; + u64 smask, mmask, emask; + smask = mmask = emask = make_bitmask(m_space.data_width()); + if (start != rstart) + { + if (endian == ENDIANNESS_LITTLE) + smask &= ~make_bitmask((start - rstart) * unit_size); + else + smask &= make_bitmask((rstart + subamask + 1 - start) * unit_size); + } + if (end != rend) + { + if (endian == ENDIANNESS_LITTLE) + emask &= make_bitmask((subamask + 1 + end - rend) * unit_size); + else + emask &= ~make_bitmask((rend - end) * unit_size); + } + + if (rend == (rstart | subamask) || smask == emask) + { + m_start_address[0] = rstart; + m_end_address[0] = rend; + m_masks[0] = smask & emask; + } + else + { + int idx = 0; + if (smask != mmask) + { + m_start_address[idx] = rstart; + m_end_address[idx] = rstart | subamask; + m_masks[idx] = smask; + idx++; + rstart += subamask + 1; + } + if (mmask == emask) + { + m_start_address[idx] = rstart; + m_end_address[idx] = rend; + m_masks[idx] = emask; + } + else + { + if (rstart < rend - subamask) + { + m_start_address[idx] = rstart; + m_end_address[idx] = rend - subamask - 1; + m_masks[idx] = mmask; + idx++; + } + m_start_address[idx] = rend - subamask; + m_end_address[idx] = rend; + m_masks[idx] = emask; + } + } + + install(read_or_write::READWRITE); + m_notifier = m_space.add_change_notifier([this](read_or_write mode) { + if (m_enabled) + { + install(mode); + } + }); +} + +debug_watchpoint::~debug_watchpoint() +{ + m_space.remove_change_notifier(m_notifier); + if (m_phr) + m_phr->remove(); + if (m_phw) + m_phw->remove(); +} + +void debug_watchpoint::setEnabled(bool value) +{ + if (m_enabled != value) + { + m_enabled = value; + if (m_enabled) + install(read_or_write::READWRITE); + else + { + m_installing = true; + if(m_phr) + m_phr->remove(); + if(m_phw) + m_phw->remove(); + m_installing = false; + } + } +} + +void debug_watchpoint::install(read_or_write mode) +{ + if (m_installing) + return; + m_installing = true; + if ((u32(mode) & u32(read_or_write::READ)) && m_phr) + m_phr->remove(); + if ((u32(mode) & u32(read_or_write::WRITE)) && m_phw) + m_phw->remove(); + std::string name = util::string_format("wp@%x", m_address); + switch (m_space.data_width()) + { + case 8: + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[0], m_end_address[0], name, + [this](offs_t offset, u8 &data, u8 mem_mask) { + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + break; + + case 16: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u16 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u16 &data, u16 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + + case 32: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u32 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u32 &data, u32 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + + case 64: + for (int i=0; i != 3; i++) + if (m_masks[i]) + { + u64 mask = m_masks[i]; + if (u32(m_type) & u32(mode) & u32(read_or_write::READ)) + m_phr = m_space.install_read_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::READ, offset, data, mem_mask); + }, m_phr); + if (u32(m_type) & u32(mode) & u32(read_or_write::WRITE)) + m_phw = m_space.install_write_tap(m_start_address[i], m_end_address[i], name, + [this, mask](offs_t offset, u64 &data, u64 mem_mask) { + if (mem_mask & mask) + triggered(read_or_write::WRITE, offset, data, mem_mask); + }, m_phw); + } + break; + } + m_installing = false; +} + +void debug_watchpoint::triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask) +{ + running_machine &machine = m_debugInterface->device().machine(); + debugger_manager &debug = machine.debugger(); + + // if we're within debugger code, don't trigger + if (debug.cpu().within_instruction_hook() || machine.side_effects_disabled()) + return; + + // adjust address, size & value_to_write based on mem_mask. + offs_t size = 0; + int ashift = m_space.addr_shift(); + offs_t unit_size = ashift <= 0 ? 8 << -ashift : 8 >> ashift; + u64 unit_mask = make_bitmask(unit_size); + + offs_t address_offset = 0; + + if(!mem_mask) + mem_mask = 0xff; + + while (!(mem_mask & unit_mask)) + { + address_offset++; + data >>= unit_size; + mem_mask >>= unit_size; + } + + while (mem_mask) + { + size++; + mem_mask >>= unit_size; + } + + data &= make_bitmask(size * unit_size); + + if (m_space.endianness() == ENDIANNESS_LITTLE) + address += address_offset; + else + address += m_space.alignment() - size - address_offset; + + // stash the value that will be written or has just been read + debug.cpu().set_wpinfo(address, data); + + // protect against recursion + debug.cpu().set_within_instruction(true); + + // must satisfy the condition + if (!m_condition.is_empty()) + { + try + { + if (!m_condition.execute()) + { + debug.cpu().set_within_instruction(false); + return; + } + } + catch (expression_error &) + { + debug.cpu().set_within_instruction(false); + return; + } + } + + // halt in the debugger by default + bool was_stopped = debug.cpu().is_stopped(); + debug.cpu().set_execution_stopped(); + + // evaluate the action + if (!m_action.empty()) + debug.console().execute_command(m_action, false); + + // print a notification, unless the action made us go again + if (debug.cpu().is_stopped()) + { + std::string buffer; + + buffer = string_format(type == read_or_write::READ ? + "Stopped at watchpoint %X reading %0*X from %08X" : + "Stopped at watchpoint %X writing %0*X to %08X", + m_index, + size * unit_size / 4, + data, + address); + + if (debug.cpu().live_cpu() == &m_space.device()) + { + offs_t pc = m_space.device().state().pcbase(); + debug.console().printf("%s (PC=%X)\n", buffer, pc); + m_debugInterface->compute_debug_flags(); + } + else if (!was_stopped) + { + debug.console().printf("%s\n", buffer); + debug.cpu().set_execution_running(); + debug.cpu().set_break_cpu(&m_space.device()); + } + m_debugInterface->set_triggered_watchpoint(this); + } + + debug.cpu().set_within_instruction(false); +} + +//************************************************************************** +// DEBUG REGISTERPOINT +//************************************************************************** + +//------------------------------------------------- +// debug_registerpoint - constructor +//------------------------------------------------- + +debug_registerpoint::debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action) + : m_index(index), + m_enabled(true), + m_condition(symbols, (condition != nullptr) ? condition : "1"), + m_action((action != nullptr) ? action : "") +{ +} + + +//------------------------------------------------- +// hit - detect a hit +//------------------------------------------------- + +bool debug_registerpoint::hit() +{ + // don't hit if disabled + if (!m_enabled) + return false; + + // must satisfy the condition + if (!m_condition.is_empty()) + { + try + { + return (m_condition.execute() != 0); + } + catch (expression_error &) + { + return false; + } + } + + return true; +} diff --git a/src/emu/debug/points.h b/src/emu/debug/points.h new file mode 100644 index 00000000000..220b75728ce --- /dev/null +++ b/src/emu/debug/points.h @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + points.h + + Debugger breakpoints, watchpoints, etc. + +***************************************************************************/ + +#ifndef MAME_EMU_DEBUG_POINTS_H +#define MAME_EMU_DEBUG_POINTS_H + +#pragma once + +#include "debugcpu.h" +#include "express.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> debug_breakpoint + +class debug_breakpoint +{ + friend class device_debug; + +public: + // construction/destruction + debug_breakpoint( + device_debug* debugInterface, + symbol_table &symbols, + int index, + offs_t address, + const char *condition = nullptr, + const char *action = nullptr); + + // getters + const device_debug *debugInterface() const { return m_debugInterface; } + int index() const { return m_index; } + bool enabled() const { return m_enabled; } + offs_t address() const { return m_address; } + const char *condition() const { return m_condition.original_string(); } + const char *action() const { return m_action.c_str(); } + + // setters + void setEnabled(bool value) { m_enabled = value; } + +private: + // internals + bool hit(offs_t pc); + const device_debug * m_debugInterface; // the interface we were created from + int m_index; // user reported index + bool m_enabled; // enabled? + offs_t m_address; // execution address + parsed_expression m_condition; // condition + std::string m_action; // action +}; + +// ======================> debug_watchpoint + +class debug_watchpoint +{ + friend class device_debug; + +public: + // construction/destruction + debug_watchpoint( + device_debug* debugInterface, + symbol_table &symbols, + int index, + address_space &space, + read_or_write type, + offs_t address, + offs_t length, + const char *condition = nullptr, + const char *action = nullptr); + ~debug_watchpoint(); + + // getters + const device_debug *debugInterface() const { return m_debugInterface; } + address_space &space() const { return m_space; } + int index() const { return m_index; } + read_or_write type() const { return m_type; } + bool enabled() const { return m_enabled; } + offs_t address() const { return m_address; } + offs_t length() const { return m_length; } + const char *condition() const { return m_condition.original_string(); } + const std::string &action() const { return m_action; } + + // setters + void setEnabled(bool value); + + // internals + bool hit(int type, offs_t address, int size); + +private: + void install(read_or_write mode); + void triggered(read_or_write type, offs_t address, u64 data, u64 mem_mask); + + device_debug * m_debugInterface; // the interface we were created from + memory_passthrough_handler *m_phr; // passthrough handler reference, read access + memory_passthrough_handler *m_phw; // passthrough handler reference, write access + address_space & m_space; // address space + int m_index; // user reported index + bool m_enabled; // enabled? + read_or_write m_type; // type (read/write) + offs_t m_address; // start address + offs_t m_length; // length of watch area + parsed_expression m_condition; // condition + std::string m_action; // action + int m_notifier; // address map change notifier id + + offs_t m_start_address[3]; // the start addresses of the checks to install + offs_t m_end_address[3]; // the end addresses + u64 m_masks[3]; // the access masks + bool m_installing; // prevent recursive multiple installs +}; + +// ======================> debug_registerpoint + +class debug_registerpoint +{ + friend class device_debug; + +public: + // construction/destruction + debug_registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr); + + // getters + int index() const { return m_index; } + bool enabled() const { return m_enabled; } + const char *condition() const { return m_condition.original_string(); } + const char *action() const { return m_action.c_str(); } + +private: + // internals + bool hit(); + + int m_index; // user reported index + bool m_enabled; // enabled? + parsed_expression m_condition; // condition + std::string m_action; // action +}; + +#endif // MAME_EMU_DEBUG_POINTS_H diff --git a/src/emu/debugger.cpp b/src/emu/debugger.cpp index f3a35a2a0bb..5e866057d61 100644 --- a/src/emu/debugger.cpp +++ b/src/emu/debugger.cpp @@ -31,7 +31,7 @@ static bool g_atexit_registered = false; void debugger_manager::debug_break() { - m_cpu->get_visible_cpu()->debug()->halt_on_next_instruction("Internal breakpoint\n"); + m_console->get_visible_cpu()->debug()->halt_on_next_instruction("Internal breakpoint\n"); } diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index 275d1fecedd..bd7d2235a15 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -96,6 +96,11 @@ class debug_view_manager; class parsed_expression; class symbol_table; +// declared in debug/points.h +class debug_breakpoint; +class debug_watchpoint; +class debug_registerpoint; + // declared in debugger.h class debugger_manager; diff --git a/src/frontend/mame/cheat.cpp b/src/frontend/mame/cheat.cpp index 00f8c9d67fd..daf6461b0f4 100644 --- a/src/frontend/mame/cheat.cpp +++ b/src/frontend/mame/cheat.cpp @@ -79,9 +79,7 @@ #include "ui/ui.h" #include "ui/menu.h" -#include "debugger.h" #include "emuopts.h" -#include "debug/debugcpu.h" #include #include @@ -679,7 +677,7 @@ void cheat_script::script_entry::output_argument::save(emu_file &cheatfile) cons cheat_entry::cheat_entry(cheat_manager &manager, symbol_table &globaltable, std::string const &filename, util::xml::data_node const &cheatnode) : m_manager(manager) - , m_symbols(&globaltable) + , m_symbols(manager.machine(), &globaltable) , m_state(SCRIPT_STATE_OFF) , m_numtemp(DEFAULT_TEMP_VARIABLES) , m_argindex(0) @@ -1058,7 +1056,7 @@ constexpr int cheat_manager::CHEAT_VERSION; cheat_manager::cheat_manager(running_machine &machine) : m_machine(machine) , m_disabled(true) - , m_symtable() + , m_symtable(machine) { // if the cheat engine is disabled, we're done if (!machine.options().cheat()) @@ -1081,19 +1079,6 @@ cheat_manager::cheat_manager(running_machine &machine) m_symtable.add("frombcd", 1, 1, execute_frombcd); m_symtable.add("tobcd", 1, 1, execute_tobcd); - // we rely on the debugger expression callbacks; if the debugger isn't - // enabled, we must jumpstart them manually - if ((machine.debug_flags & DEBUG_FLAG_ENABLED) == 0) - { - m_cpu = std::make_unique(machine); - m_cpu->configure_memory(m_symtable); - } - else - { - // configure for memory access (shared with debugger) - machine.debugger().cpu().configure_memory(m_symtable); - } - // load the cheats reload(); } diff --git a/src/frontend/mame/cheat.h b/src/frontend/mame/cheat.h index b81225faf15..b8f3e89a4e5 100644 --- a/src/frontend/mame/cheat.h +++ b/src/frontend/mame/cheat.h @@ -14,7 +14,6 @@ #pragma once #include "debug/express.h" -#include "debug/debugcpu.h" #include "ui/text.h" #include "xmlfile.h" @@ -345,7 +344,6 @@ private: int8_t m_lastline; // last line used for output bool m_disabled; // true if the cheat engine is disabled symbol_table m_symtable; // global symbol table - std::unique_ptr m_cpu; // debugger interface for cpus/memory // constants static constexpr int CHEAT_VERSION = 1; diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 8d3bd043ce0..993a3eeb428 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -14,6 +14,7 @@ #include "debugger.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "debug/points.h" #include "debug/textbuf.h" #include "drivenum.h" #include "emuopts.h" @@ -1577,8 +1578,8 @@ void lua_engine::initialize() debugger_type.set("consolelog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_console_textbuf()); })); debugger_type.set("errorlog", sol::property([](debugger_manager &debug) { return wrap_textbuf(debug.console().get_errorlog_textbuf()); })); debugger_type.set("visible_cpu", sol::property( - [](debugger_manager &debug) { debug.cpu().get_visible_cpu(); }, - [](debugger_manager &debug, device_t &dev) { debug.cpu().set_visible_cpu(&dev); })); + [](debugger_manager &debug) { debug.console().get_visible_cpu(); }, + [](debugger_manager &debug, device_t &dev) { debug.console().set_visible_cpu(&dev); })); debugger_type.set("execution_state", sol::property( [](debugger_manager &debug) { return debug.cpu().is_stopped() ? "stop" : "run"; @@ -1616,7 +1617,7 @@ void lua_engine::initialize() * debug:bpset(addr, [opt] cond, [opt] act) - set breakpoint on addr, cond and act are debugger * expressions. returns breakpoint index * debug:bpclr(idx) - clear break - * debug:bplist()[] - table of breakpoints (k=index, v=device_debug::breakpoint) + * debug:bplist()[] - table of breakpoints (k=index, v=debug_breakpoint) * debug:wpset(space, type, addr, len, [opt] cond, [opt] act) - set watchpoint, cond and act * are debugger expressions. * returns watchpoint index @@ -1636,8 +1637,9 @@ void lua_engine::initialize() device_debug_type.set("bpclr", &device_debug::breakpoint_clear); device_debug_type.set("bplist", [this](device_debug &dev) { sol::table table = sol().create_table(); - for(const device_debug::breakpoint &bpt : dev.breakpoint_list()) + for(const auto &bpp : dev.breakpoint_list()) { + const debug_breakpoint &bpt = *bpp.second; sol::table bp = sol().create_table(); bp["enabled"] = bpt.enabled(); bp["address"] = bpt.address(); diff --git a/src/mame/drivers/chihiro.cpp b/src/mame/drivers/chihiro.cpp index 8bbdd7f4ed0..a30570a2de3 100644 --- a/src/mame/drivers/chihiro.cpp +++ b/src/mame/drivers/chihiro.cpp @@ -682,7 +682,6 @@ St. Instr. Comment /* jamtable disassembler */ void chihiro_state::jamtable_disasm(address_space &space, uint32_t address, uint32_t size) // 0xff000080 == fff00080 { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); offs_t addr = (offs_t)address; if (!space.device().memory().translate(space.spacenum(), TRANSLATE_READ_DEBUG, addr)) @@ -694,11 +693,11 @@ void chihiro_state::jamtable_disasm(address_space &space, uint32_t address, uint { offs_t base = addr; - uint32_t opcode = cpu.read_byte(space, addr, true); + uint32_t opcode = space.read_byte(addr); addr++; - uint32_t op1 = cpu.read_dword(space, addr, true); + uint32_t op1 = space.read_dword_unaligned(addr); addr += 4; - uint32_t op2 = cpu.read_dword(space, addr, true); + uint32_t op2 = space.read_dword_unaligned(addr); addr += 4; char sop1[16]; diff --git a/src/mame/drivers/konamim2.cpp b/src/mame/drivers/konamim2.cpp index 13728e0ea0d..28f2ac63b19 100644 --- a/src/mame/drivers/konamim2.cpp +++ b/src/mame/drivers/konamim2.cpp @@ -1581,7 +1581,6 @@ void konamim2_state::dump_task_command(int ref, const std::vector & m2ptr pt_UserData; /* user-private data */ }; - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_ppc1->space(); uint64_t addr; @@ -1603,14 +1602,14 @@ void konamim2_state::dump_task_command(int ref, const std::vector & Task task; - task.t.pn_Next = cpu.read_dword(space, address + offsetof(ItemNode, pn_Next), true); - task.t.pn_Prev = cpu.read_dword(space, address + offsetof(ItemNode, pn_Prev), true); - task.t.n_SubsysType = cpu.read_byte(space, address + offsetof(ItemNode, n_SubsysType), true); - task.t.n_Type = cpu.read_byte(space, address + offsetof(ItemNode, n_Type), true); - task.t.n_Priority = cpu.read_byte(space, address + offsetof(ItemNode, n_Priority), true); - task.t.n_Flags = cpu.read_byte(space, address + offsetof(ItemNode, n_Flags), true); - task.t.n_Size = cpu.read_dword(space, address + offsetof(ItemNode, n_Size), true); - task.t.pn_Name = cpu.read_dword(space, address + offsetof(ItemNode, pn_Name), true); + task.t.pn_Next = space.read_dword(address + offsetof(ItemNode, pn_Next)); + task.t.pn_Prev = space.read_dword(address + offsetof(ItemNode, pn_Prev)); + task.t.n_SubsysType = space.read_byte(address + offsetof(ItemNode, n_SubsysType)); + task.t.n_Type = space.read_byte(address + offsetof(ItemNode, n_Type)); + task.t.n_Priority = space.read_byte(address + offsetof(ItemNode, n_Priority)); + task.t.n_Flags = space.read_byte(address + offsetof(ItemNode, n_Flags)); + task.t.n_Size = space.read_dword(address + offsetof(ItemNode, n_Size)); + task.t.pn_Name = space.read_dword(address + offsetof(ItemNode, pn_Name)); char name[128]; char *ptr = name; @@ -1618,31 +1617,31 @@ void konamim2_state::dump_task_command(int ref, const std::vector & do { - *ptr = cpu.read_byte(space, nameptr++, true); + *ptr = space.read_byte(nameptr++); } while (*ptr++ != 0); - task.t.n_Version = cpu.read_byte(space, address + offsetof(ItemNode, n_Version), true); - task.t.n_Revision = cpu.read_byte(space, address + offsetof(ItemNode, n_Revision), true); - task.t.n_Reserved0 = cpu.read_byte(space, address + offsetof(ItemNode, n_Reserved0), true); - task.t.n_ItemFlags = cpu.read_byte(space, address + offsetof(ItemNode, n_ItemFlags), true); - task.t.n_Item = cpu.read_dword(space, address + offsetof(ItemNode, n_Item), true); - task.t.n_Owner = cpu.read_dword(space, address + offsetof(ItemNode, n_Owner), true); - task.t.pn_Reserved1 = cpu.read_dword(space, address + offsetof(ItemNode, pn_Reserved1), true); - - task.pt_ThreadTask = cpu.read_dword(space, address + offsetof(Task, pt_ThreadTask), true); - task.t_WaitBits = cpu.read_dword(space, address + offsetof(Task, t_WaitBits), true); - task.t_SigBits = cpu.read_dword(space, address + offsetof(Task, t_SigBits), true); - task.t_AllocatedSigs = cpu.read_dword(space, address + offsetof(Task, t_AllocatedSigs), true); - task.pt_StackBase = cpu.read_dword(space, address + offsetof(Task, pt_StackBase), true); - task.t_StackSize = cpu.read_dword(space, address + offsetof(Task, t_StackSize), true); - task.t_MaxUSecs = cpu.read_dword(space, address + offsetof(Task, t_MaxUSecs), true); - task.t_ElapsedTime.tt_Hi = cpu.read_dword(space, address + offsetof(Task, t_ElapsedTime)+0, true); - task.t_ElapsedTime.tt_Lo = cpu.read_dword(space, address + offsetof(Task, t_ElapsedTime)+4, true); - task.t_NumTaskLaunch = cpu.read_dword(space, address + offsetof(Task, t_NumTaskLaunch), true); - task.t_Flags = cpu.read_dword(space, address + offsetof(Task, t_Flags), true); - task.t_Module = cpu.read_dword(space, address + offsetof(Task, t_Module), true); - task.t_DefaultMsgPort = cpu.read_dword(space, address + offsetof(Task, t_DefaultMsgPort), true); - task.pt_UserData = cpu.read_dword(space, address + offsetof(Task, pt_UserData), true); + task.t.n_Version = space.read_byte(address + offsetof(ItemNode, n_Version)); + task.t.n_Revision = space.read_byte(address + offsetof(ItemNode, n_Revision)); + task.t.n_Reserved0 = space.read_byte(address + offsetof(ItemNode, n_Reserved0)); + task.t.n_ItemFlags = space.read_byte(address + offsetof(ItemNode, n_ItemFlags)); + task.t.n_Item = space.read_dword(address + offsetof(ItemNode, n_Item)); + task.t.n_Owner = space.read_dword(address + offsetof(ItemNode, n_Owner)); + task.t.pn_Reserved1 = space.read_dword(address + offsetof(ItemNode, pn_Reserved1)); + + task.pt_ThreadTask = space.read_dword(address + offsetof(Task, pt_ThreadTask)); + task.t_WaitBits = space.read_dword(address + offsetof(Task, t_WaitBits)); + task.t_SigBits = space.read_dword(address + offsetof(Task, t_SigBits)); + task.t_AllocatedSigs = space.read_dword(address + offsetof(Task, t_AllocatedSigs)); + task.pt_StackBase = space.read_dword(address + offsetof(Task, pt_StackBase)); + task.t_StackSize = space.read_dword(address + offsetof(Task, t_StackSize)); + task.t_MaxUSecs = space.read_dword(address + offsetof(Task, t_MaxUSecs)); + task.t_ElapsedTime.tt_Hi = space.read_dword(address + offsetof(Task, t_ElapsedTime)+0); + task.t_ElapsedTime.tt_Lo = space.read_dword(address + offsetof(Task, t_ElapsedTime)+4); + task.t_NumTaskLaunch = space.read_dword(address + offsetof(Task, t_NumTaskLaunch)); + task.t_Flags = space.read_dword(address + offsetof(Task, t_Flags)); + task.t_Module = space.read_dword(address + offsetof(Task, t_Module)); + task.t_DefaultMsgPort = space.read_dword(address + offsetof(Task, t_DefaultMsgPort)); + task.pt_UserData = space.read_dword(address + offsetof(Task, pt_UserData)); // m2ptr pt_ThreadTask; /* I am a thread of what task? */ // uint32_t t_WaitBits; /* signals being waited for */ diff --git a/src/mame/machine/fddebug.cpp b/src/mame/machine/fddebug.cpp index a62cb823d9a..1e186468e12 100644 --- a/src/mame/machine/fddebug.cpp +++ b/src/mame/machine/fddebug.cpp @@ -883,7 +883,7 @@ static void execute_fdeliminate(running_machine &machine, int ref, int params, c static void execute_fdunlock(running_machine &machine, int ref, int params, const char **param) { - device_t *cpu = machine.debugger().cpu().get_visible_cpu(); + device_t *cpu = machine.debugger().console().get_visible_cpu(); /* support 0 or 1 parameters */ uint64_t offset; @@ -920,7 +920,7 @@ static void execute_fdunlock(running_machine &machine, int ref, int params, cons static void execute_fdignore(running_machine &machine, int ref, int params, const char **param) { - device_t *cpu = machine.debugger().cpu().get_visible_cpu(); + device_t *cpu = machine.debugger().console().get_visible_cpu(); /* support 0 or 1 parameters */ if (params == 1 && strcmp(param[0], "all") == 0) @@ -944,7 +944,7 @@ static void execute_fdignore(running_machine &machine, int ref, int params, cons /* if no parameter given, implicitly run as well */ if (params == 0) - machine.debugger().cpu().get_visible_cpu()->debug()->go(); + machine.debugger().console().get_visible_cpu()->debug()->go(); } @@ -1026,7 +1026,7 @@ static void execute_fdstate(running_machine &machine, int ref, int params, const static void execute_fdpc(running_machine &machine, int ref, int params, const char **param) { - device_t *cpu = machine.debugger().cpu().get_visible_cpu(); + device_t *cpu = machine.debugger().console().get_visible_cpu(); /* support 0 or 1 parameters */ uint64_t newpc = 0; @@ -1048,7 +1048,7 @@ static void execute_fdpc(running_machine &machine, int ref, int params, const ch static void execute_fdsearch(running_machine &machine, int ref, int params, const char **param) { - address_space &space = machine->debugger().cpu().get_visible_cpu()->memory().space(AS_PROGRAM); + address_space &space = machine->debugger().console().get_visible_cpu()->memory().space(AS_PROGRAM); int pc = space.device().state().pc(); int length, first = true; uint8_t instrdata[2]; @@ -1174,7 +1174,7 @@ static void execute_fdsearch(running_machine &machine, int ref, int params, cons static void execute_fddasm(running_machine &machine, int ref, int params, const char **param) { - address_space &space = machine->debugger().cpu().get_visible_cpu()->memory().space(AS_PROGRAM); + address_space &space = machine->debugger().console().get_visible_cpu()->memory().space(AS_PROGRAM); int origstate = fd1094_set_state(keyregion, -1); const char *filename; int skipped = false; diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 95d14f42167..2e84803167e 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -83,7 +83,6 @@ void xbox_base_state::find_debug_params() void xbox_base_state::dump_string_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); uint64_t addr; @@ -101,11 +100,10 @@ void xbox_base_state::dump_string_command(int ref, const std::vector 256) length = 256; - for (int a = 0; a < length; a++) + if (m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, buffer)) { - uint8_t c = cpu.read_byte(space, buffer + a, true); - con.printf("%c", c); + for (int a = 0; a < length; a++) + { + uint8_t c = space.read_byte(buffer + a); + con.printf("%c", c); + } } con.printf("\n"); } void xbox_base_state::dump_process_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); uint64_t addr; @@ -142,21 +142,19 @@ void xbox_base_state::dump_process_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); uint64_t addr; @@ -184,7 +182,6 @@ void xbox_base_state::dump_list_command(int ref, const std::vector con.printf("Address is unmapped.\n"); return; } - address = (offs_t)addr; if (params.size() >= 3) con.printf("Entry Object\n"); else @@ -198,7 +195,7 @@ void xbox_base_state::dump_list_command(int ref, const std::vector else con.printf("%08X\n", (uint32_t)addr); old = addr; - addr = cpu.read_dword(space, address, true); + addr = space.read_dword_unaligned(address); if (addr == start) break; if (addr == old) @@ -206,13 +203,11 @@ void xbox_base_state::dump_list_command(int ref, const std::vector address = (offs_t)addr; if (!m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, address)) break; - address = (offs_t)addr; } } void xbox_base_state::dump_dpc_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); uint64_t addr; @@ -230,20 +225,18 @@ void xbox_base_state::dump_dpc_command(int ref, const std::vector & con.printf("Address is unmapped.\n"); return; } - address = (offs_t)addr; - con.printf("Type %d word\n", cpu.read_word(space, address, true)); - con.printf("Inserted %d byte\n", cpu.read_byte(space, address + 2, true)); - con.printf("Padding %d byte\n", cpu.read_byte(space, address + 3, true)); - con.printf("DpcListEntry {%08X,%08X} _LIST_ENTRY\n", cpu.read_dword(space, address + 4, true), cpu.read_dword(space, address + 8, true)); - con.printf("DeferredRoutine %08X dword\n", cpu.read_dword(space, address + 12, true)); - con.printf("DeferredContext %08X dword\n", cpu.read_dword(space, address + 16, true)); - con.printf("SystemArgument1 %08X dword\n", cpu.read_dword(space, address + 20, true)); - con.printf("SystemArgument2 %08X dword\n", cpu.read_dword(space, address + 24, true)); + con.printf("Type %d word\n", space.read_word_unaligned(address)); + con.printf("Inserted %d byte\n", space.read_byte(address + 2)); + con.printf("Padding %d byte\n", space.read_byte(address + 3)); + con.printf("DpcListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 4), space.read_dword_unaligned(address + 8, true)); + con.printf("DeferredRoutine %08X dword\n", space.read_dword_unaligned(address + 12)); + con.printf("DeferredContext %08X dword\n", space.read_dword_unaligned(address + 16)); + con.printf("SystemArgument1 %08X dword\n", space.read_dword_unaligned(address + 20)); + con.printf("SystemArgument2 %08X dword\n", space.read_dword_unaligned(address + 24)); } void xbox_base_state::dump_timer_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); uint64_t addr; @@ -261,22 +254,20 @@ void xbox_base_state::dump_timer_command(int ref, const std::vector con.printf("Address is unmapped.\n"); return; } - address = (offs_t)addr; - con.printf("Header.Type %d byte\n", cpu.read_byte(space, address, true)); - con.printf("Header.Absolute %d byte\n", cpu.read_byte(space, address + 1, true)); - con.printf("Header.Size %d byte\n", cpu.read_byte(space, address + 2, true)); - con.printf("Header.Inserted %d byte\n", cpu.read_byte(space, address + 3, true)); - con.printf("Header.SignalState %08X dword\n", cpu.read_dword(space, address + 4, true)); - con.printf("Header.WaitListEntry {%08X,%08X} _LIST_ENTRY\n", cpu.read_dword(space, address + 8, true), cpu.read_dword(space, address + 12, true)); - con.printf("%s", string_format("DueTime %x qword\n", (int64_t)cpu.read_qword(space, address + 16, true)).c_str()); - con.printf("TimerListEntry {%08X,%08X} _LIST_ENTRY\n", cpu.read_dword(space, address + 24, true), cpu.read_dword(space, address + 28, true)); - con.printf("Dpc %08X dword\n", cpu.read_dword(space, address + 32, true)); - con.printf("Period %d dword\n", cpu.read_dword(space, address + 36, true)); + con.printf("Header.Type %d byte\n", space.read_byte(address)); + con.printf("Header.Absolute %d byte\n", space.read_byte(address + 1)); + con.printf("Header.Size %d byte\n", space.read_byte(address + 2)); + con.printf("Header.Inserted %d byte\n", space.read_byte(address + 3)); + con.printf("Header.SignalState %08X dword\n", space.read_dword_unaligned(address + 4)); + con.printf("Header.WaitListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 8), space.read_dword_unaligned(address + 12)); + con.printf("%s", string_format("DueTime %x qword\n", (int64_t)space.read_qword_unaligned(address + 16)).c_str()); + con.printf("TimerListEntry {%08X,%08X} _LIST_ENTRY\n", space.read_dword_unaligned(address + 24), space.read_dword_unaligned(address + 28)); + con.printf("Dpc %08X dword\n", space.read_dword_unaligned(address + 32)); + con.printf("Period %d dword\n", space.read_dword_unaligned(address + 36)); } void xbox_base_state::curthread_command(int ref, const std::vector ¶ms) { - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); address_space &space = m_maincpu->space(); offs_t address; @@ -288,26 +279,29 @@ void xbox_base_state::curthread_command(int ref, const std::vector con.printf("Address is unmapped.\n"); return; } - address = (offs_t)fsbase + (offs_t)debugc_bios->parameter[7-1]; - uint32_t kthrd = cpu.read_dword(space, address, true); + uint32_t kthrd = space.read_dword_unaligned(address); con.printf("Current thread is %08X\n", kthrd); address = (offs_t)(kthrd + debugc_bios->parameter[8-1]); - uint32_t topstack = cpu.read_dword(space, address, true); + if (!m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, address)) + return; + uint32_t topstack = space.read_dword_unaligned(address); con.printf("Current thread stack top is %08X\n", topstack); address = (offs_t)(kthrd + debugc_bios->parameter[4-1]); - uint32_t tlsdata = cpu.read_dword(space, address, true); + if (!m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, address)) + return; + uint32_t tlsdata = space.read_dword_unaligned(address); if (tlsdata == 0) address = (offs_t)(topstack - debugc_bios->parameter[5-1] - debugc_bios->parameter[6-1]); else address = (offs_t)(tlsdata - debugc_bios->parameter[6-1]); - con.printf("Current thread function is %08X\n", cpu.read_dword(space, address, true)); + if (m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, address)) + con.printf("Current thread function is %08X\n", space.read_dword_unaligned(address)); } void xbox_base_state::threadlist_command(int ref, const std::vector ¶ms) { address_space &space = m_maincpu->space(); - debugger_cpu &cpu = machine().debugger().cpu(); debugger_console &con = machine().debugger().console(); con.printf("Pri. _KTHREAD Stack Function\n"); @@ -315,20 +309,31 @@ void xbox_base_state::threadlist_command(int ref, const std::vector for (int pri = 0; pri < 16; pri++) { uint32_t curr = debugc_bios->parameter[1 - 1] + pri * 8; - uint32_t next = cpu.read_dword(space, curr, true); + uint32_t addr = curr; + if (!m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, addr)) + continue; + uint32_t next = space.read_dword_unaligned(addr); while ((next != curr) && (next != 0)) { uint32_t kthrd = next - debugc_bios->parameter[2 - 1]; - uint32_t topstack = cpu.read_dword(space, kthrd + debugc_bios->parameter[3 - 1], true); - uint32_t tlsdata = cpu.read_dword(space, kthrd + debugc_bios->parameter[4 - 1], true); - uint32_t function; + if (!m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, kthrd)) + break; + uint32_t topstack = space.read_dword_unaligned(kthrd + debugc_bios->parameter[3 - 1]); + uint32_t tlsdata = space.read_dword_unaligned(kthrd + debugc_bios->parameter[4 - 1]); + uint32_t function = 0; if (tlsdata == 0) - function = cpu.read_dword(space, topstack - debugc_bios->parameter[5 - 1] - debugc_bios->parameter[6 - 1], true); + addr = topstack - debugc_bios->parameter[5 - 1] - debugc_bios->parameter[6 - 1]; else - function = cpu.read_dword(space, tlsdata - debugc_bios->parameter[6 - 1], true); + addr = tlsdata - debugc_bios->parameter[6 - 1]; + if (m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, addr)) + function = space.read_dword_unaligned(addr); con.printf(" %02d %08x %08x %08x\n", pri, kthrd, topstack, function); - next = cpu.read_dword(space, next, true); + addr = next; + if (m_maincpu->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, addr)) + next = space.read_dword_unaligned(addr); + else + break; } } } diff --git a/src/osd/modules/debugger/debuggdbstub.cpp b/src/osd/modules/debugger/debuggdbstub.cpp index 63dbd420184..b8c0bbe7b80 100644 --- a/src/osd/modules/debugger/debuggdbstub.cpp +++ b/src/osd/modules/debugger/debuggdbstub.cpp @@ -9,6 +9,7 @@ #include "emu.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "debug/points.h" #include "debug/textbuf.h" #include "debug_module.h" #include "debugger.h" @@ -426,8 +427,8 @@ private: std::map m_address_map; - device_debug::breakpoint *m_triggered_breakpoint; - device_debug::watchpoint *m_triggered_watchpoint; + debug_breakpoint *m_triggered_breakpoint; + debug_watchpoint *m_triggered_watchpoint; std::string m_target_xml; @@ -596,7 +597,7 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop) } else { - device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug(); + device_debug *debug = m_debugger_console->get_visible_cpu()->debug(); m_triggered_watchpoint = debug->triggered_watchpoint(); m_triggered_breakpoint = debug->triggered_breakpoint(); if ( m_send_stop_packet ) @@ -683,7 +684,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_c(const char *buf) if ( *buf != '\0' ) return REPLY_UNSUPPORTED; - m_debugger_cpu->get_visible_cpu()->debug()->go(); + m_debugger_console->get_visible_cpu()->debug()->go(); m_send_stop_packet = true; return REPLY_NONE; } @@ -696,7 +697,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_D(const char *buf) if ( *buf != '\0' ) return REPLY_UNSUPPORTED; - m_debugger_cpu->get_visible_cpu()->debug()->go(); + m_debugger_console->get_visible_cpu()->debug()->go(); m_dettached = true; return REPLY_OK; @@ -752,7 +753,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_H(const char *buf) debug_gdbstub::cmd_reply debug_gdbstub::handle_k(const char *buf) { m_machine->schedule_exit(); - m_debugger_cpu->get_visible_cpu()->debug()->go(); + m_debugger_console->get_visible_cpu()->debug()->go(); m_dettached = true; m_socket.close(); return REPLY_NONE; @@ -969,7 +970,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_s(const char *buf) if ( *buf != '\0' ) return REPLY_UNSUPPORTED; - m_debugger_cpu->get_visible_cpu()->debug()->single_step(); + m_debugger_console->get_visible_cpu()->debug()->single_step(); m_send_stop_packet = true; return REPLY_NONE; } @@ -977,7 +978,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_s(const char *buf) //------------------------------------------------------------------------- static bool remove_breakpoint(device_debug *debug, uint64_t address, int /*kind*/) { - const device_debug::breakpoint *bp = debug->breakpoint_find(address); + const debug_breakpoint *bp = debug->breakpoint_find(address); if (bp != nullptr) return debug->breakpoint_clear(bp->index()); return false; @@ -1021,7 +1022,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_z(const char *buf) m_address_map.erase(offset); } - device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug(); + device_debug *debug = m_debugger_console->get_visible_cpu()->debug(); switch ( type ) { // Note: software and hardware breakpoints are treated both the @@ -1062,7 +1063,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_Z(const char *buf) m_address_map[offset] = address; } - device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug(); + device_debug *debug = m_debugger_console->get_visible_cpu()->debug(); switch ( type ) { // Note: software and hardware breakpoints are treated both the diff --git a/src/osd/modules/debugger/debugimgui.cpp b/src/osd/modules/debugger/debugimgui.cpp index c1e3a4de21d..296b148c5db 100644 --- a/src/osd/modules/debugger/debugimgui.cpp +++ b/src/osd/modules/debugger/debugimgui.cpp @@ -375,36 +375,36 @@ void debug_imgui::handle_keys() else { m_machine->schedule_soft_reset(); - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); } } if(ImGui::IsKeyPressed(ITEM_ID_F5,false)) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); m_running = true; } if(ImGui::IsKeyPressed(ITEM_ID_F6,false)) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_next_device(); m_running = true; } if(ImGui::IsKeyPressed(ITEM_ID_F7,false)) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_interrupt(); m_running = true; } if(ImGui::IsKeyPressed(ITEM_ID_F8,false)) - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_vblank(); if(ImGui::IsKeyPressed(ITEM_ID_F9,false)) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_out(); if(ImGui::IsKeyPressed(ITEM_ID_F10,false)) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_over(); if(ImGui::IsKeyPressed(ITEM_ID_F11,false)) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); if(ImGui::IsKeyPressed(ITEM_ID_F12,false)) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); m_hide = true; } @@ -484,7 +484,7 @@ void debug_imgui::handle_console(running_machine* machine) // if console input is empty, then do a single step if(strlen(view_main_console->console_input) == 0) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); view_main_console->exec_cmd = false; history_pos = view_main_console->console_history.size(); return; @@ -1248,33 +1248,33 @@ void debug_imgui::draw_console() ImGui::Separator(); if(ImGui::MenuItem("Run", "F5")) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); m_running = true; } if(ImGui::MenuItem("Go to next CPU", "F6")) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_next_device(); m_running = true; } if(ImGui::MenuItem("Run until next interrupt", "F7")) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_interrupt(); m_running = true; } if(ImGui::MenuItem("Run until VBLANK", "F8")) - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_vblank(); if(ImGui::MenuItem("Run and hide debugger", "F12")) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); m_hide = true; } ImGui::Separator(); if(ImGui::MenuItem("Single step", "F11")) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); if(ImGui::MenuItem("Step over", "F10")) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_over(); if(ImGui::MenuItem("Step out", "F9")) - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_out(); ImGui::EndMenu(); } diff --git a/src/osd/modules/debugger/debugwin.cpp b/src/osd/modules/debugger/debugwin.cpp index 975e7ba6bc6..18bbc07dd70 100644 --- a/src/osd/modules/debugger/debugwin.cpp +++ b/src/osd/modules/debugger/debugwin.cpp @@ -161,7 +161,7 @@ void debugger_windows::debugger_update() { HWND const focuswnd = GetFocus(); - m_machine->debugger().cpu().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n"); + m_machine->debugger().debug_break(); // if we were focused on some window's edit box, reset it to default for (auto &info : m_window_list) diff --git a/src/osd/modules/debugger/none.cpp b/src/osd/modules/debugger/none.cpp index 3ce8d6572bc..ef23fe04089 100644 --- a/src/osd/modules/debugger/none.cpp +++ b/src/osd/modules/debugger/none.cpp @@ -10,6 +10,7 @@ #include "debug_module.h" #include "modules/osdmodule.h" +#include "debug/debugcon.h" #include "debug/debugcpu.h" #include "debugger.h" @@ -42,7 +43,7 @@ void debug_none::init_debugger(running_machine &machine) void debug_none::wait_for_debugger(device_t &device, bool firststop) { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); } void debug_none::debugger_update() diff --git a/src/osd/modules/debugger/osx/debugconsole.mm b/src/osd/modules/debugger/osx/debugconsole.mm index 1bd285e8c3b..c1689a8b855 100644 --- a/src/osd/modules/debugger/osx/debugconsole.mm +++ b/src/osd/modules/debugger/osx/debugconsole.mm @@ -24,6 +24,7 @@ #include "debugger.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "debug/points.h" #include "util/xmlfile.h" @@ -181,7 +182,7 @@ [dasmSplit setFrame:rhsFrame]; // select the current processor - [self setCPU:machine->debugger().cpu().get_visible_cpu()]; + [self setCPU:machine->debugger().console().get_visible_cpu()]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(auxiliaryWindowWillClose:) @@ -219,7 +220,7 @@ NSString *command = [sender stringValue]; if ([command length] == 0) { - machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + machine->debugger().console().get_visible_cpu()->debug()->single_step(); [history reset]; } else @@ -234,10 +235,10 @@ - (IBAction)debugToggleBreakpoint:(id)sender { device_t &device = *[dasmView source]->device(); - if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device)) + if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device)) { offs_t const address = [dasmView selectedAddress]; - const device_debug::breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find(address); + const debug_breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find(address); // if it doesn't exist, add a new one NSString *command; @@ -252,9 +253,9 @@ - (IBAction)debugToggleBreakpointEnable:(id)sender { device_t &device = *[dasmView source]->device(); - if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device)) + if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device)) { - const device_debug::breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]); + const debug_breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]); if (bp != nullptr) { NSString *command; @@ -270,7 +271,7 @@ - (IBAction)debugRunToCursor:(id)sender { device_t &device = *[dasmView source]->device(); - if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device)) + if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device)) { NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)[dasmView selectedAddress]]; machine->debugger().console().execute_command([command UTF8String], 1); @@ -499,7 +500,7 @@ [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self userInfo:info]; - machine->debugger().cpu().get_visible_cpu()->debug()->go(); + machine->debugger().console().get_visible_cpu()->debug()->go(); } } @@ -562,9 +563,9 @@ SEL const action = [item action]; BOOL const inContextMenu = ([item menu] == [dasmView menu]); BOOL const haveCursor = [dasmView cursorVisible]; - BOOL const isCurrent = (machine->debugger().cpu().get_visible_cpu() == [dasmView source]->device()); + BOOL const isCurrent = (machine->debugger().console().get_visible_cpu() == [dasmView source]->device()); - const device_debug::breakpoint *breakpoint = nullptr; + const debug_breakpoint *breakpoint = nullptr; if (haveCursor) { breakpoint = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]); diff --git a/src/osd/modules/debugger/osx/debugview.mm b/src/osd/modules/debugger/osx/debugview.mm index a414e4ad8a4..df7c4dbcc01 100644 --- a/src/osd/modules/debugger/osx/debugview.mm +++ b/src/osd/modules/debugger/osx/debugview.mm @@ -10,6 +10,7 @@ #include "emu.h" #include "debugger.h" +#include "debug/debugcon.h" #include "debug/debugcpu.h" #include "modules/lib/osdobj_common.h" @@ -871,7 +872,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate) - (void)insertNewline:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + machine->debugger().console().get_visible_cpu()->debug()->single_step(); } diff --git a/src/osd/modules/debugger/osx/debugwindowhandler.mm b/src/osd/modules/debugger/osx/debugwindowhandler.mm index c1aa8e383a2..fd1eb44f6d3 100644 --- a/src/osd/modules/debugger/osx/debugwindowhandler.mm +++ b/src/osd/modules/debugger/osx/debugwindowhandler.mm @@ -14,6 +14,7 @@ #import "debugview.h" #include "debugger.h" +#include "debug/debugcon.h" #include "util/xmlfile.h" @@ -189,12 +190,12 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo - (IBAction)debugBreak:(id)sender { if (machine->debug_flags & DEBUG_FLAG_ENABLED) - machine->debugger().cpu().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n"); + machine->debugger().console().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n"); } - (IBAction)debugRun:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->go(); + machine->debugger().console().get_visible_cpu()->debug()->go(); } @@ -203,43 +204,43 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo object:self userInfo:[NSDictionary dictionaryWithObject:[NSValue valueWithPointer:machine] forKey:@"MAMEDebugMachine"]]; - machine->debugger().cpu().get_visible_cpu()->debug()->go(); + machine->debugger().console().get_visible_cpu()->debug()->go(); } - (IBAction)debugRunToNextCPU:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device(); + machine->debugger().console().get_visible_cpu()->debug()->go_next_device(); } - (IBAction)debugRunToNextInterrupt:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt(); + machine->debugger().console().get_visible_cpu()->debug()->go_interrupt(); } - (IBAction)debugRunToNextVBLANK:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank(); + machine->debugger().console().get_visible_cpu()->debug()->go_vblank(); } - (IBAction)debugStepInto:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + machine->debugger().console().get_visible_cpu()->debug()->single_step(); } - (IBAction)debugStepOver:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over(); + machine->debugger().console().get_visible_cpu()->debug()->single_step_over(); } - (IBAction)debugStepOut:(id)sender { - machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out(); + machine->debugger().console().get_visible_cpu()->debug()->single_step_out(); } - (IBAction)debugSoftReset:(id)sender { machine->schedule_soft_reset(); - machine->debugger().cpu().get_visible_cpu()->debug()->go(); + machine->debugger().console().get_visible_cpu()->debug()->go(); } diff --git a/src/osd/modules/debugger/osx/disassemblyviewer.mm b/src/osd/modules/debugger/osx/disassemblyviewer.mm index eb039f4ca17..1f286a6bfc4 100644 --- a/src/osd/modules/debugger/osx/disassemblyviewer.mm +++ b/src/osd/modules/debugger/osx/disassemblyviewer.mm @@ -16,6 +16,7 @@ #include "debugger.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "debug/points.h" #include "util/xmlfile.h" @@ -109,7 +110,7 @@ [actionButton release]; // set default state - [dasmView selectSubviewForDevice:machine->debugger().cpu().get_visible_cpu()]; + [dasmView selectSubviewForDevice:machine->debugger().console().get_visible_cpu()]; [dasmView setExpression:@"curpc"]; [expressionField setStringValue:@"curpc"]; [expressionField selectText:self]; @@ -176,7 +177,7 @@ { device_t &device = *[dasmView source]->device(); offs_t const address = [dasmView selectedAddress]; - const device_debug::breakpoint *bp = device.debug()->breakpoint_find(address); + const debug_breakpoint *bp = device.debug()->breakpoint_find(address); // if it doesn't exist, add a new one if (bp == nullptr) @@ -203,7 +204,7 @@ { device_t &device = *[dasmView source]->device(); offs_t const address = [dasmView selectedAddress]; - const device_debug::breakpoint *bp = device.debug()->breakpoint_find(address); + const debug_breakpoint *bp = device.debug()->breakpoint_find(address); if (bp != nullptr) { device.debug()->breakpoint_enable(bp->index(), !bp->enabled()); @@ -252,7 +253,7 @@ BOOL const inContextMenu = ([item menu] == [dasmView menu]); BOOL const haveCursor = [dasmView cursorVisible]; - const device_debug::breakpoint *breakpoint = nullptr; + const debug_breakpoint *breakpoint = nullptr; if (haveCursor) { breakpoint = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]); diff --git a/src/osd/modules/debugger/osx/memoryview.mm b/src/osd/modules/debugger/osx/memoryview.mm index 78af307e993..0db48236b79 100644 --- a/src/osd/modules/debugger/osx/memoryview.mm +++ b/src/osd/modules/debugger/osx/memoryview.mm @@ -9,7 +9,6 @@ #include "emu.h" #import "memoryview.h" -#include "debug/debugcpu.h" #include "debug/debugvw.h" #include "util/xmlfile.h" diff --git a/src/osd/modules/debugger/osx/memoryviewer.mm b/src/osd/modules/debugger/osx/memoryviewer.mm index 80d5434a826..b1064aee69f 100644 --- a/src/osd/modules/debugger/osx/memoryviewer.mm +++ b/src/osd/modules/debugger/osx/memoryviewer.mm @@ -14,7 +14,7 @@ #import "memoryview.h" #include "debugger.h" -#include "debug/debugcpu.h" +#include "debug/debugcon.h" #include "debug/dvmemory.h" #include "util/xmlfile.h" @@ -108,7 +108,7 @@ [actionButton release]; // set default state - [memoryView selectSubviewForDevice:machine->debugger().cpu().get_visible_cpu()]; + [memoryView selectSubviewForDevice:machine->debugger().console().get_visible_cpu()]; [memoryView setExpression:@"0"]; [expressionField setStringValue:@"0"]; [expressionField selectText:self]; diff --git a/src/osd/modules/debugger/osx/registersview.mm b/src/osd/modules/debugger/osx/registersview.mm index ae202fa488e..c710179c5bd 100644 --- a/src/osd/modules/debugger/osx/registersview.mm +++ b/src/osd/modules/debugger/osx/registersview.mm @@ -10,7 +10,7 @@ #include "emu.h" #include "debugger.h" -#include "debug/debugcpu.h" +#include "debug/debugcon.h" #include "debug/debugvw.h" @@ -30,7 +30,7 @@ - (NSSize)maximumFrameSize { debug_view_xy max; - device_t *curcpu = machine->debugger().cpu().get_visible_cpu(); + device_t *curcpu = machine->debugger().console().get_visible_cpu(); const debug_view_source *source = view->source_for_device(curcpu); max.x = max.y = 0; diff --git a/src/osd/modules/debugger/qt/dasmwindow.cpp b/src/osd/modules/debugger/qt/dasmwindow.cpp index 04cbd523cdd..52b33b50da8 100644 --- a/src/osd/modules/debugger/qt/dasmwindow.cpp +++ b/src/osd/modules/debugger/qt/dasmwindow.cpp @@ -12,6 +12,7 @@ #include "debug/debugcon.h" #include "debug/debugcpu.h" #include "debug/dvdisasm.h" +#include "debug/points.h" DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) : @@ -141,7 +142,7 @@ void DasmWindow::toggleBreakpointAtCursor(bool changedTo) device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); // If none exists, add a new one if (bp == nullptr) @@ -172,7 +173,7 @@ void DasmWindow::enableBreakpointAtCursor(bool changedTo) device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp != nullptr) { @@ -228,7 +229,7 @@ void DasmWindow::dasmViewUpdated() device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp != nullptr) { @@ -260,7 +261,7 @@ void DasmWindow::populateComboBox() void DasmWindow::setToCurrentCpu() { - device_t* curCpu = m_machine->debugger().cpu().get_visible_cpu(); + device_t* curCpu = m_machine->debugger().console().get_visible_cpu(); if (curCpu) { const debug_view_source *source = m_dasmView->view()->source_for_device(curCpu); diff --git a/src/osd/modules/debugger/qt/mainwindow.cpp b/src/osd/modules/debugger/qt/mainwindow.cpp index 6a79ebf955d..f2026db67e9 100644 --- a/src/osd/modules/debugger/qt/mainwindow.cpp +++ b/src/osd/modules/debugger/qt/mainwindow.cpp @@ -14,6 +14,7 @@ #include "debug/debugcon.h" #include "debug/debugcpu.h" #include "debug/dvdisasm.h" +#include "debug/points.h" MainWindow::MainWindow(running_machine* machine, QWidget* parent) : @@ -214,13 +215,13 @@ bool MainWindow::eventFilter(QObject* obj, QEvent* event) void MainWindow::toggleBreakpointAtCursor(bool changedTo) { debug_view_disasm *const dasmView = downcast(m_dasmFrame->view()->view()); - if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device())) + if (dasmView->cursor_visible() && (m_machine->debugger().console().get_visible_cpu() == dasmView->source()->device())) { offs_t const address = downcast(dasmView)->selected_address(); device_debug *const cpuinfo = dasmView->source()->device()->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); // If none exists, add a new one std::string command; @@ -242,13 +243,13 @@ void MainWindow::toggleBreakpointAtCursor(bool changedTo) void MainWindow::enableBreakpointAtCursor(bool changedTo) { debug_view_disasm *const dasmView = downcast(m_dasmFrame->view()->view()); - if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device())) + if (dasmView->cursor_visible() && (m_machine->debugger().console().get_visible_cpu() == dasmView->source()->device())) { offs_t const address = dasmView->selected_address(); device_debug *const cpuinfo = dasmView->source()->device()->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp != nullptr) { @@ -265,7 +266,7 @@ void MainWindow::enableBreakpointAtCursor(bool changedTo) void MainWindow::runToCursor(bool changedTo) { debug_view_disasm* dasmView = downcast(m_dasmFrame->view()->view()); - if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device())) + if (dasmView->cursor_visible() && (m_machine->debugger().console().get_visible_cpu() == dasmView->source()->device())) { offs_t address = downcast(dasmView)->selected_address(); std::string command = string_format("go 0x%X", address); @@ -304,7 +305,7 @@ void MainWindow::executeCommand(bool withClear) // A blank command is a "silent step" if (command == "") { - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); return; } @@ -396,7 +397,7 @@ void MainWindow::unmountImage(bool changedTo) void MainWindow::dasmViewUpdated() { debug_view_disasm *const dasmView = downcast(m_dasmFrame->view()->view()); - bool const haveCursor = dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device()); + bool const haveCursor = dasmView->cursor_visible() && (m_machine->debugger().console().get_visible_cpu() == dasmView->source()->device()); bool haveBreakpoint = false; bool breakpointEnabled = false; if (haveCursor) @@ -406,7 +407,7 @@ void MainWindow::dasmViewUpdated() device_debug *const cpuinfo = device->debug(); // Find an existing breakpoint at this address - const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address); + const debug_breakpoint *bp = cpuinfo->breakpoint_find(address); if (bp != nullptr) { diff --git a/src/osd/modules/debugger/qt/memorywindow.cpp b/src/osd/modules/debugger/qt/memorywindow.cpp index 2124effcbbd..bead6af0cef 100644 --- a/src/osd/modules/debugger/qt/memorywindow.cpp +++ b/src/osd/modules/debugger/qt/memorywindow.cpp @@ -295,7 +295,7 @@ void MemoryWindow::populateComboBox() void MemoryWindow::setToCurrentCpu() { - device_t* curCpu = m_machine->debugger().cpu().get_visible_cpu(); + device_t* curCpu = m_machine->debugger().console().get_visible_cpu(); if (curCpu) { const debug_view_source *source = m_memTable->view()->source_for_device(curCpu); @@ -355,27 +355,51 @@ void DebuggerMemView::mousePressEvent(QMouseEvent* event) const offs_t address = memView->addressAtCursorPosition(clickViewPosition); const debug_view_memory_source* source = downcast(memView->source()); address_space* addressSpace = source->space(); - const int nativeDataWidth = addressSpace->data_width() / 8; - const uint64_t memValue = source->device()->machine().debugger().cpu().read_memory(*addressSpace, - addressSpace->address_to_byte(address), - nativeDataWidth, - true); - const offs_t pc = source->device()->debug()->track_mem_pc_from_space_address_data(addressSpace->spacenum(), - address, - memValue); - if (pc != (offs_t)(-1)) + offs_t a = address & space->logaddrmask(); + if (!addressSpace->device().memory().translate(addressSpace->spacenum(), TRANSLATE_READ_DEBUG, a)) { - // TODO: You can specify a box that the tooltip stays alive within - might be good? - const QString addressAndPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16); - QToolTip::showText(QCursor::pos(), addressAndPc, nullptr); - - // Copy the PC into the clipboard as well - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(QString("%1").arg(pc, 2, 16)); + QToolTip::showText(QCursor::pos(), "Bad address", nullptr); } else { - QToolTip::showText(QCursor::pos(), "UNKNOWN PC", nullptr); + uint64_t memValue = addressSpace->unmap(); + auto dis = addressSpace->device().machine().disable_side_effects(); + switch (addressSpace->data_width()) + { + case 8: + memValue = space->read_byte(a); + break; + + case 16: + memValue = space->read_word_unaligned(a); + break; + + case 32: + memValue = space->read_dword_unaligned(a); + break; + + case 64: + memValue = space->read_qword_unaligned(a); + break; + } + + const offs_t pc = source->device()->debug()->track_mem_pc_from_space_address_data(addressSpace->spacenum(), + address, + memValue); + if (pc != (offs_t)(-1)) + { + // TODO: You can specify a box that the tooltip stays alive within - might be good? + const QString addressAndPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16); + QToolTip::showText(QCursor::pos(), addressAndPc, nullptr); + + // Copy the PC into the clipboard as well + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QString("%1").arg(pc, 2, 16)); + } + else + { + QToolTip::showText(QCursor::pos(), "UNKNOWN PC", nullptr); + } } } diff --git a/src/osd/modules/debugger/qt/windowqt.cpp b/src/osd/modules/debugger/qt/windowqt.cpp index dda9ee64dc7..aa32ffb5220 100644 --- a/src/osd/modules/debugger/qt/windowqt.cpp +++ b/src/osd/modules/debugger/qt/windowqt.cpp @@ -179,49 +179,49 @@ void WindowQt::debugActOpenDevices() void WindowQt::debugActRun() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); } void WindowQt::debugActRunAndHide() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go(); + m_machine->debugger().console().get_visible_cpu()->debug()->go(); hideAll(); } void WindowQt::debugActRunToNextCpu() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_next_device(); } void WindowQt::debugActRunNextInt() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_interrupt(); } void WindowQt::debugActRunNextVBlank() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank(); + m_machine->debugger().console().get_visible_cpu()->debug()->go_vblank(); } void WindowQt::debugActStepInto() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); } void WindowQt::debugActStepOver() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_over(); } void WindowQt::debugActStepOut() { - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step_out(); } void WindowQt::debugActSoftReset() { m_machine->schedule_soft_reset(); - m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step(); + m_machine->debugger().console().get_visible_cpu()->debug()->single_step(); } void WindowQt::debugActHardReset() diff --git a/src/osd/modules/debugger/win/consolewininfo.cpp b/src/osd/modules/debugger/win/consolewininfo.cpp index 27a6228d2f5..e6ad4c0986f 100644 --- a/src/osd/modules/debugger/win/consolewininfo.cpp +++ b/src/osd/modules/debugger/win/consolewininfo.cpp @@ -78,7 +78,7 @@ consolewin_info::consolewin_info(debugger_windows_interface &debugger) : } // recompute the children - set_cpu(*machine().debugger().cpu().get_visible_cpu()); + set_cpu(*machine().debugger().console().get_visible_cpu()); // mark the edit box as the default focus and set it editwin_info::set_default_focus(); @@ -481,7 +481,7 @@ bool consolewin_info::handle_command(WPARAM wparam, LPARAM lparam) void consolewin_info::process_string(std::string const &string) { if (string.empty()) // an empty string is a single step - machine().debugger().cpu().get_visible_cpu()->debug()->single_step(); + machine().debugger().console().get_visible_cpu()->debug()->single_step(); else // otherwise, just process the command machine().debugger().console().execute_command(string, true); diff --git a/src/osd/modules/debugger/win/debugviewinfo.cpp b/src/osd/modules/debugger/win/debugviewinfo.cpp index ff46d13c7fe..1b824a04b8c 100644 --- a/src/osd/modules/debugger/win/debugviewinfo.cpp +++ b/src/osd/modules/debugger/win/debugviewinfo.cpp @@ -12,6 +12,7 @@ #include "debugwininfo.h" #include "uimetrics.h" #include "debugger.h" +#include "debug/debugcon.h" #include "debug/debugcpu.h" #include "strconv.h" @@ -207,7 +208,7 @@ bool debugview_info::source_is_visible_cpu() const if (m_view != nullptr) { const debug_view_source *const source = m_view->source(); - return (source != nullptr) && (machine().debugger().cpu().get_visible_cpu() == source->device()); + return (source != nullptr) && (machine().debugger().console().get_visible_cpu() == source->device()); } return false; } @@ -245,7 +246,7 @@ bool debugview_info::set_source_for_device(device_t &device) bool debugview_info::set_source_for_visible_cpu() { - device_t *const curcpu = machine().debugger().cpu().get_visible_cpu(); + device_t *const curcpu = machine().debugger().console().get_visible_cpu(); if (curcpu != nullptr) return set_source_for_device(*curcpu); else diff --git a/src/osd/modules/debugger/win/debugwininfo.cpp b/src/osd/modules/debugger/win/debugwininfo.cpp index 1645582038c..e684e1f32fa 100644 --- a/src/osd/modules/debugger/win/debugwininfo.cpp +++ b/src/osd/modules/debugger/win/debugwininfo.cpp @@ -12,6 +12,7 @@ #include "debugviewinfo.h" #include "debugger.h" +#include "debug/debugcon.h" #include "debug/debugcpu.h" #include "window.h" #include "winutf8.h" @@ -300,31 +301,31 @@ bool debugwin_info::handle_command(WPARAM wparam, LPARAM lparam) case ID_RUN_AND_HIDE: debugger().hide_all(); case ID_RUN: - machine().debugger().cpu().get_visible_cpu()->debug()->go(); + machine().debugger().console().get_visible_cpu()->debug()->go(); return true; case ID_NEXT_CPU: - machine().debugger().cpu().get_visible_cpu()->debug()->go_next_device(); + machine().debugger().console().get_visible_cpu()->debug()->go_next_device(); return true; case ID_RUN_VBLANK: - machine().debugger().cpu().get_visible_cpu()->debug()->go_vblank(); + machine().debugger().console().get_visible_cpu()->debug()->go_vblank(); return true; case ID_RUN_IRQ: - machine().debugger().cpu().get_visible_cpu()->debug()->go_interrupt(); + machine().debugger().console().get_visible_cpu()->debug()->go_interrupt(); return true; case ID_STEP: - machine().debugger().cpu().get_visible_cpu()->debug()->single_step(); + machine().debugger().console().get_visible_cpu()->debug()->single_step(); return true; case ID_STEP_OVER: - machine().debugger().cpu().get_visible_cpu()->debug()->single_step_over(); + machine().debugger().console().get_visible_cpu()->debug()->single_step_over(); return true; case ID_STEP_OUT: - machine().debugger().cpu().get_visible_cpu()->debug()->single_step_out(); + machine().debugger().console().get_visible_cpu()->debug()->single_step_out(); return true; case ID_REWIND_STEP: @@ -348,7 +349,7 @@ bool debugwin_info::handle_command(WPARAM wparam, LPARAM lparam) case ID_SOFT_RESET: machine().schedule_soft_reset(); - machine().debugger().cpu().get_visible_cpu()->debug()->go(); + machine().debugger().console().get_visible_cpu()->debug()->go(); return true; case ID_EXIT: @@ -507,7 +508,7 @@ LRESULT debugwin_info::window_proc(UINT message, WPARAM wparam, LPARAM lparam) if (m_is_main_console) { debugger().hide_all(); - machine().debugger().cpu().get_visible_cpu()->debug()->go(); + machine().debugger().console().get_visible_cpu()->debug()->go(); } else { diff --git a/src/osd/modules/debugger/win/disasmbasewininfo.cpp b/src/osd/modules/debugger/win/disasmbasewininfo.cpp index 0d22b7b8d39..800443b47c1 100644 --- a/src/osd/modules/debugger/win/disasmbasewininfo.cpp +++ b/src/osd/modules/debugger/win/disasmbasewininfo.cpp @@ -15,6 +15,7 @@ #include "debugger.h" #include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "debug/points.h" //#include "winutf8.h" @@ -115,7 +116,7 @@ void disasmbasewin_info::update_menu() device_debug *const debug = dasmview->source_device()->debug(); // first find an existing breakpoint at this address - const device_debug::breakpoint *bp = debug->breakpoint_find(address); + const debug_breakpoint *bp = debug->breakpoint_find(address); if (bp == nullptr) { @@ -166,7 +167,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam) device_debug *const debug = dasmview->source_device()->debug(); // first find an existing breakpoint at this address - const device_debug::breakpoint *bp = debug->breakpoint_find(address); + const debug_breakpoint *bp = debug->breakpoint_find(address); // if it doesn't exist, add a new one if (!is_main_console()) @@ -204,7 +205,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam) device_debug *const debug = dasmview->source_device()->debug(); // first find an existing breakpoint at this address - const device_debug::breakpoint *bp = debug->breakpoint_find(address); + const debug_breakpoint *bp = debug->breakpoint_find(address); // if it doesn't exist, add a new one if (bp != nullptr) -- cgit v1.2.3