summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugcpu.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/emu/debug/debugcpu.c
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/emu/debug/debugcpu.c')
-rw-r--r--src/emu/debug/debugcpu.c3575
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)
-{
-}