summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugcpu.cpp
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2020-05-25 11:15:39 -0400
committer AJR <ajrhacker@users.noreply.github.com>2020-05-25 11:15:39 -0400
commit0fa6e7eb86d3b247c46f840ef230c9331f3cc948 (patch)
treee01509e44adcff62a7d8e087c58572fce6b90e13 /src/emu/debug/debugcpu.cpp
parentad7a31ad57b09e1e0e9bb1adb03767f9dd386605 (diff)
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.
Diffstat (limited to 'src/emu/debug/debugcpu.cpp')
-rw-r--r--src/emu/debug/debugcpu.cpp1395
1 files changed, 59 insertions, 1336 deletions
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<u64[]>(NUM_TEMP_VARIABLES);
/* create a global symbol table */
- m_symtable = std::make_unique<symbol_table>();
+ m_symtable = std::make_unique<symbol_table>(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<cpu_device *>(&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
@@ -135,22 +112,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
//**************************************************************************
@@ -288,294 +249,6 @@ bool debugger_cpu::comment_load(bool is_inline)
/***************************************************************************
- 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
***************************************************************************/
@@ -605,537 +278,6 @@ void debugger_cpu::reset_transient_flags()
}
-
-/***************************************************************************
- 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
--------------------------------------------------*/
-
-void debugger_cpu::expression_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 */
- expression_write_memory_region(rgntag, address + 0, halfsize, r0);
- expression_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;
- }
- m_memory_modified = true;
- }
- }
-}
-
-
-/*-------------------------------------------------
- expression_validate - validate that the
- provided expression references an
- appropriate name
--------------------------------------------------*/
-
-expression_error::error_code debugger_cpu::expression_validate(const char *name, expression_space space)
-{
- 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;
-}
-
-
-
-//**************************************************************************
-// VARIABLE GETTERS/SETTERS
-//**************************************************************************
-
-//-------------------------------------------------
-// get_cpunum - getter callback for the
-// 'cpunum' symbol
-//-------------------------------------------------
-
-u64 debugger_cpu::get_cpunum()
-{
- execute_interface_iterator iter(m_machine.root_device());
- return iter.indexof(m_visiblecpu->execute());
-}
-
-
//**************************************************************************
// EXECUTION HOOKS
//**************************************************************************
@@ -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<symbol_table>(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<std::forward_list<debug_registerpoint>>())
, 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<parsed_expression>(m_symtable, condition);
+ m_exception_condition = std::make_unique<parsed_expression>(*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<parsed_expression>(m_symtable, condition);
+ m_privilege_condition = std::make_unique<parsed_expression>(*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_pack<std:
// given address, or nullptr if none exists there
//-------------------------------------------------
-const device_debug::breakpoint *device_debug::breakpoint_find(offs_t address) const
+const debug_breakpoint *device_debug::breakpoint_find(offs_t address) const
{
- for (const breakpoint &bp : m_bplist)
- if (bp.address() == address)
- return &bp;
+ auto bpitp = m_bplist.equal_range(address);
+ if (bpitp.first != bpitp.second)
+ return bpitp.first->second.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<debug_breakpoint>(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<watchpoint>(this, m_symtable, id, space, type, address, length, condition, action));
+ m_wplist[space.spacenum()].emplace_back(std::make_unique<debug_watchpoint>(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<u64>(m_space.data_width());
- if (start != rstart)
- {
- if (endian == ENDIANNESS_LITTLE)
- smask &= ~make_bitmask<u64>((start - rstart) * unit_size);
- else
- smask &= make_bitmask<u64>((rstart + subamask + 1 - start) * unit_size);
- }
- if (end != rend)
- {
- if (endian == ENDIANNESS_LITTLE)
- emask &= make_bitmask<u64>((subamask + 1 + end - rend) * unit_size);
- else
- emask &= ~make_bitmask<u64>((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<u64>(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<u64>(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