diff options
| author | 2015-11-08 12:56:12 +0100 | |
|---|---|---|
| committer | 2015-11-08 12:56:12 +0100 | |
| commit | 7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch) | |
| tree | f310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/emu/debug/debugcpu.c | |
| parent | a57b46ae933badd7441ce1644711dbb851e2b504 (diff) | |
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/emu/debug/debugcpu.c')
| -rw-r--r-- | src/emu/debug/debugcpu.c | 3575 |
1 files changed, 0 insertions, 3575 deletions
diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c deleted file mode 100644 index 37d451ca0fb..00000000000 --- a/src/emu/debug/debugcpu.c +++ /dev/null @@ -1,3575 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/********************************************************************* - - debugcpu.c - - Debugger CPU/memory interface engine. - -***************************************************************************/ - -#include "emu.h" -#include "emuopts.h" -#include "osdepend.h" -#include "debugcpu.h" -#include "debugcmd.h" -#include "debugcon.h" -#include "express.h" -#include "debugvw.h" -#include "debugger.h" -#include "uiinput.h" -#include "xmlfile.h" -#include "coreutil.h" -#include <ctype.h> - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define NUM_TEMP_VARIABLES 10 - -enum -{ - EXECUTION_STATE_STOPPED, - EXECUTION_STATE_RUNNING -}; - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct debugcpu_private -{ - device_t *livecpu; - device_t *visiblecpu; - device_t *breakcpu; - - FILE * source_file; /* script source file */ - - symbol_table * symtable; /* global symbol table */ - - bool within_instruction_hook; - bool vblank_occurred; - bool memory_modified; - bool debugger_access; - - int execution_state; - device_t * m_stop_when_not_device; // stop execution when the device ceases to be this - - UINT32 bpindex; - UINT32 wpindex; - UINT32 rpindex; - - UINT64 wpdata; - UINT64 wpaddr; - UINT64 tempvar[NUM_TEMP_VARIABLES]; - - osd_ticks_t last_periodic_update_time; - - bool comments_loaded; -}; - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* internal helpers */ -static void debug_cpu_exit(running_machine &machine); -static void on_vblank(running_machine &machine, screen_device &device, bool vblank_state); -static void reset_transient_flags(running_machine &machine); -static void process_source_file(running_machine &machine); - -/* expression handlers */ -static UINT64 expression_read_memory(void *param, const char *name, expression_space space, UINT32 address, int size); -static UINT64 expression_read_program_direct(address_space &space, int opcode, offs_t address, int size); -static UINT64 expression_read_memory_region(running_machine &machine, const char *rgntag, offs_t address, int size); -static void expression_write_memory(void *param, const char *name, expression_space space, UINT32 address, int size, UINT64 data); -static void expression_write_program_direct(address_space &space, int opcode, offs_t address, int size, UINT64 data); -static void expression_write_memory_region(running_machine &machine, const char *rgntag, offs_t address, int size, UINT64 data); -static expression_error::error_code expression_validate(void *param, const char *name, expression_space space); - -/* variable getters/setters */ -static UINT64 get_cpunum(symbol_table &table, void *ref); -static UINT64 get_beamx(symbol_table &table, void *ref); -static UINT64 get_beamy(symbol_table &table, void *ref); -static UINT64 get_frame(symbol_table &table, void *ref); - - - -/*************************************************************************** - INITIALIZATION AND CLEANUP -***************************************************************************/ - -/*------------------------------------------------- - debug_cpu_init - initialize the CPU - information for debugging --------------------------------------------------*/ - -void debug_cpu_init(running_machine &machine) -{ - screen_device *first_screen = machine.first_screen(); - debugcpu_private *global; - int regnum; - - /* allocate and reset globals */ - machine.debugcpu_data = global = auto_alloc_clear(machine, debugcpu_private); - global->execution_state = EXECUTION_STATE_STOPPED; - global->bpindex = 1; - global->wpindex = 1; - global->rpindex = 1; - - /* create a global symbol table */ - global->symtable = global_alloc(symbol_table(&machine)); - - // configure our base memory accessors - debug_cpu_configure_memory(machine, *global->symtable); - - /* add "wpaddr", "wpdata", "cycles", "cpunum", "logunmap" to the global symbol table */ - global->symtable->add("wpaddr", symbol_table::READ_ONLY, &global->wpaddr); - global->symtable->add("wpdata", symbol_table::READ_ONLY, &global->wpdata); - global->symtable->add("cpunum", NULL, get_cpunum); - global->symtable->add("beamx", (void *)first_screen, get_beamx); - global->symtable->add("beamy", (void *)first_screen, get_beamy); - global->symtable->add("frame", (void *)first_screen, get_frame); - - /* add the temporary variables to the global symbol table */ - for (regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++) - { - char symname[10]; - sprintf(symname, "temp%d", regnum); - global->symtable->add(symname, symbol_table::READ_WRITE, &global->tempvar[regnum]); - } - - /* first CPU is visible by default */ - global->visiblecpu = machine.firstcpu; - - /* add callback for breaking on VBLANK */ - if (machine.first_screen() != NULL) - machine.first_screen()->register_vblank_callback(vblank_state_delegate(FUNC(on_vblank), &machine)); - - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(debug_cpu_exit), &machine)); -} - - -void debug_cpu_configure_memory(running_machine &machine, symbol_table &table) -{ - table.configure_memory(&machine, expression_validate, expression_read_memory, expression_write_memory); -} - - -/*------------------------------------------------- - debug_cpu_flush_traces - flushes all traces; - this is useful if a trace is going on when we - fatalerror --------------------------------------------------*/ - -void debug_cpu_flush_traces(running_machine &machine) -{ - /* this can be called on exit even when no debugging is enabled, so - make sure the devdebug is valid before proceeding */ - device_iterator iter(machine.root_device()); - for (device_t *device = iter.first(); device != NULL; device = iter.next()) - if (device->debug() != NULL) - device->debug()->trace_flush(); -} - - - -/*************************************************************************** - DEBUGGING STATUS AND INFORMATION -***************************************************************************/ - -/*------------------------------------------------- - cpu_get_visible_cpu - return the visible CPU - device (the one that commands should apply to) --------------------------------------------------*/ - -device_t *debug_cpu_get_visible_cpu(running_machine &machine) -{ - return machine.debugcpu_data->visiblecpu; -} - - -/*------------------------------------------------- - debug_cpu_within_instruction_hook - true if - the debugger is currently live --------------------------------------------------*/ - -int debug_cpu_within_instruction_hook(running_machine &machine) -{ - return machine.debugcpu_data->within_instruction_hook; -} - - -/*------------------------------------------------- - debug_cpu_is_stopped - return true if the - current execution state is stopped --------------------------------------------------*/ - -int debug_cpu_is_stopped(running_machine &machine) -{ - debugcpu_private *global = machine.debugcpu_data; - return (global != NULL) ? (global->execution_state == EXECUTION_STATE_STOPPED) : false; -} - - - -/*************************************************************************** - SYMBOL TABLE INTERFACES -***************************************************************************/ - -/*------------------------------------------------- - debug_cpu_get_global_symtable - return the - global symbol table --------------------------------------------------*/ - -symbol_table *debug_cpu_get_global_symtable(running_machine &machine) -{ - return machine.debugcpu_data->symtable; -} - - -/*------------------------------------------------- - debug_cpu_get_visible_symtable - return the - locally-visible symbol table --------------------------------------------------*/ - -symbol_table *debug_cpu_get_visible_symtable(running_machine &machine) -{ - return &machine.debugcpu_data->visiblecpu->debug()->symtable(); -} - - -/*------------------------------------------------- - debug_cpu_source_script - specifies a debug - command script to execute --------------------------------------------------*/ - -void debug_cpu_source_script(running_machine &machine, const char *file) -{ - debugcpu_private *global = machine.debugcpu_data; - - /* close any existing source file */ - if (global->source_file != NULL) - { - fclose(global->source_file); - global->source_file = NULL; - } - - /* open a new one if requested */ - if (file != NULL) - { - global->source_file = fopen(file, "r"); - if (!global->source_file) - { - if (machine.phase() == MACHINE_PHASE_RUNNING) - debug_console_printf(machine, "Cannot open command file '%s'\n", file); - else - fatalerror("Cannot open command file '%s'\n", file); - } - } -} - - - -//************************************************************************** -// MEMORY AND DISASSEMBLY HELPERS -//************************************************************************** - -//------------------------------------------------- -// debug_comment_save - save all comments for -// the given machine -//------------------------------------------------- - -bool debug_comment_save(running_machine &machine) -{ - bool comments_saved = false; - - // if we don't have a root, bail - xml_data_node *root = xml_file_create(); - if (root == NULL) - return false; - - // wrap in a try/catch to handle errors - try - { - // create a comment node - xml_data_node *commentnode = xml_add_child(root, "mamecommentfile", NULL); - if (commentnode == NULL) - throw emu_exception(); - xml_set_attribute_int(commentnode, "version", COMMENT_VERSION); - - // create a system node - xml_data_node *systemnode = xml_add_child(commentnode, "system", NULL); - if (systemnode == NULL) - throw emu_exception(); - xml_set_attribute(systemnode, "name", machine.system().name); - - // for each device - device_iterator iter(machine.root_device()); - bool found_comments = false; - for (device_t *device = iter.first(); device != NULL; device = iter.next()) - if (device->debug() && device->debug()->comment_count() > 0) - { - // create a node for this device - xml_data_node *curnode = xml_add_child(systemnode, "cpu", NULL); - if (curnode == NULL) - throw emu_exception(); - xml_set_attribute(curnode, "tag", device->tag()); - - // export the comments - if (!device->debug()->comment_export(*curnode)) - throw emu_exception(); - found_comments = true; - } - - // flush the file - if (found_comments) - { - emu_file file(machine.options().comment_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - file_error filerr = file.open(machine.basename(), ".cmt"); - if (filerr == FILERR_NONE) - { - xml_file_write(root, file); - comments_saved = true; - } - } - } - catch (emu_exception &) - { - xml_file_free(root); - return false; - } - - // free and get out of here - xml_file_free(root); - return comments_saved; -} - - -//------------------------------------------------- -// debug_comment_load - load all comments for -// the given machine -//------------------------------------------------- - -bool debug_comment_load(running_machine &machine) -{ - // open the file - emu_file file(machine.options().comment_directory(), OPEN_FLAG_READ); - file_error filerr = file.open(machine.basename(), ".cmt"); - - // if an error, just return false - if (filerr != FILERR_NONE) - return false; - - // wrap in a try/catch to handle errors - xml_data_node *root = xml_file_read(file, NULL); - try - { - // read the file - if (root == NULL) - throw emu_exception(); - - // find the config node - xml_data_node *commentnode = xml_get_sibling(root->child, "mamecommentfile"); - if (commentnode == NULL) - throw emu_exception(); - - // validate the config data version - int version = xml_get_attribute_int(commentnode, "version", 0); - if (version != COMMENT_VERSION) - throw emu_exception(); - - // check to make sure the file is applicable - xml_data_node *systemnode = xml_get_sibling(commentnode->child, "system"); - const char *name = xml_get_attribute_string(systemnode, "name", ""); - if (strcmp(name, machine.system().name) != 0) - throw emu_exception(); - - // iterate over devices - for (xml_data_node *cpunode = xml_get_sibling(systemnode->child, "cpu"); cpunode; cpunode = xml_get_sibling(cpunode->next, "cpu")) - { - device_t *device = machine.device(xml_get_attribute_string(cpunode, "tag", "")); - if (device != NULL) - if (!device->debug()->comment_import(*cpunode)) - throw emu_exception(); - } - } - catch (emu_exception &) - { - // clean up in case of error - if (root != NULL) - xml_file_free(root); - return false; - } - - // free the parser - xml_file_free(root); - return true; -} - - - -/*************************************************************************** - MEMORY AND DISASSEMBLY HELPERS -***************************************************************************/ - -/*------------------------------------------------- - debug_cpu_translate - return the physical - address corresponding to the given logical - address --------------------------------------------------*/ - -int debug_cpu_translate(address_space &space, int intention, offs_t *address) -{ - device_memory_interface *memory; - if (space.device().interface(memory)) - return memory->translate(space.spacenum(), intention, *address); - return true; -} - - -/*************************************************************************** - DEBUGGER MEMORY ACCESSORS -***************************************************************************/ - -/*------------------------------------------------- - debug_read_byte - return a byte from the - the specified memory space --------------------------------------------------*/ - -UINT8 debug_read_byte(address_space &space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - UINT64 custom; - UINT8 result; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, return 0xff */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) - result = 0xff; - - /* if there is a custom read handler, and it returns true, use that value */ - else if (space.device().memory().read(space.spacenum(), address, 1, custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = space.read_byte(address); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - return result; -} - - -/*------------------------------------------------- - debug_read_word - return a word from the - specified memory space --------------------------------------------------*/ - -UINT16 debug_read_word(address_space &space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - UINT16 result; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is misaligned read, or if there are no word readers, just read two bytes */ - if ((address & 1) != 0) - { - UINT8 byte0 = debug_read_byte(space, address + 0, apply_translation); - UINT8 byte1 = debug_read_byte(space, address + 1, apply_translation); - - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = byte0 | (byte1 << 8); - else - result = byte1 | (byte0 << 8); - } - - /* otherwise, this proceeds like the byte case */ - else - { - UINT64 custom; - - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, return 0xffff */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) - result = 0xffff; - - /* if there is a custom read handler, and it returns true, use that value */ - else if (space.device().memory().read(space.spacenum(), address, 2, custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = space.read_word(address); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - } - - return result; -} - - -/*------------------------------------------------- - debug_read_dword - return a dword from the - specified memory space --------------------------------------------------*/ - -UINT32 debug_read_dword(address_space &space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - UINT32 result; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is misaligned read, or if there are no dword readers, just read two words */ - if ((address & 3) != 0) - { - UINT16 word0 = debug_read_word(space, address + 0, apply_translation); - UINT16 word1 = debug_read_word(space, address + 2, apply_translation); - - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = word0 | (word1 << 16); - else - result = word1 | (word0 << 16); - } - - /* otherwise, this proceeds like the byte case */ - else - { - UINT64 custom; - - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, return 0xffffffff */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) - result = 0xffffffff; - - /* if there is a custom read handler, and it returns true, use that value */ - else if (space.device().memory().read(space.spacenum(), address, 4, custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = space.read_dword(address); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - } - - return result; -} - - -/*------------------------------------------------- - debug_read_qword - return a qword from the - specified memory space --------------------------------------------------*/ - -UINT64 debug_read_qword(address_space &space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - UINT64 result; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is misaligned read, or if there are no qword readers, just read two dwords */ - if ((address & 7) != 0) - { - UINT32 dword0 = debug_read_dword(space, address + 0, apply_translation); - UINT32 dword1 = debug_read_dword(space, address + 4, apply_translation); - - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = dword0 | ((UINT64)dword1 << 32); - else - result = dword1 | ((UINT64)dword0 << 32); - } - - /* otherwise, this proceeds like the byte case */ - else - { - UINT64 custom; - - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, return 0xffffffffffffffff */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_READ_DEBUG, &address)) - result = ~(UINT64)0; - - /* if there is a custom read handler, and it returns true, use that value */ - else if (space.device().memory().read(space.spacenum(), address, 8, custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = space.read_qword(address); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - } - - return result; -} - - -/*------------------------------------------------- - debug_read_memory - return 1,2,4 or 8 bytes - from the specified memory space --------------------------------------------------*/ - -UINT64 debug_read_memory(address_space &space, offs_t address, int size, int apply_translation) -{ - UINT64 result = ~(UINT64)0 >> (64 - 8*size); - switch (size) - { - case 1: result = debug_read_byte(space, address, apply_translation); break; - case 2: result = debug_read_word(space, address, apply_translation); break; - case 4: result = debug_read_dword(space, address, apply_translation); break; - case 8: result = debug_read_qword(space, address, apply_translation); break; - } - return result; -} - - -/*------------------------------------------------- - debug_write_byte - write a byte to the - specified memory space --------------------------------------------------*/ - -void debug_write_byte(address_space &space, offs_t address, UINT8 data, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns true, use that */ - else if (space.device().memory().write(space.spacenum(), address, 1, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - space.write_byte(address, data); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - global->memory_modified = true; -} - - -/*------------------------------------------------- - debug_write_word - write a word to the - specified memory space --------------------------------------------------*/ - -void debug_write_word(address_space &space, offs_t address, UINT16 data, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is a misaligned write, or if there are no word writers, just read two bytes */ - if ((address & 1) != 0) - { - if (space.endianness() == ENDIANNESS_LITTLE) - { - debug_write_byte(space, address + 0, data >> 0, apply_translation); - debug_write_byte(space, address + 1, data >> 8, apply_translation); - } - else - { - debug_write_byte(space, address + 0, data >> 8, apply_translation); - debug_write_byte(space, address + 1, data >> 0, apply_translation); - } - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns true, use that */ - else if (space.device().memory().write(space.spacenum(), address, 2, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - space.write_word(address, data); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - global->memory_modified = true; - } -} - - -/*------------------------------------------------- - debug_write_dword - write a dword to the - specified memory space --------------------------------------------------*/ - -void debug_write_dword(address_space &space, offs_t address, UINT32 data, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is a misaligned write, or if there are no dword writers, just read two words */ - if ((address & 3) != 0) - { - if (space.endianness() == ENDIANNESS_LITTLE) - { - debug_write_word(space, address + 0, data >> 0, apply_translation); - debug_write_word(space, address + 2, data >> 16, apply_translation); - } - else - { - debug_write_word(space, address + 0, data >> 16, apply_translation); - debug_write_word(space, address + 2, data >> 0, apply_translation); - } - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns true, use that */ - else if (space.device().memory().write(space.spacenum(), address, 4, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - space.write_dword(address, data); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - global->memory_modified = true; - } -} - - -/*------------------------------------------------- - debug_write_qword - write a qword to the - specified memory space --------------------------------------------------*/ - -void debug_write_qword(address_space &space, offs_t address, UINT64 data, int apply_translation) -{ - debugcpu_private *global = space.machine().debugcpu_data; - - /* mask against the logical byte mask */ - address &= space.logbytemask(); - - /* if this is a misaligned write, or if there are no qword writers, just read two dwords */ - if ((address & 7) != 0) - { - if (space.endianness() == ENDIANNESS_LITTLE) - { - debug_write_dword(space, address + 0, data >> 0, apply_translation); - debug_write_dword(space, address + 4, data >> 32, apply_translation); - } - else - { - debug_write_dword(space, address + 0, data >> 32, apply_translation); - debug_write_dword(space, address + 4, data >> 0, apply_translation); - } - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - space.set_debugger_access(global->debugger_access = true); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && !debug_cpu_translate(space, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns true, use that */ - else if (space.device().memory().write(space.spacenum(), address, 8, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - space.write_qword(address, data); - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - global->memory_modified = true; - } -} - - -/*------------------------------------------------- - debug_write_memory - write 1,2,4 or 8 bytes - to the specified memory space --------------------------------------------------*/ - -void debug_write_memory(address_space &space, offs_t address, UINT64 data, int size, int apply_translation) -{ - switch (size) - { - case 1: debug_write_byte(space, address, data, apply_translation); break; - case 2: debug_write_word(space, address, data, apply_translation); break; - case 4: debug_write_dword(space, address, data, apply_translation); break; - case 8: debug_write_qword(space, address, data, apply_translation); break; - } -} - - -/*------------------------------------------------- - debug_read_opcode - read 1,2,4 or 8 bytes at - the given offset from opcode space --------------------------------------------------*/ - -UINT64 debug_read_opcode(address_space &space, offs_t address, int size) -{ - UINT64 result = ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size)), result2; - debugcpu_private *global = space.machine().debugcpu_data; - - /* keep in logical range */ - address &= space.logbytemask(); - - /* return early if we got the result directly */ - space.set_debugger_access(global->debugger_access = true); - device_memory_interface *memory; - if (space.device().interface(memory) && memory->readop(address, size, result2)) - { - space.set_debugger_access(global->debugger_access = false); - return result2; - } - - /* if we're bigger than the address bus, break into smaller pieces */ - if (size > space.data_width() / 8) - { - int halfsize = size / 2; - UINT64 r0 = debug_read_opcode(space, address + 0, halfsize); - UINT64 r1 = debug_read_opcode(space, address + halfsize, halfsize); - - if (space.endianness() == ENDIANNESS_LITTLE) - return r0 | (r1 << (8 * halfsize)); - else - return r1 | (r0 << (8 * halfsize)); - } - - /* translate to physical first */ - if (!debug_cpu_translate(space, TRANSLATE_FETCH_DEBUG, &address)) - return result; - - /* keep in physical range */ - address &= space.bytemask(); - offs_t addrxor = 0; - switch (space.data_width() / 8 * 10 + size) - { - /* dump opcodes in bytes from a byte-sized bus */ - case 11: - break; - - /* dump opcodes in bytes from a word-sized bus */ - case 21: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? BYTE_XOR_LE(0) : BYTE_XOR_BE(0); - break; - - /* dump opcodes in words from a word-sized bus */ - case 22: - break; - - /* dump opcodes in bytes from a dword-sized bus */ - case 41: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? BYTE4_XOR_LE(0) : BYTE4_XOR_BE(0); - break; - - /* dump opcodes in words from a dword-sized bus */ - case 42: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? WORD_XOR_LE(0) : WORD_XOR_BE(0); - break; - - /* dump opcodes in dwords from a dword-sized bus */ - case 44: - break; - - /* dump opcodes in bytes from a qword-sized bus */ - case 81: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? BYTE8_XOR_LE(0) : BYTE8_XOR_BE(0); - break; - - /* dump opcodes in words from a qword-sized bus */ - case 82: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? WORD2_XOR_LE(0) : WORD2_XOR_BE(0); - break; - - /* dump opcodes in dwords from a qword-sized bus */ - case 84: - addrxor = (space.endianness() == ENDIANNESS_LITTLE) ? DWORD_XOR_LE(0) : DWORD_XOR_BE(0); - break; - - /* dump opcodes in qwords from a qword-sized bus */ - case 88: - break; - - default: - fatalerror("debug_read_opcode: unknown type = %d\n", space.data_width() / 8 * 10 + size); - } - - /* turn on debugger access */ - if (!global->debugger_access) - space.set_debugger_access(global->debugger_access = true); - - /* switch off the size and handle unaligned accesses */ - switch (size) - { - case 1: - result = space.direct().read_byte(address, addrxor); - break; - - case 2: - result = space.direct().read_word(address & ~1, addrxor); - if ((address & 1) != 0) - { - result2 = space.direct().read_word((address & ~1) + 2, addrxor); - if (space.endianness() == ENDIANNESS_LITTLE) - result = (result >> (8 * (address & 1))) | (result2 << (16 - 8 * (address & 1))); - else - result = (result << (8 * (address & 1))) | (result2 >> (16 - 8 * (address & 1))); - result &= 0xffff; - } - break; - - case 4: - result = space.direct().read_dword(address & ~3, addrxor); - if ((address & 3) != 0) - { - result2 = space.direct().read_dword((address & ~3) + 4, addrxor); - if (space.endianness() == ENDIANNESS_LITTLE) - result = (result >> (8 * (address & 3))) | (result2 << (32 - 8 * (address & 3))); - else - result = (result << (8 * (address & 3))) | (result2 >> (32 - 8 * (address & 3))); - result &= 0xffffffff; - } - break; - - case 8: - result = space.direct().read_qword(address & ~7, addrxor); - if ((address & 7) != 0) - { - result2 = space.direct().read_qword((address & ~7) + 8, addrxor); - if (space.endianness() == ENDIANNESS_LITTLE) - result = (result >> (8 * (address & 7))) | (result2 << (64 - 8 * (address & 7))); - else - result = (result << (8 * (address & 7))) | (result2 >> (64 - 8 * (address & 7))); - } - break; - } - - /* no longer accessing via the debugger */ - space.set_debugger_access(global->debugger_access = false); - return result; -} - - - -/*************************************************************************** - INTERNAL HELPERS -***************************************************************************/ - -/*------------------------------------------------- - debug_cpu_exit - free all memory --------------------------------------------------*/ - -static void debug_cpu_exit(running_machine &machine) -{ - debugcpu_private *global = machine.debugcpu_data; - - /* free the global symbol table */ - if (global != NULL) - global_free(global->symtable); -} - - -/*------------------------------------------------- - on_vblank - called when a VBLANK hits --------------------------------------------------*/ - -static void on_vblank(running_machine &machine, screen_device &device, bool vblank_state) -{ - /* just set a global flag to be consumed later */ - if (vblank_state) - device.machine().debugcpu_data->vblank_occurred = true; -} - - -/*------------------------------------------------- - reset_transient_flags - reset the transient - flags on all CPUs --------------------------------------------------*/ - -static void reset_transient_flags(running_machine &machine) -{ - /* loop over CPUs and reset the transient flags */ - device_iterator iter(machine.root_device()); - for (device_t *device = iter.first(); device != NULL; device = iter.next()) - device->debug()->reset_transient_flag(); - machine.debugcpu_data->m_stop_when_not_device = NULL; -} - - -/*------------------------------------------------- - process_source_file - executes commands from - a source file --------------------------------------------------*/ - -static void process_source_file(running_machine &machine) -{ - debugcpu_private *global = machine.debugcpu_data; - - /* loop until the file is exhausted or until we are executing again */ - while (global->source_file != NULL && global->execution_state == EXECUTION_STATE_STOPPED) - { - char buf[512]; - int i; - char *s; - - /* stop at the end of file */ - if (feof(global->source_file)) - { - fclose(global->source_file); - global->source_file = NULL; - return; - } - - /* fetch the next line */ - memset(buf, 0, sizeof(buf)); - fgets(buf, sizeof(buf), global->source_file); - - /* strip out comments (text after '//') */ - s = strstr(buf, "//"); - if (s) - *s = '\0'; - - /* strip whitespace */ - i = (int)strlen(buf); - while((i > 0) && (isspace((UINT8)buf[i-1]))) - buf[--i] = '\0'; - - /* execute the command */ - if (buf[0]) - debug_console_execute_command(machine, buf, 1); - } -} - - - -/*************************************************************************** - EXPRESSION HANDLERS -***************************************************************************/ - -/*------------------------------------------------- - expression_get_device - return a device - based on a case insensitive tag search --------------------------------------------------*/ - -static device_t *expression_get_device(running_machine &machine, 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 machine.device(fullname.c_str()); -} - - -/*------------------------------------------------- - expression_read_memory - read 1,2,4 or 8 bytes - at the given offset in the given address - space --------------------------------------------------*/ - -static UINT64 expression_read_memory(void *param, const char *name, expression_space spacenum, UINT32 address, int size) -{ - running_machine &machine = *(running_machine *)param; - UINT64 result = ~(UINT64)0 >> (64 - 8*size); - device_t *device = NULL; - - switch (spacenum) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (device->memory().has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) - { - address_space &space = device->memory().space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); - result = debug_read_memory(space, space.address_to_byte(address), size, true); - } - break; - - case EXPSPACE_PROGRAM_PHYSICAL: - case EXPSPACE_DATA_PHYSICAL: - case EXPSPACE_IO_PHYSICAL: - case EXPSPACE_SPACE3_PHYSICAL: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (device->memory().has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) - { - address_space &space = device->memory().space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); - result = debug_read_memory(space, space.address_to_byte(address), size, false); - } - break; - - case EXPSPACE_OPCODE: - case EXPSPACE_RAMWRITE: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - result = expression_read_program_direct(device->memory().space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size); - break; - - case EXPSPACE_REGION: - if (name == NULL) - break; - result = expression_read_memory_region(machine, name, address, size); - break; - - default: - break; - } - return result; -} - - -/*------------------------------------------------- - expression_read_program_direct - read memory - directly from an opcode or RAM pointer --------------------------------------------------*/ - -static UINT64 expression_read_program_direct(address_space &space, int opcode, offs_t address, int size) -{ - UINT64 result = ~(UINT64)0 >> (64 - 8*size); - UINT8 *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; - UINT64 r0, r1; - - /* read each half, from lower address to upper address */ - r0 = expression_read_program_direct(space, opcode | 2, address + 0, halfsize); - r1 = expression_read_program_direct(space, opcode | 2, address + halfsize, halfsize); - - /* assemble based on the target endianness */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = r0 | (r1 << (8 * halfsize)); - else - result = 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 = (UINT8 *)space.get_read_ptr(address & ~lowmask); - - /* if we have a valid base, return the appropriate byte */ - if (base != NULL) - { - if (space.endianness() == ENDIANNESS_LITTLE) - result = base[BYTE8_XOR_LE(address) & lowmask]; - else - result = base[BYTE8_XOR_BE(address) & lowmask]; - } - } - return result; -} - - -/*------------------------------------------------- - expression_read_memory_region - read memory - from a memory region --------------------------------------------------*/ - -static UINT64 expression_read_memory_region(running_machine &machine, const char *rgntag, offs_t address, int size) -{ - memory_region *region = machine.root_device().memregion(rgntag); - UINT64 result = ~(UINT64)0 >> (64 - 8*size); - - /* make sure we get a valid base before proceeding */ - if (region != NULL) - { - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; - UINT64 r0, r1; - - /* read each half, from lower address to upper address */ - r0 = expression_read_memory_region(machine, rgntag, address + 0, halfsize); - r1 = expression_read_memory_region(machine, 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 */ - UINT32 lowmask = region->bytewidth() - 1; - UINT8 *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 --------------------------------------------------*/ - -static void expression_write_memory(void *param, const char *name, expression_space spacenum, UINT32 address, int size, UINT64 data) -{ - running_machine &machine = *(running_machine *)param; - device_t *device = NULL; - - switch (spacenum) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (device->memory().has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL))) - { - address_space &space = device->memory().space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_LOGICAL)); - debug_write_memory(space, space.address_to_byte(address), data, size, true); - } - break; - - case EXPSPACE_PROGRAM_PHYSICAL: - case EXPSPACE_DATA_PHYSICAL: - case EXPSPACE_IO_PHYSICAL: - case EXPSPACE_SPACE3_PHYSICAL: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (device->memory().has_space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL))) - { - address_space &space = device->memory().space(AS_PROGRAM + (spacenum - EXPSPACE_PROGRAM_PHYSICAL)); - debug_write_memory(space, space.address_to_byte(address), data, size, false); - } - break; - - case EXPSPACE_OPCODE: - case EXPSPACE_RAMWRITE: - if (name != NULL) - device = expression_get_device(machine, name); - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - expression_write_program_direct(device->memory().space(AS_PROGRAM), (spacenum == EXPSPACE_OPCODE), address, size, data); - break; - - case EXPSPACE_REGION: - if (name == NULL) - break; - expression_write_memory_region(machine, name, address, size, data); - break; - - default: - break; - } -} - - -/*------------------------------------------------- - expression_write_program_direct - write memory - directly to an opcode or RAM pointer --------------------------------------------------*/ - -static void expression_write_program_direct(address_space &space, int opcode, offs_t address, int size, UINT64 data) -{ - debugcpu_private *global = space.machine().debugcpu_data; - UINT8 *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; - UINT64 r0, r1, halfmask; - - /* break apart based on the target endianness */ - halfmask = ~(UINT64)0 >> (64 - 8 * halfsize); - 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 */ - base = (UINT8 *)space.get_read_ptr(address & ~lowmask); - - /* if we have a valid base, write the appropriate byte */ - if (base != NULL) - { - if (space.endianness() == ENDIANNESS_LITTLE) - base[BYTE8_XOR_LE(address) & lowmask] = data; - else - base[BYTE8_XOR_BE(address) & lowmask] = data; - global->memory_modified = true; - } - } -} - - -/*------------------------------------------------- - expression_write_memory_region - write memory - from a memory region --------------------------------------------------*/ - -static void expression_write_memory_region(running_machine &machine, const char *rgntag, offs_t address, int size, UINT64 data) -{ - debugcpu_private *global = machine.debugcpu_data; - memory_region *region = machine.root_device().memregion(rgntag); - - /* make sure we get a valid base before proceeding */ - if (region != NULL) - { - /* call ourself recursively until we are byte-sized */ - if (size > 1) - { - int halfsize = size / 2; - UINT64 r0, r1, halfmask; - - /* break apart based on the target endianness */ - halfmask = ~(UINT64)0 >> (64 - 8 * halfsize); - 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(machine, rgntag, address + 0, halfsize, r0); - expression_write_memory_region(machine, 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 */ - UINT32 lowmask = region->bytewidth() - 1; - UINT8 *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; - global->memory_modified = true; - } - } -} - - -/*------------------------------------------------- - expression_validate - validate that the - provided expression references an - appropriate name --------------------------------------------------*/ - -static expression_error::error_code expression_validate(void *param, const char *name, expression_space space) -{ - running_machine &machine = *(running_machine *)param; - device_t *device = NULL; - - switch (space) - { - case EXPSPACE_PROGRAM_LOGICAL: - case EXPSPACE_DATA_LOGICAL: - case EXPSPACE_IO_LOGICAL: - case EXPSPACE_SPACE3_LOGICAL: - if (name != NULL) - { - device = expression_get_device(machine, name); - if (device == NULL) - return expression_error::INVALID_MEMORY_NAME; - } - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (!device->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 != NULL) - { - device = expression_get_device(machine, name); - if (device == NULL) - return expression_error::INVALID_MEMORY_NAME; - } - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (!device->memory().has_space(AS_PROGRAM + (space - EXPSPACE_PROGRAM_PHYSICAL))) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_OPCODE: - case EXPSPACE_RAMWRITE: - if (name != NULL) - { - device = expression_get_device(machine, name); - if (device == NULL) - return expression_error::INVALID_MEMORY_NAME; - } - if (device == NULL) - device = debug_cpu_get_visible_cpu(machine); - if (!device->memory().has_space(AS_PROGRAM)) - return expression_error::NO_SUCH_MEMORY_SPACE; - break; - - case EXPSPACE_REGION: - if (name == NULL) - return expression_error::MISSING_MEMORY_NAME; - if (machine.root_device().memregion(name)->base() == NULL) - return expression_error::INVALID_MEMORY_NAME; - break; - - default: - return expression_error::NO_SUCH_MEMORY_SPACE; - } - return expression_error::NONE; -} - - - -/*************************************************************************** - VARIABLE GETTERS/SETTERS -***************************************************************************/ - -/*------------------------------------------------- - get_beamx - get beam horizontal position --------------------------------------------------*/ - -static UINT64 get_beamx(symbol_table &table, void *ref) -{ - screen_device *screen = reinterpret_cast<screen_device *>(ref); - return (screen != NULL) ? screen->hpos() : 0; -} - - -/*------------------------------------------------- - get_beamy - get beam vertical position --------------------------------------------------*/ - -static UINT64 get_beamy(symbol_table &table, void *ref) -{ - screen_device *screen = reinterpret_cast<screen_device *>(ref); - return (screen != NULL) ? screen->vpos() : 0; -} - - -/*------------------------------------------------- - get_frame - get current frame number --------------------------------------------------*/ - -static UINT64 get_frame(symbol_table &table, void *ref) -{ - screen_device *screen = reinterpret_cast<screen_device *>(ref); - return (screen != NULL) ? screen->frame_number() : 0; -} - - -/*------------------------------------------------- - get_cpunum - getter callback for the - 'cpunum' symbol --------------------------------------------------*/ - -static UINT64 get_cpunum(symbol_table &table, void *ref) -{ - running_machine &machine = *reinterpret_cast<running_machine *>(table.globalref()); - device_t *target = machine.debugcpu_data->visiblecpu; - - execute_interface_iterator iter(machine.root_device()); - return iter.indexof(target->execute()); -} - - - -//************************************************************************** -// DEVICE DEBUG -//************************************************************************** - -//------------------------------------------------- -// device_debug - constructor -//------------------------------------------------- - -device_debug::device_debug(device_t &device) - : m_device(device), - m_exec(NULL), - m_memory(NULL), - m_state(NULL), - m_disasm(NULL), - m_flags(0), - m_symtable(&device, debug_cpu_get_global_symtable(device.machine())), - m_instrhook(NULL), - m_dasm_override(NULL), - m_opwidth(0), - m_stepaddr(0), - m_stepsleft(0), - m_stopaddr(0), - m_stoptime(attotime::zero), - m_stopirq(0), - m_stopexception(0), - m_endexectime(attotime::zero), - m_total_cycles(0), - m_last_total_cycles(0), - m_pc_history_index(0), - m_bplist(NULL), - m_rplist(NULL), - m_trace(NULL), - m_hotspot_threshhold(0), - m_track_pc_set(), - m_track_pc(false), - m_comment_set(), - 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)); - - // find out which interfaces we have to work with - device.interface(m_exec); - device.interface(m_memory); - device.interface(m_state); - device.interface(m_disasm); - - // set up state-related stuff - if (m_state != NULL) - { - // add global symbol for cycles and totalcycles - if (m_exec != NULL) - { - m_symtable.add("cycles", NULL, get_cycles); - m_symtable.add("totalcycles", NULL, get_totalcycles); - m_symtable.add("lastinstructioncycles", NULL, get_lastinstructioncycles); - } - - // add entries to enable/disable unmap reporting for each space - if (m_memory != NULL) - { - if (m_memory->has_space(AS_PROGRAM)) - m_symtable.add("logunmap", (void *)&m_memory->space(AS_PROGRAM), get_logunmap, set_logunmap); - if (m_memory->has_space(AS_DATA)) - m_symtable.add("logunmapd", (void *)&m_memory->space(AS_DATA), get_logunmap, set_logunmap); - if (m_memory->has_space(AS_IO)) - m_symtable.add("logunmapi", (void *)&m_memory->space(AS_IO), get_logunmap, set_logunmap); - } - - // add all registers into it - std::string tempstr; - for (const device_state_entry *entry = m_state->state_first(); entry != NULL; entry = entry->next()) { - strmakelower(tempstr.assign(entry->symbol())); - m_symtable.add(tempstr.c_str(), (void *)(FPTR)entry->index(), get_state, set_state); - } - } - - // set up execution-related stuff - if (m_exec != NULL) - { - m_flags = DEBUG_FLAG_OBSERVING | DEBUG_FLAG_HISTORY; - m_opwidth = min_opcode_bytes(); - - // if no curpc, add one - if (m_state != NULL && m_symtable.find("curpc") == NULL) - m_symtable.add("curpc", NULL, get_current_pc); - } -} - - -//------------------------------------------------- -// ~device_debug - constructor -//------------------------------------------------- - -device_debug::~device_debug() -{ - auto_free(m_device.machine(), m_trace); - - // free breakpoints and watchpoints - breakpoint_clear_all(); - watchpoint_clear_all(); - registerpoint_clear_all(); -} - - -//------------------------------------------------- -// start_hook - the scheduler calls this hook -// before beginning execution for the given device -//------------------------------------------------- - -void device_debug::start_hook(const attotime &endtime) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert((m_device.machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); - - // stash a pointer to the current live CPU - assert(global->livecpu == NULL); - global->livecpu = &m_device; - - // if we're a new device, stop now - if (global->m_stop_when_not_device != NULL && global->m_stop_when_not_device != &m_device) - { - global->m_stop_when_not_device = NULL; - global->execution_state = EXECUTION_STATE_STOPPED; - reset_transient_flags(m_device.machine()); - } - - // update the target execution end time - m_endexectime = endtime; - - // if we're running, do some periodic updating - if (global->execution_state != EXECUTION_STATE_STOPPED) - { - // check for periodic updates - if (&m_device == global->visiblecpu && osd_ticks() > global->last_periodic_update_time + osd_ticks_per_second()/4) - { - m_device.machine().debug_view().update_all(); - m_device.machine().debug_view().flush_osd_updates(); - global->last_periodic_update_time = osd_ticks(); - } - - // check for pending breaks - else if (&m_device == global->breakcpu) - { - global->execution_state = EXECUTION_STATE_STOPPED; - global->breakcpu = NULL; - } - - // if a VBLANK occurred, check on things - if (global->vblank_occurred) - { - global->vblank_occurred = false; - - // if we were waiting for a VBLANK, signal it now - if ((m_flags & DEBUG_FLAG_STOP_VBLANK) != 0) - { - global->execution_state = EXECUTION_STATE_STOPPED; - debug_console_printf(m_device.machine(), "Stopped at VBLANK\n"); - } - } - // check for debug keypresses - if (ui_input_pressed(m_device.machine(), IPT_UI_DEBUG_BREAK)) - global->visiblecpu->debug()->halt_on_next_instruction("User-initiated break\n"); - } - - // recompute the debugging mode - compute_debug_flags(); -} - - -//------------------------------------------------- -// stop_hook - the scheduler calls this hook when -// ending execution for the given device -//------------------------------------------------- - -void device_debug::stop_hook() -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(global->livecpu == &m_device); - - // clear the live CPU - global->livecpu = NULL; -} - - -//------------------------------------------------- -// interrupt_hook - called when an interrupt is -// acknowledged -//------------------------------------------------- - -void device_debug::interrupt_hook(int irqline) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - // see if this matches a pending interrupt request - if ((m_flags & DEBUG_FLAG_STOP_INTERRUPT) != 0 && (m_stopirq == -1 || m_stopirq == irqline)) - { - global->execution_state = EXECUTION_STATE_STOPPED; - debug_console_printf(m_device.machine(), "Stopped on interrupt (CPU '%s', IRQ %d)\n", m_device.tag(), irqline); - compute_debug_flags(); - } -} - - -//------------------------------------------------- -// exception_hook - called when an exception is -// generated -//------------------------------------------------- - -void device_debug::exception_hook(int exception) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - // see if this matches a pending interrupt request - if ((m_flags & DEBUG_FLAG_STOP_EXCEPTION) != 0 && (m_stopexception == -1 || m_stopexception == exception)) - { - global->execution_state = EXECUTION_STATE_STOPPED; - debug_console_printf(m_device.machine(), "Stopped on exception (CPU '%s', exception %d)\n", m_device.tag(), exception); - compute_debug_flags(); - } -} - - -//------------------------------------------------- -// instruction_hook - called by the CPU cores -// before executing each instruction -//------------------------------------------------- - -void device_debug::instruction_hook(offs_t curpc) -{ - running_machine &machine = m_device.machine(); - debugcpu_private *global = machine.debugcpu_data; - - // note that we are in the debugger code - global->within_instruction_hook = true; - - // update the history - m_pc_history[m_pc_history_index++ % HISTORY_SIZE] = curpc; - - // update total cycles - m_last_total_cycles = m_total_cycles; - m_total_cycles = m_exec->total_cycles(); - - // are we tracking our recent pc visits? - if (m_track_pc) - { - const UINT32 crc = compute_opcode_crc32(curpc); - m_track_pc_set.insert(dasm_pc_tag(curpc, crc)); - } - - // are we tracing? - if (m_trace != NULL) - m_trace->update(curpc); - - // per-instruction hook? - if (global->execution_state != EXECUTION_STATE_STOPPED && (m_flags & DEBUG_FLAG_HOOKED) != 0 && (*m_instrhook)(m_device, curpc)) - global->execution_state = EXECUTION_STATE_STOPPED; - - // handle single stepping - if (global->execution_state != EXECUTION_STATE_STOPPED && (m_flags & DEBUG_FLAG_STEPPING_ANY) != 0) - { - // is this an actual step? - if (m_stepaddr == ~0 || curpc == m_stepaddr) - { - // decrement the count and reset the breakpoint - m_stepsleft--; - m_stepaddr = ~0; - - // if we hit 0, stop - if (m_stepsleft == 0) - global->execution_state = EXECUTION_STATE_STOPPED; - - // update every 100 steps until we are within 200 of the end - else if ((m_flags & DEBUG_FLAG_STEPPING_OUT) == 0 && (m_stepsleft < 200 || m_stepsleft % 100 == 0)) - { - machine.debug_view().update_all(); - machine.debug_view().flush_osd_updates(); - debugger_refresh_display(machine); - } - } - } - - // handle breakpoints - if (global->execution_state != EXECUTION_STATE_STOPPED && (m_flags & (DEBUG_FLAG_STOP_TIME | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) - { - // see if we hit a target time - if ((m_flags & DEBUG_FLAG_STOP_TIME) != 0 && machine.time() >= m_stoptime) - { - debug_console_printf(machine, "Stopped at time interval %.1g\n", machine.time().as_double()); - global->execution_state = EXECUTION_STATE_STOPPED; - } - - // check the temp running breakpoint and break if we hit it - else if ((m_flags & DEBUG_FLAG_STOP_PC) != 0 && m_stopaddr == curpc) - { - debug_console_printf(machine, "Stopped at temporary breakpoint %X on CPU '%s'\n", m_stopaddr, m_device.tag()); - global->execution_state = EXECUTION_STATE_STOPPED; - } - - // check for execution breakpoints - else if ((m_flags & DEBUG_FLAG_LIVE_BP) != 0) - breakpoint_check(curpc); - } - - // if we are supposed to halt, do it now - if (global->execution_state == EXECUTION_STATE_STOPPED) - { - bool firststop = true; - - // load comments if we haven't yet - if (!global->comments_loaded) - { - debug_comment_load(m_device.machine()); - global->comments_loaded = true; - } - - // reset any transient state - reset_transient_flags(m_device.machine()); - global->breakcpu = NULL; - - // remember the last visible CPU in the debugger - global->visiblecpu = &m_device; - - // update all views - machine.debug_view().update_all(); - debugger_refresh_display(m_device.machine()); - - // wait for the debugger; during this time, disable sound output - m_device.machine().sound().debugger_mute(true); - while (global->execution_state == EXECUTION_STATE_STOPPED) - { - // flush any pending updates before waiting again - machine.debug_view().flush_osd_updates(); - - // clear the memory modified flag and wait - global->memory_modified = false; - if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED) - machine.osd().wait_for_debugger(m_device, firststop); - firststop = false; - - // if something modified memory, update the screen - if (global->memory_modified) - { - machine.debug_view().update_all(DVT_DISASSEMBLY); - debugger_refresh_display(m_device.machine()); - } - - // check for commands in the source file - process_source_file(m_device.machine()); - - // if an event got scheduled, resume - if (machine.scheduled_event_pending()) - global->execution_state = EXECUTION_STATE_RUNNING; - } - m_device.machine().sound().debugger_mute(false); - - // remember the last visible CPU in the debugger - global->visiblecpu = &m_device; - } - - // handle step out/over on the instruction we are about to execute - if ((m_flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT)) != 0 && m_stepaddr == ~0) - prepare_for_step_overout(pc()); - - // no longer in debugger code - global->within_instruction_hook = false; -} - - -//------------------------------------------------- -// memory_read_hook - the memory system calls -// this hook when watchpoints are enabled and a -// memory read happens -//------------------------------------------------- - -void device_debug::memory_read_hook(address_space &space, offs_t address, UINT64 mem_mask) -{ - // check watchpoints - watchpoint_check(space, WATCHPOINT_READ, address, 0, mem_mask); - - // check hotspots - if (!m_hotspots.empty()) - hotspot_check(space, address); -} - - -//------------------------------------------------- -// memory_write_hook - the memory system calls -// this hook when watchpoints are enabled and a -// memory write happens -//------------------------------------------------- - -void device_debug::memory_write_hook(address_space &space, offs_t address, UINT64 data, UINT64 mem_mask) -{ - if (m_track_mem) - { - dasm_memory_access const newAccess(space.spacenum(), address, data, history_pc(0)); - std::pair<std::set<dasm_memory_access>::iterator, bool> trackedAccess = m_track_mem_set.insert(newAccess); - if (!trackedAccess.second) - trackedAccess.first->m_pc = newAccess.m_pc; - } - watchpoint_check(space, WATCHPOINT_WRITE, address, data, mem_mask); -} - - -//------------------------------------------------- -// set_instruction_hook - set a hook to be -// called on each instruction for a given device -//------------------------------------------------- - -void device_debug::set_instruction_hook(debug_instruction_hook_func hook) -{ - // set the hook and also the CPU's flag for fast knowledge of the hook - m_instrhook = hook; - if (hook != NULL) - m_flags |= DEBUG_FLAG_HOOKED; - else - m_flags &= ~DEBUG_FLAG_HOOKED; -} - - -//------------------------------------------------- -// disassemble - disassemble a line at a given -// PC on a given device -//------------------------------------------------- - -offs_t device_debug::disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) const -{ - offs_t result = 0; - - // check for disassembler override - if (m_dasm_override != NULL) - result = (*m_dasm_override)(m_device, buffer, pc, oprom, opram, 0); - - // if we have a disassembler, run it - if (result == 0 && m_disasm != NULL) - result = m_disasm->disassemble(buffer, pc, oprom, opram, 0); - - // make sure we get good results - assert((result & DASMFLAG_LENGTHMASK) != 0); -#ifdef MAME_DEBUG - if (m_memory != NULL && m_disasm != NULL) - { - address_space &space = m_memory->space(AS_PROGRAM); - int bytes = space.address_to_byte(result & DASMFLAG_LENGTHMASK); - assert(bytes >= m_disasm->min_opcode_bytes()); - assert(bytes <= m_disasm->max_opcode_bytes()); - (void) bytes; // appease compiler - } -#endif - - return result; -} - - -//------------------------------------------------- -// ignore - ignore/observe a given device -//------------------------------------------------- - -void device_debug::ignore(bool ignore) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - if (ignore) - m_flags &= ~DEBUG_FLAG_OBSERVING; - else - m_flags |= DEBUG_FLAG_OBSERVING; - - if (&m_device == global->livecpu && ignore) - go_next_device(); -} - - -//------------------------------------------------- -// single_step - single step the device past the -// requested number of instructions -//------------------------------------------------- - -void device_debug::single_step(int numsteps) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stepsleft = numsteps; - m_stepaddr = ~0; - m_flags |= DEBUG_FLAG_STEPPING; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// single_step_over - single step the device over -// the requested number of instructions -//------------------------------------------------- - -void device_debug::single_step_over(int numsteps) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stepsleft = numsteps; - m_stepaddr = ~0; - m_flags |= DEBUG_FLAG_STEPPING_OVER; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// single_step_out - single step the device -// out of the current function -//------------------------------------------------- - -void device_debug::single_step_out() -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stepsleft = 100; - m_stepaddr = ~0; - m_flags |= DEBUG_FLAG_STEPPING_OUT; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go - execute the device until it hits the given -// address -//------------------------------------------------- - -void device_debug::go(offs_t targetpc) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stopaddr = targetpc; - m_flags |= DEBUG_FLAG_STOP_PC; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go_vblank - execute until the next VBLANK -//------------------------------------------------- - -void device_debug::go_vblank() -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - global->vblank_occurred = false; - m_flags |= DEBUG_FLAG_STOP_VBLANK; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go_interrupt - execute until the specified -// interrupt fires on the device -//------------------------------------------------- - -void device_debug::go_interrupt(int irqline) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stopirq = irqline; - m_flags |= DEBUG_FLAG_STOP_INTERRUPT; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go_exception - execute until the specified -// exception fires on the visible CPU -//------------------------------------------------- - -void device_debug::go_exception(int exception) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stopexception = exception; - m_flags |= DEBUG_FLAG_STOP_EXCEPTION; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go_milliseconds - execute until the specified -// delay elapses -//------------------------------------------------- - -void device_debug::go_milliseconds(UINT64 milliseconds) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - m_stoptime = m_device.machine().time() + attotime::from_msec(milliseconds); - m_flags |= DEBUG_FLAG_STOP_TIME; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// go_next_device - execute until we hit the next -// device -//------------------------------------------------- - -void device_debug::go_next_device() -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - - assert(m_exec != NULL); - - global->m_stop_when_not_device = &m_device; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -//------------------------------------------------- -// halt_on_next_instruction - halt in the -// debugger on the next instruction -//------------------------------------------------- - -void device_debug::halt_on_next_instruction(const char *fmt, ...) -{ - debugcpu_private *global = m_device.machine().debugcpu_data; - va_list arg; - - assert(m_exec != NULL); - - // if something is pending on this CPU already, ignore this request - if (&m_device == global->breakcpu) - return; - - // output the message to the console - va_start(arg, fmt); - debug_console_vprintf(m_device.machine(), fmt, arg); - va_end(arg); - - // if we are live, stop now, otherwise note that we want to break there - if (&m_device == global->livecpu) - { - global->execution_state = EXECUTION_STATE_STOPPED; - if (global->livecpu != NULL) - global->livecpu->debug()->compute_debug_flags(); - } - else - global->breakcpu = &m_device; -} - - -//------------------------------------------------- -// breakpoint_set - set a new breakpoint, -// returning its index -//------------------------------------------------- - -int device_debug::breakpoint_set(offs_t address, const char *condition, const char *action) -{ - // allocate a new one - breakpoint *bp = auto_alloc(m_device.machine(), breakpoint(this, m_symtable, m_device.machine().debugcpu_data->bpindex++, address, condition, action)); - - // hook it into our list - bp->m_next = m_bplist; - m_bplist = bp; - - // update the flags and return the index - breakpoint_update_flags(); - return bp->m_index; -} - - -//------------------------------------------------- -// breakpoint_clear - clear a breakpoint by index, -// returning true if we found it -//------------------------------------------------- - -bool device_debug::breakpoint_clear(int index) -{ - // scan the list to see if we own this breakpoint - for (breakpoint **bp = &m_bplist; *bp != NULL; bp = &(*bp)->m_next) - if ((*bp)->m_index == index) - { - breakpoint *deleteme = *bp; - *bp = deleteme->m_next; - auto_free(m_device.machine(), deleteme); - breakpoint_update_flags(); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// breakpoint_clear_all - clear all breakpoints -//------------------------------------------------- - -void device_debug::breakpoint_clear_all() -{ - // clear the head until we run out - while (m_bplist != NULL) - breakpoint_clear(m_bplist->index()); -} - - -//------------------------------------------------- -// breakpoint_enable - enable/disable a breakpoint -// by index, returning true if we found it -//------------------------------------------------- - -bool device_debug::breakpoint_enable(int index, bool enable) -{ - // scan the list to see if we own this breakpoint - for (breakpoint *bp = m_bplist; bp != NULL; bp = bp->next()) - if (bp->m_index == index) - { - bp->m_enabled = enable; - breakpoint_update_flags(); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// breakpoint_enable_all - enable/disable all -// breakpoints -//------------------------------------------------- - -void device_debug::breakpoint_enable_all(bool enable) -{ - // apply the enable to all breakpoints we own - for (breakpoint *bp = m_bplist; bp != NULL; bp = bp->next()) - breakpoint_enable(bp->index(), enable); -} - - -//------------------------------------------------- -// watchpoint_set - set a new watchpoint, -// returning its index -//------------------------------------------------- - -int device_debug::watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action) -{ - assert(space.spacenum() < ARRAY_LENGTH(m_wplist)); - - // allocate a new one - watchpoint *wp = auto_alloc(m_device.machine(), watchpoint(this, m_symtable, m_device.machine().debugcpu_data->wpindex++, space, type, address, length, condition, action)); - - // hook it into our list - wp->m_next = m_wplist[space.spacenum()]; - m_wplist[space.spacenum()] = wp; - - // update the flags and return the index - watchpoint_update_flags(wp->m_space); - return wp->m_index; -} - - -//------------------------------------------------- -// watchpoint_clear - clear a watchpoint by index, -// returning true if we found it -//------------------------------------------------- - -bool device_debug::watchpoint_clear(int index) -{ - // scan the list to see if we own this breakpoint - for (address_spacenum spacenum = AS_0; spacenum < ARRAY_LENGTH(m_wplist); spacenum++) - for (watchpoint **wp = &m_wplist[spacenum]; *wp != NULL; wp = &(*wp)->m_next) - if ((*wp)->m_index == index) - { - watchpoint *deleteme = *wp; - address_space &space = deleteme->m_space; - *wp = deleteme->m_next; - auto_free(m_device.machine(), deleteme); - watchpoint_update_flags(space); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// watchpoint_clear_all - clear all watchpoints -//------------------------------------------------- - -void device_debug::watchpoint_clear_all() -{ - // clear the head until we run out - for (address_spacenum spacenum = AS_0; spacenum < ARRAY_LENGTH(m_wplist); spacenum++) - while (m_wplist[spacenum] != NULL) - watchpoint_clear(m_wplist[spacenum]->index()); -} - - -//------------------------------------------------- -// watchpoint_enable - enable/disable a watchpoint -// by index, returning true if we found it -//------------------------------------------------- - -bool device_debug::watchpoint_enable(int index, bool enable) -{ - // scan the list to see if we own this watchpoint - for (address_spacenum spacenum = AS_0; spacenum < ARRAY_LENGTH(m_wplist); spacenum++) - for (watchpoint *wp = m_wplist[spacenum]; wp != NULL; wp = wp->next()) - if (wp->m_index == index) - { - wp->m_enabled = enable; - watchpoint_update_flags(wp->m_space); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// watchpoint_enable_all - enable/disable all -// watchpoints -//------------------------------------------------- - -void device_debug::watchpoint_enable_all(bool enable) -{ - // apply the enable to all watchpoints we own - for (address_spacenum spacenum = AS_0; spacenum < ARRAY_LENGTH(m_wplist); spacenum++) - for (watchpoint *wp = m_wplist[spacenum]; wp != NULL; wp = wp->next()) - watchpoint_enable(wp->index(), enable); -} - - -//------------------------------------------------- -// registerpoint_set - set a new registerpoint, -// returning its index -//------------------------------------------------- - -int device_debug::registerpoint_set(const char *condition, const char *action) -{ - // allocate a new one - registerpoint *rp = auto_alloc(m_device.machine(), registerpoint(m_symtable, m_device.machine().debugcpu_data->rpindex++, condition, action)); - - // hook it into our list - rp->m_next = m_rplist; - m_rplist = rp; - - // update the flags and return the index - breakpoint_update_flags(); - return rp->m_index; -} - - -//------------------------------------------------- -// registerpoint_clear - clear a registerpoint by index, -// returning true if we found it -//------------------------------------------------- - -bool device_debug::registerpoint_clear(int index) -{ - // scan the list to see if we own this registerpoint - for (registerpoint **rp = &m_rplist; *rp != NULL; rp = &(*rp)->m_next) - if ((*rp)->m_index == index) - { - registerpoint *deleteme = *rp; - *rp = deleteme->m_next; - auto_free(m_device.machine(), deleteme); - breakpoint_update_flags(); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// registerpoint_clear_all - clear all registerpoints -//------------------------------------------------- - -void device_debug::registerpoint_clear_all() -{ - // clear the head until we run out - while (m_rplist != NULL) - registerpoint_clear(m_rplist->index()); -} - - -//------------------------------------------------- -// registerpoint_enable - enable/disable a registerpoint -// by index, returning true if we found it -//------------------------------------------------- - -bool device_debug::registerpoint_enable(int index, bool enable) -{ - // scan the list to see if we own this conditionpoint - for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->next()) - if (rp->m_index == index) - { - rp->m_enabled = enable; - breakpoint_update_flags(); - return true; - } - - // we don't own it, return false - return false; -} - - -//------------------------------------------------- -// registerpoint_enable_all - enable/disable all -// registerpoints -//------------------------------------------------- - -void device_debug::registerpoint_enable_all(bool enable) -{ - // apply the enable to all registerpoints we own - for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->next()) - registerpoint_enable(rp->index(), enable); -} - - -//------------------------------------------------- -// hotspot_track - enable/disable tracking of -// hotspots -//------------------------------------------------- - -void device_debug::hotspot_track(int numspots, int threshhold) -{ - // if we already have tracking enabled, kill it - m_hotspots.clear(); - - // only start tracking if we have a non-zero count - if (numspots > 0) - { - // allocate memory for hotspots - m_hotspots.resize(numspots); - memset(&m_hotspots[0], 0xff, numspots*sizeof(m_hotspots[0])); - - // fill in the info - m_hotspot_threshhold = threshhold; - } - - // update the watchpoint flags to include us - if (m_memory != NULL && m_memory->has_space(AS_PROGRAM)) - watchpoint_update_flags(m_memory->space(AS_PROGRAM)); -} - - -//------------------------------------------------- -// history_pc - return an entry from the PC -// history -//------------------------------------------------- - -offs_t device_debug::history_pc(int index) const -{ - if (index > 0) - index = 0; - if (index <= -HISTORY_SIZE) - index = -HISTORY_SIZE + 1; - return m_pc_history[(m_pc_history_index + ARRAY_LENGTH(m_pc_history) - 1 + index) % ARRAY_LENGTH(m_pc_history)]; -} - - -//------------------------------------------------- -// track_pc_visited - returns a boolean stating -// if this PC has been visited or not. CRC32 is -// done in this function on currently active CPU. -// TODO: Take a CPU context as input -//------------------------------------------------- - -bool device_debug::track_pc_visited(const offs_t& pc) const -{ - if (m_track_pc_set.empty()) - return false; - const UINT32 crc = compute_opcode_crc32(pc); - return m_track_pc_set.find(dasm_pc_tag(pc, crc)) != m_track_pc_set.end(); -} - - -//------------------------------------------------- -// set_track_pc_visited - set this pc as visited. -// TODO: Take a CPU context as input -//------------------------------------------------- - -void device_debug::set_track_pc_visited(const offs_t& pc) -{ - const UINT32 crc = compute_opcode_crc32(pc); - m_track_pc_set.insert(dasm_pc_tag(pc, crc)); -} - - -//------------------------------------------------- -// 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; - std::set<dasm_memory_access>::iterator const mem_access = m_track_mem_set.find(dasm_memory_access(space, address, data, 0)); - if (mem_access == m_track_mem_set.end()) return missing; - return mem_access->m_pc; -} - - -//------------------------------------------------- -// comment_add - adds a comment to the list at -// the given address -//------------------------------------------------- - -void device_debug::comment_add(offs_t addr, const char *comment, rgb_t color) -{ - // create a new item for the list - UINT32 const crc = compute_opcode_crc32(addr); - dasm_comment const newComment = dasm_comment(addr, crc, comment, color); - std::pair<std::set<dasm_comment>::iterator, bool> const inserted = m_comment_set.insert(newComment); - if (!inserted.second) - { - // Insert returns false if comment exists - m_comment_set.erase(inserted.first); - m_comment_set.insert(newComment); - } - - // force an update - m_comment_change++; -} - - -//------------------------------------------------- -// comment_remove - removes a comment at the -// given address with a matching CRC -//------------------------------------------------- - -bool device_debug::comment_remove(offs_t addr) -{ - const UINT32 crc = compute_opcode_crc32(addr); - size_t const removed = m_comment_set.erase(dasm_comment(addr, crc, "", 0xffffffff)); - if (removed != 0U) m_comment_change++; - return removed != 0U; -} - - -//------------------------------------------------- -// comment_text - return the text of a comment -//------------------------------------------------- - -const char *device_debug::comment_text(offs_t addr) const -{ - const UINT32 crc = compute_opcode_crc32(addr); - std::set<dasm_comment>::iterator comment = m_comment_set.find(dasm_comment(addr, crc, "", 0)); - if (comment == m_comment_set.end()) return NULL; - return comment->m_text.c_str(); -} - - -//------------------------------------------------- -// comment_export - export the comments to the -// given XML data node -//------------------------------------------------- - -bool device_debug::comment_export(xml_data_node &curnode) -{ - // iterate through the comments - std::string crc_buf; - for (std::set<dasm_comment>::iterator item = m_comment_set.begin(); item != m_comment_set.end(); ++item) - { - xml_data_node *datanode = xml_add_child(&curnode, "comment", xml_normalize_string(item->m_text.c_str())); - if (datanode == NULL) - return false; - xml_set_attribute_int(datanode, "address", item->m_address); - xml_set_attribute_int(datanode, "color", item->m_color); - strprintf(crc_buf,"%08X", item->m_crc); - xml_set_attribute(datanode, "crc", crc_buf.c_str()); - } - return true; -} - - -//------------------------------------------------- -// comment_import - import the comments from the -// given XML data node -//------------------------------------------------- - -bool device_debug::comment_import(xml_data_node &cpunode) -{ - // iterate through nodes - for (xml_data_node *datanode = xml_get_sibling(cpunode.child, "comment"); datanode; datanode = xml_get_sibling(datanode->next, "comment")) - { - // extract attributes - offs_t address = xml_get_attribute_int(datanode, "address", 0); - rgb_t color = xml_get_attribute_int(datanode, "color", 0); - - UINT32 crc; - sscanf(xml_get_attribute_string(datanode, "crc", 0), "%08X", &crc); - - // add the new comment - m_comment_set.insert(dasm_comment(address, crc, datanode->value, color)); - } - return true; -} - - -//------------------------------------------------- -// compute_opcode_crc32 - determine the CRC of -// the opcode bytes at the given address -//------------------------------------------------- - -UINT32 device_debug::compute_opcode_crc32(offs_t pc) const -{ - // Basically the same thing as dasm_wrapped, but with some tiny savings - assert(m_memory != NULL); - - // determine the adjusted PC - address_space &decrypted_space = m_memory->has_space(AS_DECRYPTED_OPCODES) ? m_memory->space(AS_DECRYPTED_OPCODES) : m_memory->space(AS_PROGRAM); - address_space &space = m_memory->space(AS_PROGRAM); - offs_t pcbyte = space.address_to_byte(pc) & space.bytemask(); - - // fetch the bytes up to the maximum - UINT8 opbuf[64], argbuf[64]; - int maxbytes = max_opcode_bytes(); - for (int numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = debug_read_opcode(decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1); - } - - // disassemble to our buffer - char diasmbuf[200]; - memset(diasmbuf, 0x00, 200); - UINT32 numbytes = disassemble(diasmbuf, pc, opbuf, argbuf) & DASMFLAG_LENGTHMASK; - - // return a CRC of the exact count of opcode bytes - return core_crc32(0, opbuf, numbytes); -} - - -//------------------------------------------------- -// trace - trace execution of a given device -//------------------------------------------------- - -void device_debug::trace(FILE *file, bool trace_over, const char *action) -{ - // delete any existing tracers - auto_free(m_device.machine(), m_trace); - m_trace = NULL; - - // if we have a new file, make a new tracer - if (file != NULL) - m_trace = auto_alloc(m_device.machine(), tracer(*this, *file, trace_over, action)); -} - - -//------------------------------------------------- -// trace_printf - output data into the given -// device's tracefile, if tracing -//------------------------------------------------- - -void device_debug::trace_printf(const char *fmt, ...) -{ - if (m_trace != NULL) - { - va_list va; - va_start(va, fmt); - m_trace->vprintf(fmt, va); - va_end(va); - } -} - - -//------------------------------------------------- -// compute_debug_flags - compute the global -// debug flags for optimal efficiency -//------------------------------------------------- - -void device_debug::compute_debug_flags() -{ - running_machine &machine = m_device.machine(); - debugcpu_private *global = machine.debugcpu_data; - - // clear out global flags by default, keep DEBUG_FLAG_OSD_ENABLED - machine.debug_flags &= DEBUG_FLAG_OSD_ENABLED; - machine.debug_flags |= DEBUG_FLAG_ENABLED; - - // if we are ignoring this CPU, or if events are pending, we're done - if ((m_flags & DEBUG_FLAG_OBSERVING) == 0 || machine.scheduled_event_pending() || machine.save_or_load_pending()) - return; - - // if we're stopped, keep calling the hook - if (global->execution_state == EXECUTION_STATE_STOPPED) - machine.debug_flags |= DEBUG_FLAG_CALL_HOOK; - - // if we're tracking history, or we're hooked, or stepping, or stopping at a breakpoint - // make sure we call the hook - if ((m_flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_HOOKED | DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) - machine.debug_flags |= DEBUG_FLAG_CALL_HOOK; - - // also call if we are tracing - if (m_trace != NULL) - machine.debug_flags |= DEBUG_FLAG_CALL_HOOK; - - // if we are stopping at a particular time and that time is within the current timeslice, we need to be called - if ((m_flags & DEBUG_FLAG_STOP_TIME) && m_endexectime <= m_stoptime) - machine.debug_flags |= DEBUG_FLAG_CALL_HOOK; -} - - -//------------------------------------------------- -// prepare_for_step_overout - prepare things for -// stepping over an instruction -//------------------------------------------------- - -void device_debug::prepare_for_step_overout(offs_t pc) -{ - // disassemble the current instruction and get the flags - std::string dasmbuffer; - offs_t dasmresult = dasm_wrapped(dasmbuffer, pc); - - // if flags are supported and it's a call-style opcode, set a temp breakpoint after that instruction - if ((dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OVER) != 0) - { - int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT; - pc += dasmresult & DASMFLAG_LENGTHMASK; - - // if we need to skip additional instructions, advance as requested - while (extraskip-- > 0) - pc += dasm_wrapped(dasmbuffer, pc) & DASMFLAG_LENGTHMASK; - m_stepaddr = pc; - } - - // if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number - if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0) - { - if ((dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OUT) == 0) - m_stepsleft = 100; - else - m_stepsleft = 1; - } -} - - -//------------------------------------------------- -// breakpoint_update_flags - update the device's -// breakpoint flags -//------------------------------------------------- - -void device_debug::breakpoint_update_flags() -{ - // see if there are any enabled breakpoints - m_flags &= ~DEBUG_FLAG_LIVE_BP; - for (breakpoint *bp = m_bplist; bp != NULL; bp = bp->m_next) - if (bp->m_enabled) - { - m_flags |= DEBUG_FLAG_LIVE_BP; - break; - } - - if ( ! ( m_flags & DEBUG_FLAG_LIVE_BP ) ) - { - // see if there are any enabled registerpoints - for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->m_next) - { - if (rp->m_enabled) - { - m_flags |= DEBUG_FLAG_LIVE_BP; - } - } - } - - // push the flags out globally - debugcpu_private *global = m_device.machine().debugcpu_data; - if (global->livecpu != NULL) - global->livecpu->debug()->compute_debug_flags(); -} - - -//------------------------------------------------- -// breakpoint_check - check the breakpoints for -// a given device -//------------------------------------------------- - -void device_debug::breakpoint_check(offs_t pc) -{ - // see if we match - for (breakpoint *bp = m_bplist; bp != NULL; bp = bp->m_next) - if (bp->hit(pc)) - { - // halt in the debugger by default - debugcpu_private *global = m_device.machine().debugcpu_data; - global->execution_state = EXECUTION_STATE_STOPPED; - - // if we hit, evaluate the action - if (!bp->m_action.empty()) - debug_console_execute_command(m_device.machine(), bp->m_action.c_str(), 0); - - // print a notification, unless the action made us go again - if (global->execution_state == EXECUTION_STATE_STOPPED) - debug_console_printf(m_device.machine(), "Stopped at breakpoint %X\n", bp->m_index); - break; - } - - // see if we have any matching registerpoints - for (registerpoint *rp = m_rplist; rp != NULL; rp = rp->m_next) - { - if (rp->hit()) - { - // halt in the debugger by default - debugcpu_private *global = m_device.machine().debugcpu_data; - global->execution_state = EXECUTION_STATE_STOPPED; - - // if we hit, evaluate the action - if (!rp->m_action.empty()) - { - debug_console_execute_command(m_device.machine(), rp->m_action.c_str(), 0); - } - - // print a notification, unless the action made us go again - if (global->execution_state == EXECUTION_STATE_STOPPED) - { - debug_console_printf(m_device.machine(), "Stopped at registerpoint %X\n", rp->m_index); - } - break; - } - } -} - - -//------------------------------------------------- -// watchpoint_update_flags - update the device's -// watchpoint flags -//------------------------------------------------- - -void device_debug::watchpoint_update_flags(address_space &space) -{ - // if hotspots are enabled, turn on all reads - bool enableread = false; - if (!m_hotspots.empty()) - enableread = true; - - // see if there are any enabled breakpoints - bool enablewrite = false; - for (watchpoint *wp = m_wplist[space.spacenum()]; wp != NULL; wp = wp->m_next) - if (wp->m_enabled) - { - if (wp->m_type & WATCHPOINT_READ) - enableread = true; - if (wp->m_type & WATCHPOINT_WRITE) - enablewrite = true; - } - - // push the flags out globally - space.enable_read_watchpoints(enableread); - space.enable_write_watchpoints(enablewrite); -} - - -//------------------------------------------------- -// watchpoint_check - check the watchpoints -// for a given CPU and address space -//------------------------------------------------- - -void device_debug::watchpoint_check(address_space &space, int type, offs_t address, UINT64 value_to_write, UINT64 mem_mask) -{ - debugcpu_private *global = space.machine().debugcpu_data; - - // if we're within debugger code, don't stop - if (global->within_instruction_hook || global->debugger_access) - return; - global->within_instruction_hook = true; - - // adjust address, size & value_to_write based on mem_mask. - offs_t size = 0; - if (mem_mask != 0) - { - int bus_size = space.data_width() / 8; - int address_offset = 0; - - while (address_offset < bus_size && (mem_mask & 0xff) == 0) - { - address_offset++; - value_to_write >>= 8; - mem_mask >>= 8; - } - - while (mem_mask != 0) - { - size++; - mem_mask >>= 8; - } - - // (1<<(size*8))-1 won't work when size is 8; let's just use a lut - static const UINT64 masks[] = {0, - 0xff, - 0xffff, - 0xffffff, - 0xffffffff, - U64(0xffffffffff), - U64(0xffffffffffff), - U64(0xffffffffffffff), - U64(0xffffffffffffffff)}; - value_to_write &= masks[size]; - - if (space.endianness() == ENDIANNESS_LITTLE) - address += address_offset; - else - address += bus_size - size - address_offset; - } - - // if we are a write watchpoint, stash the value that will be written - global->wpaddr = address; - if (type & WATCHPOINT_WRITE) - global->wpdata = value_to_write; - - // see if we match - for (watchpoint *wp = m_wplist[space.spacenum()]; wp != NULL; wp = wp->m_next) - if (wp->hit(type, address, size)) - { - // halt in the debugger by default - global->execution_state = EXECUTION_STATE_STOPPED; - - // if we hit, evaluate the action - if (!wp->m_action.empty()) - debug_console_execute_command(space.machine(), wp->m_action.c_str(), 0); - - // print a notification, unless the action made us go again - if (global->execution_state == EXECUTION_STATE_STOPPED) - { - static const char *const sizes[] = - { - "0bytes", "byte", "word", "3bytes", "dword", "5bytes", "6bytes", "7bytes", "qword" - }; - offs_t pc = (space.device().debug()->m_state != NULL) ? space.device().debug()->m_state->pc() : 0; - std::string buffer; - - if (type & WATCHPOINT_WRITE) - { - strprintf(buffer, "Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->m_index, sizes[size], space.byte_to_address(address), pc); - if (value_to_write >> 32) - strcatprintf(buffer, " (data=%X%08X)", (UINT32)(value_to_write >> 32), (UINT32)value_to_write); - else - strcatprintf(buffer, " (data=%X)", (UINT32)value_to_write); - } - else - strprintf(buffer,"Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->m_index, sizes[size], space.byte_to_address(address), pc); - debug_console_printf(space.machine(), "%s\n", buffer.c_str()); - space.device().debug()->compute_debug_flags(); - } - break; - } - - global->within_instruction_hook = false; -} - - -//------------------------------------------------- -// hotspot_check - check for hotspots on a -// memory read access -//------------------------------------------------- - -void device_debug::hotspot_check(address_space &space, offs_t address) -{ - offs_t curpc = pc(); - - // see if we have a match in our list - unsigned int hotindex; - for (hotindex = 0; hotindex < m_hotspots.size(); hotindex++) - if (m_hotspots[hotindex].m_access == address && m_hotspots[hotindex].m_pc == curpc && m_hotspots[hotindex].m_space == &space) - break; - - // if we didn't find any, make a new entry - if (hotindex == m_hotspots.size()) - { - // if the bottom of the list is over the threshhold, print it - hotspot_entry &spot = m_hotspots[m_hotspots.size() - 1]; - if (spot.m_count > m_hotspot_threshhold) - debug_console_printf(space.machine(), "Hotspot @ %s %08X (PC=%08X) hit %d times (fell off bottom)\n", space.name(), spot.m_access, spot.m_pc, spot.m_count); - - // move everything else down and insert this one at the top - memmove(&m_hotspots[1], &m_hotspots[0], sizeof(m_hotspots[0]) * (m_hotspots.size() - 1)); - m_hotspots[0].m_access = address; - m_hotspots[0].m_pc = curpc; - m_hotspots[0].m_space = &space; - m_hotspots[0].m_count = 1; - } - - // if we did find one, increase the count and move it to the top - else - { - m_hotspots[hotindex].m_count++; - if (hotindex != 0) - { - hotspot_entry temp = m_hotspots[hotindex]; - memmove(&m_hotspots[1], &m_hotspots[0], sizeof(m_hotspots[0]) * hotindex); - m_hotspots[0] = temp; - } - } -} - - -//------------------------------------------------- -// dasm_wrapped - wraps calls to the disassembler -// by fetching the opcode bytes to a temporary -// buffer and then disassembling them -//------------------------------------------------- - -UINT32 device_debug::dasm_wrapped(std::string &buffer, offs_t pc) -{ - assert(m_memory != NULL && m_disasm != NULL); - - // determine the adjusted PC - address_space &decrypted_space = m_memory->has_space(AS_DECRYPTED_OPCODES) ? m_memory->space(AS_DECRYPTED_OPCODES) : m_memory->space(AS_PROGRAM); - address_space &space = m_memory->space(AS_PROGRAM); - offs_t pcbyte = space.address_to_byte(pc) & space.bytemask(); - - // fetch the bytes up to the maximum - UINT8 opbuf[64], argbuf[64]; - int maxbytes = max_opcode_bytes(); - for (int numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = debug_read_opcode(decrypted_space, pcbyte + numbytes, 1); - argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1); - } - - // disassemble to our buffer - char diasmbuf[200]; - memset(diasmbuf, 0x00, 200); - UINT32 result = disassemble(diasmbuf, pc, opbuf, argbuf); - buffer.assign(diasmbuf); - return result; -} - - -//------------------------------------------------- -// get_current_pc - getter callback for a device's -// current instruction pointer -//------------------------------------------------- - -UINT64 device_debug::get_current_pc(symbol_table &table, void *ref) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - return device->debug()->pc(); -} - - -//------------------------------------------------- -// get_cycles - getter callback for the -// 'cycles' symbol -//------------------------------------------------- - -UINT64 device_debug::get_cycles(symbol_table &table, void *ref) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - return device->debug()->m_exec->cycles_remaining(); -} - - -//------------------------------------------------- -// get_totalcycles - getter callback for the -// 'totalcycles' symbol -//------------------------------------------------- - -UINT64 device_debug::get_totalcycles(symbol_table &table, void *ref) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - return device->debug()->m_total_cycles; -} - - -//------------------------------------------------- -// get_lastinstructioncycles - getter callback for the -// 'lastinstructioncycles' symbol -//------------------------------------------------- - -UINT64 device_debug::get_lastinstructioncycles(symbol_table &table, void *ref) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - device_debug *debug = device->debug(); - return debug->m_total_cycles - debug->m_last_total_cycles; -} - - -//------------------------------------------------- -// get_logunmap - getter callback for the logumap -// symbols -//------------------------------------------------- - -UINT64 device_debug::get_logunmap(symbol_table &table, void *ref) -{ - address_space &space = *reinterpret_cast<address_space *>(table.globalref()); - return space.log_unmap(); -} - - -//------------------------------------------------- -// set_logunmap - setter callback for the logumap -// symbols -//------------------------------------------------- - -void device_debug::set_logunmap(symbol_table &table, void *ref, UINT64 value) -{ - address_space &space = *reinterpret_cast<address_space *>(table.globalref()); - space.set_log_unmap(value ? true : false); -} - - -//------------------------------------------------- -// get_state - getter callback for a device's -// state symbols -//------------------------------------------------- - -UINT64 device_debug::get_state(symbol_table &table, void *ref) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - return device->debug()->m_state->state_int(reinterpret_cast<FPTR>(ref)); -} - - -//------------------------------------------------- -// set_state - setter callback for a device's -// state symbols -//------------------------------------------------- - -void device_debug::set_state(symbol_table &table, void *ref, UINT64 value) -{ - device_t *device = reinterpret_cast<device_t *>(table.globalref()); - device->debug()->m_state->set_state_int(reinterpret_cast<FPTR>(ref), value); -} - - - -//************************************************************************** -// 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_next(NULL), - m_index(index), - m_enabled(true), - m_address(address), - m_condition(&symbols, (condition != NULL) ? condition : "1"), - m_action((action != NULL) ? 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, - int type, - offs_t address, - offs_t length, - const char *condition, - const char *action) - : m_debugInterface(debugInterface), - m_next(NULL), - m_space(space), - m_index(index), - m_enabled(true), - m_type(type), - m_address(space.address_to_byte(address) & space.bytemask()), - m_length(space.address_to_byte(length)), - m_condition(&symbols, (condition != NULL) ? condition : "1"), - m_action((action != NULL) ? action : "") -{ -} - - -//------------------------------------------------- -// hit - detect a hit -//------------------------------------------------- - -bool device_debug::watchpoint::hit(int type, offs_t address, int size) -{ - // don't hit if disabled - if (!m_enabled) - return false; - - // must match the type - if ((m_type & type) == 0) - return false; - - // must match our address - if (address + size <= m_address || address >= m_address + m_length) - 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 REGISTERPOINT -//************************************************************************** - -//------------------------------------------------- -// registerpoint - constructor -//------------------------------------------------- - -device_debug::registerpoint::registerpoint(symbol_table &symbols, int index, const char *condition, const char *action) - : m_next(NULL), - m_index(index), - m_enabled(true), - m_condition(&symbols, (condition != NULL) ? condition : "1"), - m_action((action != NULL) ? 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 -//************************************************************************** - -//------------------------------------------------- -// tracer - constructor -//------------------------------------------------- - -device_debug::tracer::tracer(device_debug &debug, FILE &file, bool trace_over, const char *action) - : m_debug(debug), - m_file(file), - m_action((action != NULL) ? action : ""), - m_loops(0), - m_nextdex(0), - m_trace_over(trace_over), - m_trace_over_target(~0) -{ - memset(m_history, 0, sizeof(m_history)); -} - - -//------------------------------------------------- -// ~tracer - destructor -//------------------------------------------------- - -device_debug::tracer::~tracer() -{ - // make sure we close the file if we can - fclose(&m_file); -} - - -//------------------------------------------------- -// update - log to the tracefile the data for a -// given instruction -//------------------------------------------------- - -void device_debug::tracer::update(offs_t pc) -{ - // are we in trace over mode and in a subroutine? - if (m_trace_over && m_trace_over_target != ~0) - { - if (m_trace_over_target != pc) - return; - m_trace_over_target = ~0; - } - - // check for a loop condition - int count = 0; - for (int index = 0; index < ARRAY_LENGTH(m_history); index++) - if (m_history[index] == pc) - count++; - - // if more than 1 hit, just up the loop count and get out - if (count > 1) - { - m_loops++; - return; - } - - // if we just finished looping, indicate as much - if (m_loops != 0) - fprintf(&m_file, "\n (loops for %d instructions)\n\n", m_loops); - m_loops = 0; - - // execute any trace actions first - if (!m_action.empty()) - debug_console_execute_command(m_debug.m_device.machine(), m_action.c_str(), 0); - - // print the address - std::string buffer; - int logaddrchars = m_debug.logaddrchars(); - strprintf(buffer,"%0*X: ", logaddrchars, pc); - - // print the disassembly - std::string dasm; - offs_t dasmresult = m_debug.dasm_wrapped(dasm, pc); - buffer.append(dasm); - - // output the result - fprintf(&m_file, "%s\n", buffer.c_str()); - - // do we need to step the trace over this instruction? - if (m_trace_over && (dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OVER) != 0) - { - int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT; - offs_t trace_over_target = pc + (dasmresult & DASMFLAG_LENGTHMASK); - - // if we need to skip additional instructions, advance as requested - while (extraskip-- > 0) - trace_over_target += m_debug.dasm_wrapped(dasm, trace_over_target) & DASMFLAG_LENGTHMASK; - - m_trace_over_target = trace_over_target; - } - - // log this PC - m_nextdex = (m_nextdex + 1) % TRACE_LOOPS; - m_history[m_nextdex] = pc; -} - - -//------------------------------------------------- -// vprintf - generic print to the trace file -//------------------------------------------------- - -void device_debug::tracer::vprintf(const char *format, va_list va) -{ - // pass through to the file - vfprintf(&m_file, format, va); -} - - -//------------------------------------------------- -// flush - flush any pending changes to the trace -// file -//------------------------------------------------- - -void device_debug::tracer::flush() -{ - fflush(&m_file); -} - - -//------------------------------------------------- -// dasm_pc_tag - constructor -//------------------------------------------------- - -device_debug::dasm_pc_tag::dasm_pc_tag(const offs_t& address, const UINT32& crc) - : m_address(address), - 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) -{ -} - -//------------------------------------------------- -// dasm_comment - constructor -//------------------------------------------------- - -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) -{ -} |
