mirror of
https://github.com/libretro/mame.git
synced 2024-12-11 19:53:49 +00:00
Adds memory tracking to debugger. This includes two new commands: trackmem and
pcatmem(p|d|i). [Andrew Gardner] Fixes left-click selection bug in the memory window. [Andrew Gardner] Explanation: ------------ Call trackmem to start tracking which PC writes to which address in memory and pcatmem(p|d|i) to query a memory region for which PC wrote to it. Users of the QT debugger can also right click on a memory address in the memory window to make a popup message appear with the results - right-clicking also automatically copies the resultant PC onto the clipboard. (I'll attach an image of this behavior in a follow-up mail).
This commit is contained in:
parent
f57d8d2d7b
commit
7964d924b3
@ -143,6 +143,8 @@ static void execute_traceover(running_machine &machine, int ref, int params, con
|
||||
static void execute_traceflush(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_history(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_trackpc(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_trackmem(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_pcatmem(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_snap(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_source(running_machine &machine, int ref, int params, const char **param);
|
||||
static void execute_map(running_machine &machine, int ref, int params, const char **param);
|
||||
@ -292,10 +294,10 @@ void debug_command_init(running_machine &machine)
|
||||
debug_console_register_command(machine, "ignore", CMDFLAG_NONE, 0, 0, MAX_COMMAND_PARAMS, execute_ignore);
|
||||
debug_console_register_command(machine, "observe", CMDFLAG_NONE, 0, 0, MAX_COMMAND_PARAMS, execute_observe);
|
||||
|
||||
debug_console_register_command(machine, "comadd", CMDFLAG_NONE, 0, 1, 2, execute_comment);
|
||||
debug_console_register_command(machine, "comadd", CMDFLAG_NONE, 0, 1, 2, execute_comment);
|
||||
debug_console_register_command(machine, "//", CMDFLAG_NONE, 0, 1, 2, execute_comment);
|
||||
debug_console_register_command(machine, "comdelete", CMDFLAG_NONE, 0, 1, 1, execute_comment_del);
|
||||
debug_console_register_command(machine, "comsave", CMDFLAG_NONE, 0, 0, 0, execute_comment_save);
|
||||
debug_console_register_command(machine, "comdelete", CMDFLAG_NONE, 0, 1, 1, execute_comment_del);
|
||||
debug_console_register_command(machine, "comsave", CMDFLAG_NONE, 0, 0, 0, execute_comment_save);
|
||||
|
||||
debug_console_register_command(machine, "bpset", CMDFLAG_NONE, 0, 1, 3, execute_bpset);
|
||||
debug_console_register_command(machine, "bp", CMDFLAG_NONE, 0, 1, 3, execute_bpset);
|
||||
@ -369,6 +371,11 @@ void debug_command_init(running_machine &machine)
|
||||
debug_console_register_command(machine, "history", CMDFLAG_NONE, 0, 0, 2, execute_history);
|
||||
debug_console_register_command(machine, "trackpc", CMDFLAG_NONE, 0, 0, 3, execute_trackpc);
|
||||
|
||||
debug_console_register_command(machine, "trackmem", CMDFLAG_NONE, 0, 0, 3, execute_trackmem);
|
||||
debug_console_register_command(machine, "pcatmemp", CMDFLAG_NONE, AS_PROGRAM, 1, 2, execute_pcatmem);
|
||||
debug_console_register_command(machine, "pcatmemd", CMDFLAG_NONE, AS_DATA, 1, 2, execute_pcatmem);
|
||||
debug_console_register_command(machine, "pcatmemi", CMDFLAG_NONE, AS_IO, 1, 2, execute_pcatmem);
|
||||
|
||||
debug_console_register_command(machine, "snap", CMDFLAG_NONE, 0, 0, 1, execute_snap);
|
||||
|
||||
debug_console_register_command(machine, "source", CMDFLAG_NONE, 0, 1, 1, execute_source);
|
||||
@ -2694,6 +2701,82 @@ static void execute_trackpc(running_machine &machine, int ref, int params, const
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
execute_trackmem - execute the trackmem command
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void execute_trackmem(running_machine &machine, int ref, int params, const char *param[])
|
||||
{
|
||||
// Gather the on/off switch (if present)
|
||||
UINT64 turnOn = true;
|
||||
if (!debug_command_parameter_number(machine, param[0], &turnOn))
|
||||
return;
|
||||
|
||||
// Gather the cpu id (if present)
|
||||
device_t *cpu = NULL;
|
||||
if (!debug_command_parameter_cpu(machine, (params > 1) ? param[1] : NULL, &cpu))
|
||||
return;
|
||||
|
||||
// Should we clear the existing data?
|
||||
UINT64 clear = false;
|
||||
if (!debug_command_parameter_number(machine, param[2], &clear))
|
||||
return;
|
||||
|
||||
// Get the address space for the given cpu
|
||||
address_space *space;
|
||||
if (!debug_command_parameter_cpu_space(machine, (params > 1) ? param[1] : NULL, AS_PROGRAM, space))
|
||||
return;
|
||||
|
||||
// Inform the CPU it's time to start tracking memory writes
|
||||
cpu->debug()->set_track_mem(turnOn);
|
||||
|
||||
// Use the watchpoint system to catch memory writes
|
||||
space->enable_write_watchpoints(true);
|
||||
|
||||
// Clear out the existing data if requested
|
||||
if (clear)
|
||||
space->device().debug()->track_mem_data_clear();
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
execute_pcatmem - execute the pcatmem command
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void execute_pcatmem(running_machine &machine, int ref, int params, const char *param[])
|
||||
{
|
||||
// Gather the required address parameter
|
||||
UINT64 address;
|
||||
if (!debug_command_parameter_number(machine, param[0], &address))
|
||||
return;
|
||||
|
||||
// Gather the cpu id (if present)
|
||||
device_t *cpu = NULL;
|
||||
if (!debug_command_parameter_cpu(machine, (params > 1) ? param[1] : NULL, &cpu))
|
||||
return;
|
||||
|
||||
// Get the address space for the given cpu
|
||||
address_space *space;
|
||||
if (!debug_command_parameter_cpu_space(machine, (params > 1) ? param[1] : NULL, ref, space))
|
||||
return;
|
||||
|
||||
// Get the value of memory at the address
|
||||
const int nativeDataWidth = space->data_width() / 8;
|
||||
const UINT64 data = debug_read_memory(*space,
|
||||
space->address_to_byte(address),
|
||||
nativeDataWidth,
|
||||
true);
|
||||
|
||||
// Recover the pc & print
|
||||
const address_spacenum spaceNum = (address_spacenum)ref;
|
||||
const offs_t result = space->device().debug()->track_mem_pc_from_space_address_data(spaceNum, address, data);
|
||||
if (result != (offs_t)(-1))
|
||||
debug_console_printf(machine, "%02x\n", result);
|
||||
else
|
||||
debug_console_printf(machine, "UNKNOWN PC\n");
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
execute_snap - execute the snapshot command
|
||||
-------------------------------------------------*/
|
||||
|
@ -1663,7 +1663,9 @@ device_debug::device_debug(device_t &device)
|
||||
m_track_pc_set(),
|
||||
m_track_pc(false),
|
||||
m_comment_set(),
|
||||
m_comment_change(0)
|
||||
m_comment_change(0),
|
||||
m_track_mem_set(),
|
||||
m_track_mem(false)
|
||||
{
|
||||
memset(m_pc_history, 0, sizeof(m_pc_history));
|
||||
memset(m_wplist, 0, sizeof(m_wplist));
|
||||
@ -2023,6 +2025,15 @@ void device_debug::memory_read_hook(address_space &space, offs_t address, UINT64
|
||||
|
||||
void device_debug::memory_write_hook(address_space &space, offs_t address, UINT64 data, UINT64 mem_mask)
|
||||
{
|
||||
if (m_track_mem)
|
||||
{
|
||||
dasm_memory_access newAccess(space.spacenum(), address, data, history_pc(0));
|
||||
if (!m_track_mem_set.insert(newAccess))
|
||||
{
|
||||
m_track_mem_set.remove(newAccess);
|
||||
m_track_mem_set.insert(newAccess);
|
||||
}
|
||||
}
|
||||
watchpoint_check(space, WATCHPOINT_WRITE, address, data, mem_mask);
|
||||
}
|
||||
|
||||
@ -2630,6 +2641,25 @@ void device_debug::set_track_pc_visited(const offs_t& pc)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// track_mem_pc_from_address_data - returns the pc that
|
||||
// wrote the data to this address or (offs_t)(-1) for
|
||||
// 'not available'.
|
||||
//-------------------------------------------------
|
||||
|
||||
offs_t device_debug::track_mem_pc_from_space_address_data(const address_spacenum& space,
|
||||
const offs_t& address,
|
||||
const UINT64& data) const
|
||||
{
|
||||
const offs_t missing = (offs_t)(-1);
|
||||
if (m_track_mem_set.empty())
|
||||
return missing;
|
||||
dasm_memory_access* mem_access = m_track_mem_set.find(dasm_memory_access(space, address, data, 0));
|
||||
if (mem_access == NULL) return missing;
|
||||
return mem_access->m_pc;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// comment_add - adds a comment to the list at
|
||||
// the given address
|
||||
@ -2672,7 +2702,7 @@ bool device_debug::comment_remove(offs_t addr)
|
||||
|
||||
const char *device_debug::comment_text(offs_t addr) const
|
||||
{
|
||||
const UINT32 crc = compute_opcode_crc32(addr);
|
||||
const UINT32 crc = compute_opcode_crc32(addr);
|
||||
dasm_comment* comment = m_comment_set.find(dasm_comment(addr, crc, "", 0));
|
||||
if (comment == NULL) return NULL;
|
||||
return comment->m_text;
|
||||
@ -3523,7 +3553,22 @@ void device_debug::tracer::flush()
|
||||
|
||||
device_debug::dasm_pc_tag::dasm_pc_tag(const offs_t& address, const UINT32& crc)
|
||||
: m_address(address),
|
||||
m_crc(crc)
|
||||
m_crc(crc)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// dasm_memory_access - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_debug::dasm_memory_access::dasm_memory_access(const address_spacenum& address_space,
|
||||
const offs_t& address,
|
||||
const UINT64& data,
|
||||
const offs_t& pc)
|
||||
: m_address_space(address_space),
|
||||
m_address(address),
|
||||
m_data(data),
|
||||
m_pc(pc)
|
||||
{
|
||||
}
|
||||
|
||||
@ -3533,7 +3578,7 @@ device_debug::dasm_pc_tag::dasm_pc_tag(const offs_t& address, const UINT32& crc)
|
||||
|
||||
device_debug::dasm_comment::dasm_comment(offs_t address, UINT32 crc, const char *text, rgb_t color)
|
||||
: dasm_pc_tag(address, crc),
|
||||
m_text(text),
|
||||
m_color(color)
|
||||
m_text(text),
|
||||
m_color(color)
|
||||
{
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ public:
|
||||
// internals
|
||||
bool hit();
|
||||
|
||||
registerpoint * m_next; // next in the list
|
||||
registerpoint * m_next; // next in the list
|
||||
int m_index; // user reported index
|
||||
UINT8 m_enabled; // enabled?
|
||||
parsed_expression m_condition; // condition
|
||||
@ -258,6 +258,13 @@ public:
|
||||
void set_track_pc_visited(const offs_t& pc);
|
||||
void track_pc_data_clear() { m_track_pc_set.clear(); }
|
||||
|
||||
// memory tracking
|
||||
void set_track_mem(bool value) { m_track_mem = value; }
|
||||
offs_t track_mem_pc_from_space_address_data(const address_spacenum& space,
|
||||
const offs_t& address,
|
||||
const UINT64& data) const;
|
||||
void track_mem_data_clear() { m_track_mem_set.clear(); }
|
||||
|
||||
// tracing
|
||||
void trace(FILE *file, bool trace_over, const char *action);
|
||||
void trace_printf(const char *fmt, ...);
|
||||
@ -298,8 +305,8 @@ private:
|
||||
device_disasm_interface * m_disasm; // disasm interface, if present
|
||||
|
||||
// global state
|
||||
UINT32 m_flags; // debugging flags for this CPU
|
||||
symbol_table m_symtable; // symbol table for expression evaluation
|
||||
UINT32 m_flags; // debugging flags for this CPU
|
||||
symbol_table m_symtable; // symbol table for expression evaluation
|
||||
debug_instruction_hook_func m_instrhook; // per-instruction callback hook
|
||||
|
||||
// disassembly
|
||||
@ -377,11 +384,11 @@ private:
|
||||
bool operator < (const dasm_pc_tag& rhs) const
|
||||
{
|
||||
if (m_address == rhs.m_address)
|
||||
return m_crc < rhs.m_crc;
|
||||
return m_crc < rhs.m_crc;
|
||||
return (m_address < rhs.m_address);
|
||||
}
|
||||
|
||||
offs_t m_address;
|
||||
offs_t m_address; // Stores [nothing] for a given address & crc32
|
||||
UINT32 m_crc;
|
||||
};
|
||||
simple_set<dasm_pc_tag> m_track_pc_set;
|
||||
@ -393,12 +400,38 @@ private:
|
||||
public:
|
||||
dasm_comment(offs_t address, UINT32 crc, const char *text, rgb_t color);
|
||||
|
||||
astring m_text; // comment text
|
||||
rgb_t m_color; // comment color
|
||||
astring m_text; // Stores comment text & color for a given address & crc32
|
||||
rgb_t m_color;
|
||||
};
|
||||
simple_set<dasm_comment> m_comment_set; // collection of comments
|
||||
UINT32 m_comment_change; // change counter for comments
|
||||
|
||||
// memory tracking
|
||||
class dasm_memory_access
|
||||
{
|
||||
public:
|
||||
dasm_memory_access(const address_spacenum& address_space,
|
||||
const offs_t& address,
|
||||
const UINT64& data,
|
||||
const offs_t& pc);
|
||||
|
||||
// required to be included in a simple_set
|
||||
bool operator < (const dasm_memory_access& rhs) const
|
||||
{
|
||||
if ((m_address == rhs.m_address) && (m_address_space == rhs.m_address_space))
|
||||
return m_data < rhs.m_data;
|
||||
return (m_address < rhs.m_address) && (m_address_space == rhs.m_address_space);
|
||||
}
|
||||
|
||||
// Stores the PC for a given address, memory region, and data value
|
||||
address_spacenum m_address_space;
|
||||
offs_t m_address;
|
||||
UINT64 m_data;
|
||||
offs_t m_pc;
|
||||
};
|
||||
simple_set<dasm_memory_access> m_track_mem_set;
|
||||
bool m_track_mem;
|
||||
|
||||
// internal flag values
|
||||
static const UINT32 DEBUG_FLAG_OBSERVING = 0x00000001; // observing this CPU
|
||||
static const UINT32 DEBUG_FLAG_HISTORY = 0x00000002; // tracking this CPU's history
|
||||
|
@ -88,7 +88,12 @@ static const help_item static_help_list[] =
|
||||
" logerror <format>[,<item>[,...]] -- outputs one or more <item>s to the error.log\n"
|
||||
" tracelog <format>[,<item>[,...]] -- outputs one or more <item>s to the trace file using <format>\n"
|
||||
" history [<cpu>,<length>] -- outputs a brief history of visited opcodes.\n"
|
||||
" trackpc [<bool>,<cpu>,<bool>] -- toggle to visually track visited opcodes [for the given cpu [& clear]].\n"
|
||||
" trackpc [<bool>,<cpu>,<bool>] -- visually track visited opcodes [boolean to turn on and off, for the given cpu, clear].\n"
|
||||
" trackmem [<bool>,<bool>] -- record which PC writes to each memory address [boolean to turn on and off, clear].\n"
|
||||
" pcatmemp <address>[,<cpu>] -- query which PC wrote to a given program memory address for the current CPU.\n"
|
||||
" pcatmemd <address>[,<cpu>] -- query which PC wrote to a given data memory address for the current CPU.\n"
|
||||
" pcatmemi <address>[,<cpu>] -- query which PC wrote to a given I/O memory address for the current CPU.\n"
|
||||
" (Note: you can also query this info by right clicking in a memory window.\n"
|
||||
" snap [<filename>] -- save a screen snapshot\n"
|
||||
" source <filename> -- reads commands from <filename> and executes them one by one\n"
|
||||
" quit -- exits MAME and the debugger\n"
|
||||
@ -391,9 +396,44 @@ static const help_item static_help_list[] =
|
||||
"trackpc 1\n"
|
||||
" Begin tracking the current cpu's pc.\n"
|
||||
"\n"
|
||||
"trackpc 1, 0, 0\n"
|
||||
"trackpc 1, 0, 1\n"
|
||||
" Continue tracking pc on cpu 0, but clear existing track info.\n"
|
||||
},
|
||||
{
|
||||
"trackmem",
|
||||
"\n"
|
||||
" trackmem [<bool>,<cpu>,<bool>]\n"
|
||||
"\n"
|
||||
"The trackmem command logs the PC at each time a memory address is written to. "
|
||||
"The first boolean argument toggles the process on and off. The second argument is a cpu "
|
||||
"selector; if no cpu is specified, the current cpu is automatically selected. The third argument "
|
||||
" is a boolean denoting if the existing data should be cleared or not. Please refer to the "
|
||||
"pcatmem command for information on how to retrieve this data. Also, right clicking in "
|
||||
"a memory window will display the logged PC for the given address.\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"\n"
|
||||
"trackmem\n"
|
||||
" Begin tracking the current CPU's pc.\n"
|
||||
"\n"
|
||||
"trackmem 1, 0, 1\n"
|
||||
" Continue tracking memory writes on cpu 0, but clear existing track info.\n"
|
||||
},
|
||||
{
|
||||
"pcatmem",
|
||||
"\n"
|
||||
" pcatmem(p/d/i) <address>[,<cpu>]\n"
|
||||
"\n"
|
||||
"The pcatmem command returns which PC wrote to a given memory address for the current CPU. "
|
||||
"The first argument is the requested address. The second argument is a cpu selector; if no "
|
||||
"cpu is specified, the current cpu is automatically selected. Right clicking in a memory window "
|
||||
"will also display the logged PC for the given address.\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
"\n"
|
||||
"pcatmem 400000\n"
|
||||
" Print which PC wrote this CPU's memory location 0x400000.\n"
|
||||
},
|
||||
{
|
||||
"snap",
|
||||
"\n"
|
||||
|
@ -204,7 +204,7 @@ void debug_view_memory::view_notify(debug_view_notification type)
|
||||
if (type == VIEW_NOTIFY_CURSOR_CHANGED)
|
||||
{
|
||||
// normalize the cursor
|
||||
set_cursor_pos(get_cursor_pos());
|
||||
set_cursor_pos(get_cursor_pos(m_cursor));
|
||||
}
|
||||
else if (type == VIEW_NOTIFY_SOURCE_CHANGED)
|
||||
{
|
||||
@ -315,7 +315,7 @@ void debug_view_memory::view_update()
|
||||
void debug_view_memory::view_char(int chval)
|
||||
{
|
||||
// get the position
|
||||
cursor_pos pos = get_cursor_pos();
|
||||
cursor_pos pos = get_cursor_pos(m_cursor);
|
||||
|
||||
// handle the incoming key
|
||||
switch (chval)
|
||||
@ -437,7 +437,7 @@ void debug_view_memory::view_click(const int button, const debug_view_xy& pos)
|
||||
|
||||
/* cursor popup|toggle */
|
||||
bool cursorVisible = true;
|
||||
if (m_cursor.y == origcursor.y)
|
||||
if (m_cursor.y == origcursor.y && m_cursor.x == origcursor.x)
|
||||
{
|
||||
cursorVisible = !m_cursor_visible;
|
||||
}
|
||||
@ -461,7 +461,7 @@ void debug_view_memory::recompute()
|
||||
const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
|
||||
|
||||
// get the current cursor position
|
||||
cursor_pos pos = get_cursor_pos();
|
||||
cursor_pos pos = get_cursor_pos(m_cursor);
|
||||
|
||||
// determine the maximum address and address format string from the raw information
|
||||
int addrchars;
|
||||
@ -565,15 +565,15 @@ bool debug_view_memory::needs_recompute()
|
||||
// an address and a shift value
|
||||
//-------------------------------------------------
|
||||
|
||||
debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos()
|
||||
debug_view_memory::cursor_pos debug_view_memory::get_cursor_pos(const debug_view_xy& cursor)
|
||||
{
|
||||
// start with the base address for this row
|
||||
cursor_pos pos;
|
||||
pos.m_address = m_byte_offset + m_cursor.y * m_bytes_per_chunk * m_chunks_per_row;
|
||||
pos.m_address = m_byte_offset + cursor.y * m_bytes_per_chunk * m_chunks_per_row;
|
||||
|
||||
// determine the X position within the middle section, clamping as necessary
|
||||
const memory_view_pos &posdata = s_memory_pos_table[m_bytes_per_chunk];
|
||||
int xposition = m_cursor.x - m_section[1].m_pos - 1;
|
||||
int xposition = cursor.x - m_section[1].m_pos - 1;
|
||||
if (xposition < 0)
|
||||
xposition = 0;
|
||||
else if (xposition >= posdata.m_spacing * m_chunks_per_row)
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
bool reverse() const { return m_reverse_view; }
|
||||
bool ascii() const { return m_ascii_view; }
|
||||
bool physical() const { return m_no_translation; }
|
||||
offs_t addressAtCursorPosition(const debug_view_xy& pos) { return get_cursor_pos(pos).m_address; }
|
||||
|
||||
// setters
|
||||
void set_expression(const char *expression);
|
||||
@ -117,9 +118,9 @@ private:
|
||||
bool needs_recompute();
|
||||
|
||||
// cursor position management
|
||||
cursor_pos get_cursor_pos();
|
||||
cursor_pos get_cursor_pos(const debug_view_xy& cursor);
|
||||
void set_cursor_pos(cursor_pos pos);
|
||||
cursor_pos begin_update_and_get_cursor_pos() { begin_update(); return get_cursor_pos(); }
|
||||
cursor_pos begin_update_and_get_cursor_pos() { begin_update(); return get_cursor_pos(m_cursor); }
|
||||
void end_update_and_set_cursor_pos(cursor_pos pos) { set_cursor_pos(pos); end_update(); }
|
||||
|
||||
// memory access
|
||||
|
@ -52,13 +52,13 @@ public:
|
||||
m_rightBar(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~DasmWindowQtConfig() {}
|
||||
|
||||
|
||||
// Settings
|
||||
int m_cpu;
|
||||
int m_rightBar;
|
||||
|
||||
|
||||
void buildFromQWidget(QWidget* widget);
|
||||
void applyToQWidget(QWidget* widget);
|
||||
void addToXmlDataNode(xml_data_node* node) const;
|
||||
|
@ -35,9 +35,9 @@ public:
|
||||
WindowQtConfig(WIN_TYPE_LOG)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~LogWindowQtConfig() {}
|
||||
|
||||
|
||||
void buildFromQWidget(QWidget* widget);
|
||||
void applyToQWidget(QWidget* widget);
|
||||
void addToXmlDataNode(xml_data_node* node) const;
|
||||
|
@ -125,7 +125,7 @@ void MainWindow::setProcessor(device_t* processor)
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
debugActQuit();
|
||||
|
||||
|
||||
// Insure the window doesn't disappear before we get a chance to save its parameters
|
||||
event->ignore();
|
||||
}
|
||||
|
@ -171,13 +171,13 @@ public:
|
||||
m_rightBar(0),
|
||||
m_windowState()
|
||||
{}
|
||||
|
||||
|
||||
~MainWindowQtConfig() {}
|
||||
|
||||
|
||||
// Settings
|
||||
int m_rightBar;
|
||||
QByteArray m_windowState;
|
||||
|
||||
|
||||
void buildFromQWidget(QWidget* widget);
|
||||
void applyToQWidget(QWidget* widget);
|
||||
void addToXmlDataNode(xml_data_node* node) const;
|
||||
|
@ -35,9 +35,7 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
|
||||
connect(m_memoryComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(memoryRegionChanged(int)));
|
||||
|
||||
// The main memory window
|
||||
m_memTable = new DebuggerView(DVT_MEMORY,
|
||||
m_machine,
|
||||
this);
|
||||
m_memTable = new DebuggerMemView(DVT_MEMORY, m_machine, this);
|
||||
|
||||
// Layout
|
||||
QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame);
|
||||
@ -264,6 +262,65 @@ QAction* MemoryWindow::chunkSizeMenuItem(const QString& itemName)
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// DebuggerMemView
|
||||
//=========================================================================
|
||||
void DebuggerMemView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
const bool leftClick = event->button() == Qt::LeftButton;
|
||||
const bool rightClick = event->button() == Qt::RightButton;
|
||||
|
||||
if (leftClick || rightClick)
|
||||
{
|
||||
QFontMetrics actualFont = fontMetrics();
|
||||
const int fontWidth = MAX(1, actualFont.width('_'));
|
||||
const int fontHeight = MAX(1, actualFont.height());
|
||||
|
||||
debug_view_xy topLeft = view()->visible_position();
|
||||
debug_view_xy clickViewPosition;
|
||||
clickViewPosition.x = topLeft.x + (event->x() / fontWidth);
|
||||
clickViewPosition.y = topLeft.y + (event->y() / fontHeight);
|
||||
if (leftClick)
|
||||
{
|
||||
view()->process_click(DCK_LEFT_CLICK, clickViewPosition);
|
||||
}
|
||||
else if (rightClick)
|
||||
{
|
||||
// Display the last known PC to write to this memory location & copy it onto the clipboard
|
||||
debug_view_memory* memView = downcast<debug_view_memory*>(view());
|
||||
const offs_t address = memView->addressAtCursorPosition(clickViewPosition);
|
||||
const debug_view_memory_source* source = downcast<const debug_view_memory_source*>(memView->source());
|
||||
address_space* addressSpace = source->space();
|
||||
const int nativeDataWidth = addressSpace->data_width() / 8;
|
||||
const UINT64 memValue = debug_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))
|
||||
{
|
||||
// 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, NULL);
|
||||
|
||||
// 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", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
viewport()->update();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// MemoryWindowQtConfig
|
||||
//=========================================================================
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "debugqtview.h"
|
||||
#include "debugqtwindow.h"
|
||||
|
||||
class DebuggerMemView;
|
||||
|
||||
|
||||
//============================================================
|
||||
// The Memory Window.
|
||||
@ -39,7 +41,25 @@ private:
|
||||
// Widgets
|
||||
QLineEdit* m_inputEdit;
|
||||
QComboBox* m_memoryComboBox;
|
||||
DebuggerView* m_memTable;
|
||||
DebuggerMemView* m_memTable;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// The mem window gets its own debugger view to handle right click pop-ups
|
||||
//=========================================================================
|
||||
class DebuggerMemView : public DebuggerView
|
||||
{
|
||||
public:
|
||||
DebuggerMemView(const debug_view_type& type,
|
||||
running_machine* machine,
|
||||
QWidget* parent=NULL)
|
||||
: DebuggerView(type, machine, parent)
|
||||
{}
|
||||
virtual ~DebuggerMemView() {}
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
};
|
||||
|
||||
|
||||
@ -59,13 +79,13 @@ public:
|
||||
}
|
||||
|
||||
~MemoryWindowQtConfig() {}
|
||||
|
||||
|
||||
// Settings
|
||||
int m_reverse;
|
||||
int m_addressMode;
|
||||
int m_chunkSize;
|
||||
int m_memoryRegion;
|
||||
|
||||
|
||||
void buildFromQWidget(QWidget* widget);
|
||||
void applyToQWidget(QWidget* widget);
|
||||
void addToXmlDataNode(xml_data_node* node) const;
|
||||
|
@ -12,8 +12,8 @@ class DebuggerView : public QAbstractScrollArea
|
||||
|
||||
public:
|
||||
DebuggerView(const debug_view_type& type,
|
||||
running_machine* machine,
|
||||
QWidget* parent=NULL);
|
||||
running_machine* machine,
|
||||
QWidget* parent=NULL);
|
||||
virtual ~DebuggerView();
|
||||
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
@ -77,17 +77,17 @@ public:
|
||||
m_next(NULL)
|
||||
{}
|
||||
virtual ~WindowQtConfig() {}
|
||||
|
||||
|
||||
// Settings
|
||||
WindowType m_type;
|
||||
QPoint m_size;
|
||||
QPoint m_position;
|
||||
|
||||
|
||||
// Dues for becoming a member of a simple_list
|
||||
WindowQtConfig* m_next;
|
||||
WindowQtConfig* next() const { return m_next; }
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void buildFromQWidget(QWidget* widget);
|
||||
virtual void applyToQWidget(QWidget* widget);
|
||||
virtual void addToXmlDataNode(xml_data_node* node) const;
|
||||
|
Loading…
Reference in New Issue
Block a user