diff --git a/src/emu/cheat.c b/src/emu/cheat.c index 630138d9e1c..d995d8e261f 100644 --- a/src/emu/cheat.c +++ b/src/emu/cheat.c @@ -205,10 +205,10 @@ static void script_entry_free(script_entry *entry); static astring *quote_astring_expression(astring *string, int isattribute); static int validate_format(const char *filename, int line, const script_entry *entry); -static UINT64 cheat_variable_get(void *ref); -static void cheat_variable_set(void *ref, UINT64 value); -static UINT64 execute_frombcd(void *ref, UINT32 params, const UINT64 *param); -static UINT64 execute_tobcd(void *ref, UINT32 params, const UINT64 *param); +static UINT64 cheat_variable_get(void *globalref, void *ref); +static void cheat_variable_set(void *globalref, void *ref, UINT64 value); +static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param); +static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param); @@ -951,7 +951,7 @@ static cheat_entry *cheat_entry_load(running_machine *machine, const char *filen cheat->description = astring_dupc(description); /* create the symbol table */ - cheat->symbols = symtable_alloc(NULL); + cheat->symbols = symtable_alloc(NULL, machine); symtable_add_register(cheat->symbols, "frame", &cheatinfo->framecount, cheat_variable_get, NULL); symtable_add_register(cheat->symbols, "argindex", &cheat->argindex, cheat_variable_get, NULL); for (curtemp = 0; curtemp < tempcount; curtemp++) @@ -1653,7 +1653,7 @@ static int validate_format(const char *filename, int line, const script_entry *e cheat variable -------------------------------------------------*/ -static UINT64 cheat_variable_get(void *ref) +static UINT64 cheat_variable_get(void *globalref, void *ref) { return *(UINT64 *)ref; } @@ -1664,7 +1664,7 @@ static UINT64 cheat_variable_get(void *ref) cheat variable -------------------------------------------------*/ -static void cheat_variable_set(void *ref, UINT64 value) +static void cheat_variable_set(void *globalref, void *ref, UINT64 value) { *(UINT64 *)ref = value; } @@ -1674,7 +1674,7 @@ static void cheat_variable_set(void *ref, UINT64 value) execute_frombcd - convert a value from BCD -------------------------------------------------*/ -static UINT64 execute_frombcd(void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_frombcd(void *globalref, void *ref, UINT32 params, const UINT64 *param) { UINT64 value = param[0]; UINT64 multiplier = 1; @@ -1694,7 +1694,7 @@ static UINT64 execute_frombcd(void *ref, UINT32 params, const UINT64 *param) execute_tobcd - convert a value to BCD -------------------------------------------------*/ -static UINT64 execute_tobcd(void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_tobcd(void *globalref, void *ref, UINT32 params, const UINT64 *param) { UINT64 value = param[0]; UINT64 result = 0; diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c index f9c9d998fbc..202c05f1856 100644 --- a/src/emu/debug/debugcmd.c +++ b/src/emu/debug/debugcmd.c @@ -58,12 +58,12 @@ static global_entry global_array[MAX_GLOBALS]; static void debug_command_exit(running_machine *machine); -static UINT64 execute_min(void *ref, UINT32 params, const UINT64 *param); -static UINT64 execute_max(void *ref, UINT32 params, const UINT64 *param); -static UINT64 execute_if(void *ref, UINT32 params, const UINT64 *param); +static UINT64 execute_min(void *globalref, void *ref, UINT32 params, const UINT64 *param); +static UINT64 execute_max(void *globalref, void *ref, UINT32 params, const UINT64 *param); +static UINT64 execute_if(void *globalref, void *ref, UINT32 params, const UINT64 *param); -static UINT64 global_get(void *ref); -static void global_set(void *ref, UINT64 value); +static UINT64 global_get(void *globalref, void *ref); +static void global_set(void *globalref, void *ref, UINT64 value); static void execute_help(running_machine *machine, int ref, int params, const char **param); static void execute_print(running_machine *machine, int ref, int params, const char **param); @@ -291,7 +291,7 @@ static void debug_command_exit(running_machine *machine) execute_min - return the minimum of two values -------------------------------------------------*/ -static UINT64 execute_min(void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_min(void *globalref, void *ref, UINT32 params, const UINT64 *param) { return (param[0] < param[1]) ? param[0] : param[1]; } @@ -301,7 +301,7 @@ static UINT64 execute_min(void *ref, UINT32 params, const UINT64 *param) execute_max - return the maximum of two values -------------------------------------------------*/ -static UINT64 execute_max(void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_max(void *globalref, void *ref, UINT32 params, const UINT64 *param) { return (param[0] > param[1]) ? param[0] : param[1]; } @@ -311,7 +311,7 @@ static UINT64 execute_max(void *ref, UINT32 params, const UINT64 *param) execute_if - if (a) return b; else return c; -------------------------------------------------*/ -static UINT64 execute_if(void *ref, UINT32 params, const UINT64 *param) +static UINT64 execute_if(void *globalref, void *ref, UINT32 params, const UINT64 *param) { return param[0] ? param[1] : param[2]; } @@ -328,7 +328,7 @@ static UINT64 execute_if(void *ref, UINT32 params, const UINT64 *param) global_get - symbol table getter for globals -------------------------------------------------*/ -static UINT64 global_get(void *ref) +static UINT64 global_get(void *globalref, void *ref) { global_entry *global = ref; switch (global->size) @@ -346,7 +346,7 @@ static UINT64 global_get(void *ref) global_set - symbol table setter for globals -------------------------------------------------*/ -static void global_set(void *ref, UINT64 value) +static void global_set(void *globalref, void *ref, UINT64 value) { global_entry *global = ref; switch (global->size) @@ -694,7 +694,7 @@ static void execute_step(running_machine *machine, int ref, int params, const ch if (params > 0 && !debug_command_parameter_number(machine, param[0], &steps)) return; - debug_cpu_single_step(steps); + debug_cpu_single_step(machine, steps); } @@ -710,7 +710,7 @@ static void execute_over(running_machine *machine, int ref, int params, const ch if (params > 0 && !debug_command_parameter_number(machine, param[0], &steps)) return; - debug_cpu_single_step_over(steps); + debug_cpu_single_step_over(machine, steps); } @@ -720,7 +720,7 @@ static void execute_over(running_machine *machine, int ref, int params, const ch static void execute_out(running_machine *machine, int ref, int params, const char *param[]) { - debug_cpu_single_step_out(); + debug_cpu_single_step_out(machine); } @@ -736,7 +736,7 @@ static void execute_go(running_machine *machine, int ref, int params, const char if (params > 0 && !debug_command_parameter_number(machine, param[0], &addr)) return; - debug_cpu_go(addr); + debug_cpu_go(machine, addr); } @@ -747,7 +747,7 @@ static void execute_go(running_machine *machine, int ref, int params, const char static void execute_go_vblank(running_machine *machine, int ref, int params, const char *param[]) { - debug_cpu_go_vblank(); + debug_cpu_go_vblank(machine); } @@ -763,7 +763,7 @@ static void execute_go_interrupt(running_machine *machine, int ref, int params, if (params > 0 && !debug_command_parameter_number(machine, param[0], &irqline)) return; - debug_cpu_go_interrupt(irqline); + debug_cpu_go_interrupt(machine, irqline); } @@ -779,7 +779,7 @@ static void execute_go_time(running_machine *machine, int ref, int params, const if (params > 0 && !debug_command_parameter_number(machine, param[0], &milliseconds)) return; - debug_cpu_go_milliseconds(milliseconds); + debug_cpu_go_milliseconds(machine, milliseconds); } @@ -789,7 +789,7 @@ static void execute_go_time(running_machine *machine, int ref, int params, const static void execute_next(running_machine *machine, int ref, int params, const char *param[]) { - debug_cpu_next_cpu(); + debug_cpu_next_cpu(machine); } @@ -1728,6 +1728,7 @@ static void execute_find(running_machine *machine, int ref, int params, const ch static void execute_dasm(running_machine *machine, int ref, int params, const char *param[]) { const device_config *cpu = debug_cpu_get_visible_cpu(machine); + const address_space *space = cpu_get_address_space(cpu, ADDRESS_SPACE_PROGRAM); UINT64 offset, length, bytes = 1; const cpu_debug_data *info; int minbytes, maxbytes, byteswidth; @@ -1788,12 +1789,12 @@ static void execute_dasm(running_machine *machine, int ref, int params, const ch /* fetch the bytes up to the maximum */ for (numbytes = 0; numbytes < maxbytes; numbytes++) { - opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE); - argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE); + opbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, FALSE); + argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, TRUE); } /* disassemble the result */ - i += numbytes = cpu_dasm(machine->activecpu, disasm, offset + i, opbuf, argbuf) & DASMFLAG_LENGTHMASK; + i += numbytes = cpu_dasm(cpu, disasm, offset + i, opbuf, argbuf) & DASMFLAG_LENGTHMASK; } /* print the bytes */ @@ -1805,23 +1806,23 @@ static void execute_dasm(running_machine *machine, int ref, int params, const ch { case 1: for (j = 0; j < numbytes; j++) - outdex += sprintf(&output[outdex], "%02X ", (UINT32)debug_read_opcode(pcbyte + j, 1, FALSE)); + outdex += sprintf(&output[outdex], "%02X ", (UINT32)debug_read_opcode(space, pcbyte + j, 1, FALSE)); break; case 2: for (j = 0; j < numbytes; j += 2) - outdex += sprintf(&output[outdex], "%04X ", (UINT32)debug_read_opcode(pcbyte + j, 2, FALSE)); + outdex += sprintf(&output[outdex], "%04X ", (UINT32)debug_read_opcode(space, pcbyte + j, 2, FALSE)); break; case 4: for (j = 0; j < numbytes; j += 4) - outdex += sprintf(&output[outdex], "%08X ", (UINT32)debug_read_opcode(pcbyte + j, 4, FALSE)); + outdex += sprintf(&output[outdex], "%08X ", (UINT32)debug_read_opcode(space, pcbyte + j, 4, FALSE)); break; case 8: for (j = 0; j < numbytes; j += 8) { - UINT64 val = debug_read_opcode(pcbyte + j, 8, FALSE); + UINT64 val = debug_read_opcode(space, pcbyte + j, 8, FALSE); outdex += sprintf(&output[outdex], "%08X%08X ", (UINT32)(val >> 32), (UINT32)val); } break; @@ -1940,7 +1941,7 @@ static void execute_traceover(running_machine *machine, int ref, int params, con static void execute_traceflush(running_machine *machine, int ref, int params, const char *param[]) { - debug_cpu_flush_traces(); + debug_cpu_flush_traces(machine); } @@ -1951,6 +1952,7 @@ static void execute_traceflush(running_machine *machine, int ref, int params, co static void execute_history(running_machine *machine, int ref, int params, const char *param[]) { const device_config *cpu = debug_cpu_get_visible_cpu(machine); + const address_space *space = cpu_get_address_space(cpu, ADDRESS_SPACE_PROGRAM); UINT64 count = DEBUG_HISTORY_SIZE; const cpu_debug_data *info; int i; @@ -1982,8 +1984,8 @@ static void execute_history(running_machine *machine, int ref, int params, const pcbyte = ADDR2BYTE_MASKED(pc, info, ADDRESS_SPACE_PROGRAM); for (numbytes = 0; numbytes < maxbytes; numbytes++) { - opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE); - argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE); + opbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, FALSE); + argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, TRUE); } cpu_dasm(cpu, buffer, pc, opbuf, argbuf); @@ -2177,7 +2179,7 @@ static void execute_symlist(running_machine *machine, int ref, int params, const for (symnum = 0; symnum < count; symnum++) { const symbol_entry *entry = symtable_find(symtable, namelist[symnum]); - UINT64 value = (*entry->info.reg.getter)(entry->ref); + UINT64 value = (*entry->info.reg.getter)(symtable_get_globalref(entry->table), entry->ref); assert(entry != NULL); /* only display "register" type symbols */ diff --git a/src/emu/debug/debugcmt.c b/src/emu/debug/debugcmt.c index 0779e2efc0e..4e267c079e5 100644 --- a/src/emu/debug/debugcmt.c +++ b/src/emu/debug/debugcmt.c @@ -311,6 +311,7 @@ UINT32 debug_comment_all_change_count(running_machine *machine) UINT32 debug_comment_get_opcode_crc32(const device_config *device, offs_t address) { const cpu_debug_data *info = cpu_get_debug_data(device); + const address_space *space = cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM); int i; UINT32 crc; UINT8 opbuf[64], argbuf[64]; @@ -325,8 +326,8 @@ UINT32 debug_comment_get_opcode_crc32(const device_config *device, offs_t addres // fetch the bytes up to the maximum for (i = 0; i < maxbytes; i++) { - opbuf[i] = debug_read_opcode(address + i, 1, FALSE); - argbuf[i] = debug_read_opcode(address + i, 1, TRUE); + opbuf[i] = debug_read_opcode(space, address + i, 1, FALSE); + argbuf[i] = debug_read_opcode(space, address + i, 1, TRUE); } numbytes = cpu_dasm(device, buff, address & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK; diff --git a/src/emu/debug/debugcpu.c b/src/emu/debug/debugcpu.c index ab595e10597..570dc097dc3 100644 --- a/src/emu/debug/debugcpu.c +++ b/src/emu/debug/debugcpu.c @@ -24,7 +24,6 @@ #include "express.h" #include "debugvw.h" #include "debugger.h" -#include "deprecat.h" #include "uiinput.h" #include "machine/eeprom.h" #include @@ -52,9 +51,11 @@ enum /* in mame.h: typedef struct _debugcpu_private debugcpu_private; */ struct _debugcpu_private { - cpu_debug_data *livecpu; - cpu_debug_data *visiblecpu; - cpu_debug_data *breakcpu; + const device_config *livecpu; + const device_config *visiblecpu; + const device_config *breakcpu; + + FILE * source_file; /* script source file */ symbol_table * symtable; /* global symbol table */ @@ -81,21 +82,26 @@ struct _debugcpu_private LOCAL VARIABLES ***************************************************************************/ -FILE *debug_source_file; - /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ +/* internal helpers */ static void debug_cpu_exit(running_machine *machine); -static void perform_trace(running_machine *machine, cpu_debug_data *info); -static void prepare_for_step_overout(running_machine *machine, cpu_debug_data *info); +static void on_vblank(const device_config *device, void *param, int vblank_state); +static void reset_transient_flags(running_machine *machine); +static void compute_debug_flags(const device_config *device); +static void perform_trace(cpu_debug_data *info); +static void prepare_for_step_overout(cpu_debug_data *info); static void process_source_file(running_machine *machine); +static void breakpoint_update_flags(cpu_debug_data *info); static void breakpoint_check(running_machine *machine, cpu_debug_data *info, offs_t pc); +static void watchpoint_update_flags(const address_space *space); static void watchpoint_check(const address_space *space, int type, offs_t address, UINT64 value_to_write, UINT64 mem_mask); static void check_hotspots(const address_space *space, offs_t address); +static UINT32 dasm_wrapped(const device_config *device, char *buffer, offs_t pc); /* expression handlers */ static UINT64 expression_read_memory(void *param, const char *name, int space, UINT32 address, int size); @@ -111,20 +117,21 @@ static void expression_write_eeprom(running_machine *machine, offs_t address, in static EXPRERR expression_validate(void *param, const char *name, int space); /* variable getters/setters */ -static UINT64 get_wpaddr(void *ref); -static UINT64 get_wpdata(void *ref); -static UINT64 get_cycles(void *ref); -static UINT64 get_cpunum(void *ref); -static UINT64 get_tempvar(void *ref); -static UINT64 get_logunmap(void *ref); -static UINT64 get_beamx(void *ref); -static UINT64 get_beamy(void *ref); -static UINT64 get_frame(void *ref); -static void set_tempvar(void *ref, UINT64 value); -static void set_logunmap(void *ref, UINT64 value); -static UINT64 get_current_pc(void *ref); -static UINT64 get_cpu_reg(void *ref); -static void set_cpu_reg(void *ref, UINT64 value); +static UINT64 get_wpaddr(void *globalref, void *ref); +static UINT64 get_wpdata(void *globalref, void *ref); +static UINT64 get_cpunum(void *globalref, void *ref); +static UINT64 get_tempvar(void *globalref, void *ref); +static void set_tempvar(void *globalref, void *ref, UINT64 value); +static UINT64 get_beamx(void *globalref, void *ref); +static UINT64 get_beamy(void *globalref, void *ref); +static UINT64 get_frame(void *globalref, void *ref); +static UINT64 get_current_pc(void *globalref, void *ref); +static UINT64 get_cycles(void *globalref, void *ref); +static UINT64 get_logunmap(void *globalref, void *ref); +static void set_logunmap(void *globalref, void *ref, UINT64 value); +static UINT64 get_cpu_reg(void *globalref, void *ref); +static void set_cpu_reg(void *globalref, void *ref, UINT64 value); + /*************************************************************************** @@ -141,35 +148,7 @@ const express_callbacks debug_expression_callbacks = /*************************************************************************** - FRONTENDS FOR OLDER FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - 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; -} - - -/*------------------------------------------------- - on_vblank - called when a VBLANK hits --------------------------------------------------*/ - -static void on_vblank(const device_config *device, void *param, int vblank_state) -{ - /* just set a global flag to be consumed later */ - if (vblank_state) - device->machine->debugcpu_data->vblank_occurred = TRUE; -} - - - -/*************************************************************************** - INITIALIZATION + INITIALIZATION AND CLEANUP ***************************************************************************/ /*------------------------------------------------- @@ -179,6 +158,7 @@ static void on_vblank(const device_config *device, void *param, int vblank_state void debug_cpu_init(running_machine *machine) { + const device_config *first_screen = video_screen_first(machine->config); int cpunum, spacenum, regnum; debugcpu_private *global; @@ -190,19 +170,15 @@ void debug_cpu_init(running_machine *machine) global->wpindex = 1; /* create a global symbol table */ - global->symtable = symtable_alloc(NULL); + global->symtable = symtable_alloc(NULL, machine); /* add "wpaddr", "wpdata", "cycles", "cpunum", "logunmap" to the global symbol table */ symtable_add_register(global->symtable, "wpaddr", NULL, get_wpaddr, NULL); symtable_add_register(global->symtable, "wpdata", NULL, get_wpdata, NULL); - symtable_add_register(global->symtable, "cycles", NULL, get_cycles, NULL); symtable_add_register(global->symtable, "cpunum", NULL, get_cpunum, NULL); - symtable_add_register(global->symtable, "logunmap", (void *)ADDRESS_SPACE_PROGRAM, get_logunmap, set_logunmap); - symtable_add_register(global->symtable, "logunmapd", (void *)ADDRESS_SPACE_DATA, get_logunmap, set_logunmap); - symtable_add_register(global->symtable, "logunmapi", (void *)ADDRESS_SPACE_IO, get_logunmap, set_logunmap); - symtable_add_register(global->symtable, "beamx", NULL, get_beamx, NULL); - symtable_add_register(global->symtable, "beamy", NULL, get_beamy, NULL); - symtable_add_register(global->symtable, "frame", NULL, get_frame, NULL); + symtable_add_register(global->symtable, "beamx", (void *)first_screen, get_beamx, NULL); + symtable_add_register(global->symtable, "beamy", (void *)first_screen, get_beamy, NULL); + symtable_add_register(global->symtable, "frame", (void *)first_screen, get_frame, NULL); /* add the temporary variables to the global symbol table */ for (regnum = 0; regnum < NUM_TEMP_VARIABLES; regnum++) @@ -238,10 +214,17 @@ void debug_cpu_init(running_machine *machine) info->readop = (cpu_readop_func)cpu_get_info_fct(info->device, CPUINFO_PTR_READOP); /* allocate a symbol table */ - info->symtable = symtable_alloc(global->symtable); + info->symtable = symtable_alloc(global->symtable, (void *)cpu); /* add a global symbol for the current instruction pointer */ - symtable_add_register(info->symtable, "curpc", info, get_current_pc, 0); + symtable_add_register(info->symtable, "curpc", NULL, get_current_pc, 0); + symtable_add_register(info->symtable, "cycles", NULL, get_cycles, NULL); + if (classheader->space[ADDRESS_SPACE_PROGRAM] != NULL) + symtable_add_register(info->symtable, "logunmap", (void *)classheader->space[ADDRESS_SPACE_PROGRAM], get_logunmap, set_logunmap); + if (classheader->space[ADDRESS_SPACE_DATA] != NULL) + symtable_add_register(info->symtable, "logunmapd", (void *)classheader->space[ADDRESS_SPACE_DATA], get_logunmap, set_logunmap); + if (classheader->space[ADDRESS_SPACE_IO] != NULL) + symtable_add_register(info->symtable, "logunmapi", (void *)classheader->space[ADDRESS_SPACE_IO], get_logunmap, set_logunmap); /* add all registers into it */ for (regnum = 0; regnum < MAX_REGS; regnum++) @@ -306,7 +289,7 @@ void debug_cpu_init(running_machine *machine) } /* first CPU is visible by default */ - global->visiblecpu = cpu_get_debug_data(machine->cpu[0]); + global->visiblecpu = machine->cpu[0]; /* add callback for breaking on VBLANK */ if (machine->primary_screen != NULL) @@ -317,49 +300,30 @@ void debug_cpu_init(running_machine *machine) /*------------------------------------------------- - debug_cpu_exit - free all memory + debug_cpu_flush_traces - flushes all traces; + this is useful if a trace is going on when we + fatalerror -------------------------------------------------*/ -static void debug_cpu_exit(running_machine *machine) +void debug_cpu_flush_traces(running_machine *machine) { - debugcpu_private *global = machine->debugcpu_data; - int cpunum, spacenum; + int cpunum; - /* loop over all watchpoints and breakpoints to free their memory */ for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) if (machine->cpu[cpunum] != NULL) { cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); - - /* close any tracefiles */ if (info->trace.file != NULL) - fclose(info->trace.file); - if (info->trace.action != NULL) - free(info->trace.action); - - /* free the symbol table */ - if (info->symtable != NULL) - symtable_free(info->symtable); - - /* free all breakpoints */ - while (info->bplist != NULL) - debug_cpu_breakpoint_clear(machine, info->bplist->index); - - /* loop over all address spaces */ - for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) - { - /* free all watchpoints */ - while (info->space[spacenum].wplist != NULL) - debug_cpu_watchpoint_clear(machine, info->space[spacenum].wplist->index); - } + fflush(info->trace.file); } - - /* free the global symbol table */ - if (global != NULL && global->symtable != NULL) - symtable_free(global->symtable); } + +/*************************************************************************** + DEBUGGING STATUS AND INFORMATION +***************************************************************************/ + /*------------------------------------------------- cpu_get_visible_cpu - return the visible CPU device (the one that commands should apply to) @@ -367,10 +331,38 @@ static void debug_cpu_exit(running_machine *machine) const device_config *debug_cpu_get_visible_cpu(running_machine *machine) { - return machine->debugcpu_data->visiblecpu->device; + 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->execution_state == EXECUTION_STATE_STOPPED; +} + + + +/*************************************************************************** + SYMBOL TABLE INTERFACES +***************************************************************************/ + /*------------------------------------------------- debug_cpu_get_global_symtable - return the global symbol table @@ -383,13 +375,13 @@ symbol_table *debug_cpu_get_global_symtable(running_machine *machine) /*------------------------------------------------- - debug_cpu_get_global_symtable - return the + debug_cpu_get_visible_symtable - return the locally-visible symbol table --m------------------------------------------------*/ +-------------------------------------------------*/ symbol_table *debug_cpu_get_visible_symtable(running_machine *machine) { - return machine->debugcpu_data->visiblecpu->symtable; + return cpu_get_debug_data(machine->debugcpu_data->visiblecpu)->symtable; } @@ -406,55 +398,9 @@ symbol_table *debug_cpu_get_symtable(const device_config *device) /*************************************************************************** - MAIN CPU CALLBACK + CORE DEBUGGER HOOKS ***************************************************************************/ -/*------------------------------------------------- - compute_debug_flags - compute the global - debug flags for optimal efficiency --------------------------------------------------*/ - -static void compute_debug_flags(const cpu_debug_data *info) -{ - running_machine *machine = info->device->machine; - debugcpu_private *global = machine->debugcpu_data; - - /* clear out all global flags by default */ - machine->debug_flags = DEBUG_FLAG_ENABLED; - - /* if we are ignoring this CPU, or if events are pending, we're done */ - if ((info->flags & DEBUG_FLAG_OBSERVING) == 0 || mame_is_scheduled_event_pending(machine) || mame_is_save_or_load_pending(machine)) - return; - - /* many of our states require us to be called on each instruction */ - if (global->execution_state == EXECUTION_STATE_STOPPED) - machine->debug_flags |= DEBUG_FLAG_CALL_HOOK; - if ((info->flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_TRACING_ANY | DEBUG_FLAG_HOOKED | - DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) - 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 ((info->flags & DEBUG_FLAG_STOP_TIME) && attotime_compare(info->endexectime, info->stoptime) <= 0) - machine->debug_flags |= DEBUG_FLAG_CALL_HOOK; -} - - -/*------------------------------------------------- - reset_transient_flags - reset the transient - flags on all CPUs --------------------------------------------------*/ - -static void reset_transient_flags(running_machine *machine) -{ - int cpunum; - - /* loop over CPUs and reset the transient flags */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - cpu_get_debug_data(machine->cpu[cpunum])->flags &= ~DEBUG_FLAG_TRANSIENT; -} - - /*------------------------------------------------- debug_cpu_start_hook - the CPU execution system calls this hook before beginning @@ -470,7 +416,7 @@ void debug_cpu_start_hook(const device_config *device, attotime endtime) /* stash a pointer to the current live CPU */ assert(global->livecpu == NULL); - global->livecpu = info; + global->livecpu = device; /* update the target execution end time */ info->endexectime = endtime; @@ -479,14 +425,14 @@ void debug_cpu_start_hook(const device_config *device, attotime endtime) if (global->execution_state != EXECUTION_STATE_STOPPED) { /* check for periodic updates */ - if (info == global->visiblecpu && osd_ticks() > global->last_periodic_update_time + osd_ticks_per_second()/4) + if (device == global->visiblecpu && osd_ticks() > global->last_periodic_update_time + osd_ticks_per_second()/4) { debug_view_update_all(); global->last_periodic_update_time = osd_ticks(); } /* check for pending breaks */ - else if (info == global->breakcpu) + else if (device == global->breakcpu) { global->execution_state = EXECUTION_STATE_STOPPED; global->breakcpu = NULL; @@ -506,12 +452,12 @@ void debug_cpu_start_hook(const device_config *device, attotime endtime) /* check for debug keypresses */ else if (ui_input_pressed(device->machine, IPT_UI_DEBUG_BREAK)) - debug_cpu_halt_on_next_instruction(device->machine, -1, "User-initiated break\n"); + debug_cpu_halt_on_next_instruction(global->visiblecpu, "User-initiated break\n"); } } /* recompute the debugging mode */ - compute_debug_flags(info); + compute_debug_flags(device); } @@ -526,7 +472,7 @@ void debug_cpu_stop_hook(const device_config *device) debugcpu_private *global = device->machine->debugcpu_data; cpu_debug_data *info = cpu_get_debug_data(device); - assert(global->livecpu == info); + assert(global->livecpu == device); /* if we're stopping on a context switch, handle it now */ if (info->flags & DEBUG_FLAG_STOP_CONTEXT) @@ -555,7 +501,7 @@ void debug_cpu_interrupt_hook(const device_config *device, int irqline) { global->execution_state = EXECUTION_STATE_STOPPED; debug_console_printf("Stopped on interrupt (CPU '%s', IRQ %d)\n", device->tag, irqline); - compute_debug_flags(info); + compute_debug_flags(device); } } @@ -575,7 +521,7 @@ void debug_cpu_exception_hook(const device_config *device, int exception) { global->execution_state = EXECUTION_STATE_STOPPED; debug_console_printf("Stopped on exception (CPU '%s', exception %d)\n", device->tag, exception); - compute_debug_flags(info); + compute_debug_flags(device); } } @@ -598,7 +544,7 @@ void debug_cpu_instruction_hook(const device_config *device, offs_t curpc) /* are we tracing? */ if (info->flags & DEBUG_FLAG_TRACING_ANY) - perform_trace(device->machine, info); + perform_trace(info); /* per-instruction hook? */ if (global->execution_state != EXECUTION_STATE_STOPPED && (info->flags & DEBUG_FLAG_HOOKED) != 0 && (*info->instrhook)(device, curpc)) @@ -688,12 +634,12 @@ void debug_cpu_instruction_hook(const device_config *device, offs_t curpc) sound_mute(FALSE); /* remember the last visible CPU in the debugger */ - global->visiblecpu = info; + global->visiblecpu = device; } /* handle step out/over on the instruction we are about to execute */ if ((info->flags & (DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT)) != 0 && info->stepaddr == ~0) - prepare_for_step_overout(device->machine, info); + prepare_for_step_overout(info); /* no longer in debugger code */ global->within_instruction_hook = FALSE; @@ -737,185 +683,34 @@ void debug_cpu_memory_write_hook(const address_space *space, offs_t address, UIN ***************************************************************************/ /*------------------------------------------------- - debug_cpu_single_step - single step past the - requested number of instructions + debug_cpu_halt_on_next_instruction - halt in + the debugger on the next instruction -------------------------------------------------*/ -void debug_cpu_single_step(int numsteps) +void debug_cpu_halt_on_next_instruction(const device_config *device, const char *fmt, ...) { - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; + debugcpu_private *global = device->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(device); + va_list arg; - if (!global->within_instruction_hook) + /* if something is pending on this CPU already, ignore this request */ + if (info != NULL && device == global->breakcpu) return; - assert(info != NULL); - info->stepsleft = numsteps; - info->stepaddr = ~0; - info->flags |= DEBUG_FLAG_STEPPING; - global->execution_state = EXECUTION_STATE_RUNNING; -} + /* output the message to the console */ + va_start(arg, fmt); + debug_console_vprintf(fmt, arg); + va_end(arg); - -/*------------------------------------------------- - debug_cpu_single_step_over - single step over - a single instruction --------------------------------------------------*/ - -void debug_cpu_single_step_over(int numsteps) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stepsleft = numsteps; - info->stepaddr = ~0; - info->flags |= DEBUG_FLAG_STEPPING_OVER; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_single_step_out - single step out of - the current function --------------------------------------------------*/ - -void debug_cpu_single_step_out(void) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stepsleft = 100; - info->stepaddr = ~0; - info->flags |= DEBUG_FLAG_STEPPING_OUT; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_go - resume execution --------------------------------------------------*/ - -void debug_cpu_go(offs_t targetpc) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stopaddr = targetpc; - info->flags |= DEBUG_FLAG_STOP_PC; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_go_vblank - run until the next - VBLANK --------------------------------------------------*/ - -void debug_cpu_go_vblank(void) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - global->vblank_occurred = FALSE; - info->flags |= DEBUG_FLAG_STOP_VBLANK; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_go_interrupt - run until the - specified interrupt fires --------------------------------------------------*/ - -void debug_cpu_go_interrupt(int irqline) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stopirq = irqline; - info->flags |= DEBUG_FLAG_STOP_INTERRUPT; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_go_exception - run until the - specified exception fires --------------------------------------------------*/ - -#ifdef UNUSED_FUNCTION -void debug_cpu_go_exception(int exception) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stopexception = exception; - info->flags |= DEBUG_FLAG_STOP_EXCEPTION; - global->execution_state = EXECUTION_STATE_RUNNING; -} -#endif - - -/*------------------------------------------------- - debug_cpu_go_milliseconds - run until the - specified delay elapses --------------------------------------------------*/ - -void debug_cpu_go_milliseconds(UINT64 milliseconds) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->stoptime = attotime_add(timer_get_time(), ATTOTIME_IN_MSEC(milliseconds)); - info->flags |= DEBUG_FLAG_STOP_TIME; - global->execution_state = EXECUTION_STATE_RUNNING; -} - - -/*------------------------------------------------- - debug_cpu_next_cpu - execute until we hit - the next CPU --------------------------------------------------*/ - -void debug_cpu_next_cpu(void) -{ - debugcpu_private *global = Machine->debugcpu_data; - cpu_debug_data *info = global->livecpu; - - if (!global->within_instruction_hook) - return; - assert(info != NULL); - - info->flags |= DEBUG_FLAG_STOP_CONTEXT; - global->execution_state = EXECUTION_STATE_RUNNING; + /* if we are live, stop now, otherwise note that we want to break there */ + if (device == global->livecpu) + { + global->execution_state = EXECUTION_STATE_STOPPED; + if (global->livecpu != NULL) + compute_debug_flags(global->livecpu); + } + else + global->breakcpu = device; } @@ -937,8 +732,450 @@ void debug_cpu_ignore_cpu(const device_config *device, int ignore) else info->flags |= DEBUG_FLAG_OBSERVING; - if (info == global->livecpu && ignore) - debug_cpu_next_cpu(); + if (device == global->livecpu && ignore) + debug_cpu_next_cpu(device->machine); +} + + +/*------------------------------------------------- + debug_cpu_single_step - single step the visible + CPU past the requested number of instructions +-------------------------------------------------*/ + +void debug_cpu_single_step(running_machine *machine, int numsteps) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stepsleft = numsteps; + info->stepaddr = ~0; + info->flags |= DEBUG_FLAG_STEPPING; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_single_step_over - single step the + visible over the requested number of + instructions +-------------------------------------------------*/ + +void debug_cpu_single_step_over(running_machine *machine, int numsteps) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stepsleft = numsteps; + info->stepaddr = ~0; + info->flags |= DEBUG_FLAG_STEPPING_OVER; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_single_step_out - single step the + visible CPU out of the current function +-------------------------------------------------*/ + +void debug_cpu_single_step_out(running_machine *machine) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stepsleft = 100; + info->stepaddr = ~0; + info->flags |= DEBUG_FLAG_STEPPING_OUT; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_go - execute the visible CPU until + it hits the given address +-------------------------------------------------*/ + +void debug_cpu_go(running_machine *machine, offs_t targetpc) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stopaddr = targetpc; + info->flags |= DEBUG_FLAG_STOP_PC; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_go_vblank - execute until the next + VBLANK +-------------------------------------------------*/ + +void debug_cpu_go_vblank(running_machine *machine) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + global->vblank_occurred = FALSE; + info->flags |= DEBUG_FLAG_STOP_VBLANK; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_go_interrupt - execute until the + specified interrupt fires on the visible CPU +-------------------------------------------------*/ + +void debug_cpu_go_interrupt(running_machine *machine, int irqline) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stopirq = irqline; + info->flags |= DEBUG_FLAG_STOP_INTERRUPT; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_go_exception - execute until the + specified exception fires on the visible CPU +-------------------------------------------------*/ + +void debug_cpu_go_exception(running_machine *machine, int exception) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stopexception = exception; + info->flags |= DEBUG_FLAG_STOP_EXCEPTION; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_go_milliseconds - execute until the + specified delay elapses +-------------------------------------------------*/ + +void debug_cpu_go_milliseconds(running_machine *machine, UINT64 milliseconds) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->stoptime = attotime_add(timer_get_time(), ATTOTIME_IN_MSEC(milliseconds)); + info->flags |= DEBUG_FLAG_STOP_TIME; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + +/*------------------------------------------------- + debug_cpu_next_cpu - execute until we hit + the next CPU +-------------------------------------------------*/ + +void debug_cpu_next_cpu(running_machine *machine) +{ + debugcpu_private *global = machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(global->livecpu); + + if (!global->within_instruction_hook) + return; + assert(info != NULL); + + info->flags |= DEBUG_FLAG_STOP_CONTEXT; + global->execution_state = EXECUTION_STATE_RUNNING; +} + + + +/*************************************************************************** + BREAKPOINTS +***************************************************************************/ + +/*------------------------------------------------- + debug_cpu_breakpoint_set - set a new + breakpoint, returning its index +-------------------------------------------------*/ + +int debug_cpu_breakpoint_set(const device_config *device, offs_t address, parsed_expression *condition, const char *action) +{ + debugcpu_private *global = device->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(device); + debug_cpu_breakpoint *bp; + + assert_always(device != NULL, "debug_cpu_breakpoint_set() called with invalid cpu!"); + + /* allocate breakpoint */ + bp = malloc_or_die(sizeof(*bp)); + bp->index = global->bpindex++; + bp->enabled = TRUE; + bp->address = address; + bp->condition = condition; + bp->action = NULL; + if (action != NULL) + { + bp->action = malloc_or_die(strlen(action) + 1); + strcpy(bp->action, action); + } + + /* hook us in */ + bp->next = info->bplist; + info->bplist = bp; + + /* ensure the live breakpoint flag is set */ + breakpoint_update_flags(info); + return bp->index; +} + + +/*------------------------------------------------- + debug_cpu_breakpoint_clear - clear a + breakpoint by index +-------------------------------------------------*/ + +int debug_cpu_breakpoint_clear(running_machine *machine, int bpnum) +{ + debug_cpu_breakpoint *bp, *pbp; + int cpunum; + + /* loop over CPUs and find the requested breakpoint */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + { + cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); + for (pbp = NULL, bp = info->bplist; bp != NULL; pbp = bp, bp = bp->next) + if (bp->index == bpnum) + { + /* unlink us from the list */ + if (pbp == NULL) + info->bplist = bp->next; + else + pbp->next = bp->next; + + /* free the memory */ + if (bp->condition != NULL) + expression_free(bp->condition); + if (bp->action != NULL) + free(bp->action); + free(bp); + + /* update the flags */ + breakpoint_update_flags(info); + return TRUE; + } + } + + /* we didn't find it; return an error */ + return FALSE; +} + + +/*------------------------------------------------- + debug_cpu_breakpoint_enable - enable/disable + a breakpoint by index +-------------------------------------------------*/ + +int debug_cpu_breakpoint_enable(running_machine *machine, int bpnum, int enable) +{ + debug_cpu_breakpoint *bp; + int cpunum; + + /* loop over CPUs and find the requested breakpoint */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + { + cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); + for (bp = info->bplist; bp != NULL; bp = bp->next) + if (bp->index == bpnum) + { + bp->enabled = (enable != 0); + breakpoint_update_flags(info); + return TRUE; + } + } + + return FALSE; +} + + + +/*************************************************************************** + WATCHPOINTS +***************************************************************************/ + +/*------------------------------------------------- + debug_cpu_watchpoint_set - set a new + watchpoint, returning its index +-------------------------------------------------*/ + +int debug_cpu_watchpoint_set(const address_space *space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + debug_cpu_watchpoint *wp = malloc_or_die(sizeof(*wp)); + + /* fill in the structure */ + wp->index = global->wpindex++; + wp->enabled = TRUE; + wp->type = type; + wp->address = ADDR2BYTE_MASKED(address, info, space->spacenum); + wp->length = ADDR2BYTE(length, info, space->spacenum); + wp->condition = condition; + wp->action = NULL; + if (action != NULL) + { + wp->action = malloc_or_die(strlen(action) + 1); + strcpy(wp->action, action); + } + + /* hook us in */ + wp->next = info->space[space->spacenum].wplist; + info->space[space->spacenum].wplist = wp; + + watchpoint_update_flags(space); + + return wp->index; +} + + +/*------------------------------------------------- + debug_cpu_watchpoint_clear - clear a + watchpoint by index +-------------------------------------------------*/ + +int debug_cpu_watchpoint_clear(running_machine *machine, int wpnum) +{ + debug_cpu_watchpoint *wp, *pwp; + int cpunum, spacenum; + + /* loop over CPUs and find the requested watchpoint */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + { + cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); + + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + for (pwp = NULL, wp = info->space[spacenum].wplist; wp != NULL; pwp = wp, wp = wp->next) + if (wp->index == wpnum) + { + /* unlink us from the list */ + if (pwp == NULL) + info->space[spacenum].wplist = wp->next; + else + pwp->next = wp->next; + + /* free the memory */ + if (wp->condition != NULL) + expression_free(wp->condition); + if (wp->action != NULL) + free(wp->action); + free(wp); + + watchpoint_update_flags(cpu_get_address_space(machine->cpu[cpunum], spacenum)); + return TRUE; + } + } + + /* we didn't find it; return an error */ + return FALSE; +} + + +/*------------------------------------------------- + debug_cpu_watchpoint_enable - enable/disable a + watchpoint by index +-------------------------------------------------*/ + +int debug_cpu_watchpoint_enable(running_machine *machine, int wpnum, int enable) +{ + debug_cpu_watchpoint *wp; + int cpunum, spacenum; + + /* loop over CPUs and address spaces and find the requested watchpoint */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + { + cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); + + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + for (wp = info->space[spacenum].wplist; wp; wp = wp->next) + if (wp->index == wpnum) + { + wp->enabled = (enable != 0); + watchpoint_update_flags(cpu_get_address_space(machine->cpu[cpunum], spacenum)); + return TRUE; + } + } + return FALSE; +} + + + +/*************************************************************************** + MISC DEBUGGER FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + 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 (mame_get_phase(machine) == MAME_PHASE_RUNNING) + debug_console_printf("Cannot open command file '%s'\n", file); + else + fatalerror("Cannot open command file '%s'", file); + } + } } @@ -978,58 +1215,697 @@ void debug_cpu_trace(const device_config *device, FILE *file, int trace_over, co } - -/*************************************************************************** - UTILITIES -***************************************************************************/ - /*------------------------------------------------- - debug_cpu_halt_on_next_instruction - halt in - the debugger on the next instruction + debug_cpu_trace_printf - output data into the + given CPU's tracefile, if tracing -------------------------------------------------*/ -void debug_cpu_halt_on_next_instruction(running_machine *machine, int cpunum, const char *fmt, ...) +void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) { - debugcpu_private *global = machine->debugcpu_data; - cpu_debug_data *info; - va_list arg; + va_list va; - /* pick the best CPU to land on */ - if (cpunum != -1) - info = cpu_get_debug_data(machine->cpu[cpunum]); - else if (global->visiblecpu != NULL) - info = global->visiblecpu; - else - info = global->livecpu; + cpu_debug_data *info = cpu_get_debug_data(device); - /* if something is pending on this CPU already, ignore this request */ - if (info != NULL && info == global->breakcpu) - return; - - va_start(arg, fmt); - debug_console_vprintf(fmt, arg); - va_end(arg); - - if (info == global->livecpu) + if (info->trace.file) { - global->execution_state = EXECUTION_STATE_STOPPED; - if (global->livecpu != NULL) - compute_debug_flags(global->livecpu); + va_start(va, fmt); + vfprintf(info->trace.file, fmt, va); + va_end(va); } - else - global->breakcpu = info; } /*------------------------------------------------- - debug_cpu_is_stopped - return the - current execution state + debug_cpu_set_instruction_hook - set a hook to + be called on each instruction for a given CPU -------------------------------------------------*/ -int debug_cpu_is_stopped(running_machine *machine) +void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook) +{ + cpu_debug_data *info = cpu_get_debug_data(device); + + /* set the hook and also the CPU's flag for fast knowledge of the hook */ + info->instrhook = hook; + if (hook != NULL) + info->flags |= DEBUG_FLAG_HOOKED; + else + info->flags &= ~DEBUG_FLAG_HOOKED; +} + + +/*------------------------------------------------- + debug_cpu_hotspot_track - enable/disable + tracking of hotspots +-------------------------------------------------*/ + +int debug_cpu_hotspot_track(const device_config *device, int numspots, int threshhold) +{ + cpu_debug_data *info = cpu_get_debug_data(device); + + /* if we already have tracking info, kill it */ + if (info->hotspots) + free(info->hotspots); + info->hotspots = NULL; + + /* only start tracking if we have a non-zero count */ + if (numspots > 0) + { + /* allocate memory for hotspots */ + info->hotspots = malloc_or_die(sizeof(*info->hotspots) * numspots); + memset(info->hotspots, 0xff, sizeof(*info->hotspots) * numspots); + + /* fill in the info */ + info->hotspot_count = numspots; + info->hotspot_threshhold = threshhold; + } + + watchpoint_update_flags(cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM)); + return TRUE; +} + + + +/*************************************************************************** + DEBUGGER MEMORY ACCESSORS +***************************************************************************/ + +/*------------------------------------------------- + debug_read_byte - return a byte from the + the specified memory space +-------------------------------------------------*/ + +UINT8 debug_read_byte(const address_space *space, offs_t address, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + UINT64 custom; + UINT8 result; + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].logbytemask; + + /* all accesses from this point on are for the debugger */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, return 0xff */ + if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) + result = 0xff; + + /* if there is a custom read handler, and it returns TRUE, use that value */ + else if (info->read != NULL && (*info->read)(space->cpu, space->spacenum, address, 1, &custom)) + result = custom; + + /* otherwise, call the byte reading function for the translated address */ + else + result = memory_read_byte(space, address); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + return result; +} + + +/*------------------------------------------------- + debug_read_word - return a word from the + specified memory space +-------------------------------------------------*/ + +UINT16 debug_read_word(const address_space *space, offs_t address, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + UINT64 custom; + UINT16 result; + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) + result = byte0 | (byte1 << 8); + else + result = byte1 | (byte0 << 8); + } + + /* otherwise, this proceeds like the byte case */ + else + { + /* all accesses from this point on are for the debugger */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, return 0xffff */ + if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) + result = 0xffff; + + /* if there is a custom read handler, and it returns TRUE, use that value */ + else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 2, &custom)) + result = custom; + + /* otherwise, call the byte reading function for the translated address */ + else + result = memory_read_word(space, address); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + } + + return result; +} + + +/*------------------------------------------------- + debug_read_dword - return a dword from the + specified memory space +-------------------------------------------------*/ + +UINT32 debug_read_dword(const address_space *space, offs_t address, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + UINT64 custom; + UINT32 result; + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) + result = word0 | (word1 << 16); + else + result = word1 | (word0 << 16); + } + + /* otherwise, this proceeds like the byte case */ + else + { + /* all accesses from this point on are for the debugger */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, return 0xffffffff */ + if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) + result = 0xffffffff; + + /* if there is a custom read handler, and it returns TRUE, use that value */ + else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 4, &custom)) + result = custom; + + /* otherwise, call the byte reading function for the translated address */ + else + result = memory_read_dword(space, address); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + } + + return result; +} + + +/*------------------------------------------------- + debug_read_qword - return a qword from the + specified memory space +-------------------------------------------------*/ + +UINT64 debug_read_qword(const address_space *space, offs_t address, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + UINT64 custom; + UINT64 result; + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) + result = dword0 | ((UINT64)dword1 << 32); + else + result = dword1 | ((UINT64)dword0 << 32); + } + + /* otherwise, this proceeds like the byte case */ + else + { + /* all accesses from this point on are for the debugger */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, return 0xffffffffffffffff */ + if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) + result = ~(UINT64)0; + + /* if there is a custom read handler, and it returns TRUE, use that value */ + else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 8, &custom)) + result = custom; + + /* otherwise, call the byte reading function for the translated address */ + else + result = memory_read_qword(space, address); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + } + + return result; +} + + +/*------------------------------------------------- + debug_write_byte - write a byte to the + specified memory space +-------------------------------------------------*/ + +void debug_write_byte(const address_space *space, offs_t address, UINT8 data, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].logbytemask; + + /* all accesses from this point on are for the debugger */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, we're done */ + if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) + ; + + /* if there is a custom write handler, and it returns TRUE, use that */ + else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 1, data)) + ; + + /* otherwise, call the byte reading function for the translated address */ + else + memory_write_byte(space, address, data); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + global->memory_modified = TRUE; +} + + +/*------------------------------------------------- + debug_write_word - write a word to the + specified memory space +-------------------------------------------------*/ + +void debug_write_word(const address_space *space, offs_t address, UINT16 data, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].logbytemask; + + /* if this is a misaligned write, or if there are no word writers, just read two bytes */ + if ((address & 1) != 0) + { + if (info->endianness == CPU_IS_LE) + { + 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 */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, we're done */ + if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) + ; + + /* if there is a custom write handler, and it returns TRUE, use that */ + else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 2, data)) + ; + + /* otherwise, call the byte reading function for the translated address */ + else + memory_write_word(space, address, data); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + global->memory_modified = TRUE; + } +} + + +/*------------------------------------------------- + debug_write_dword - write a dword to the + specified memory space +-------------------------------------------------*/ + +void debug_write_dword(const address_space *space, offs_t address, UINT32 data, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].logbytemask; + + /* if this is a misaligned write, or if there are no dword writers, just read two words */ + if ((address & 3) != 0) + { + if (info->endianness == CPU_IS_LE) + { + 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 */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, we're done */ + if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) + ; + + /* if there is a custom write handler, and it returns TRUE, use that */ + else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 4, data)) + ; + + /* otherwise, call the byte reading function for the translated address */ + else + memory_write_dword(space, address, data); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + global->memory_modified = TRUE; + } +} + + +/*------------------------------------------------- + debug_write_qword - write a qword to the + specified memory space +-------------------------------------------------*/ + +void debug_write_qword(const address_space *space, offs_t address, UINT64 data, int apply_translation) +{ + debugcpu_private *global = space->machine->debugcpu_data; + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + + /* mask against the logical byte mask */ + address &= info->space[space->spacenum].logbytemask; + + /* if this is a misaligned write, or if there are no qword writers, just read two dwords */ + if ((address & 7) != 0) + { + if (info->endianness == CPU_IS_LE) + { + 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 */ + memory_set_debugger_access(space, global->debugger_access = TRUE); + + /* translate if necessary; if not mapped, we're done */ + if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) + ; + + /* if there is a custom write handler, and it returns TRUE, use that */ + else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 8, data)) + ; + + /* otherwise, call the byte reading function for the translated address */ + else + memory_write_qword(space, address, data); + + /* no longer accessing via the debugger */ + memory_set_debugger_access(space, global->debugger_access = FALSE); + global->memory_modified = TRUE; + } +} + + +/*------------------------------------------------- + debug_read_opcode - read 1,2,4 or 8 bytes at + the given offset from opcode space +-------------------------------------------------*/ + +UINT64 debug_read_opcode(const address_space *space, offs_t address, int size, int arg) +{ + cpu_debug_data *info = cpu_get_debug_data(space->cpu); + offs_t lowbits_mask; + const void *ptr; + + /* keep in logical range */ + address &= info->space[ADDRESS_SPACE_PROGRAM].logbytemask; + + /* shortcut if we have a custom routine */ + if (info->readop) + { + UINT64 result; + if ((*info->readop)(space->cpu, address, size, &result)) + return result; + } + + /* if we're bigger than the address bus, break into smaller pieces */ + if (size > info->space[ADDRESS_SPACE_PROGRAM].databytes) + { + int halfsize = size / 2; + UINT64 r0 = debug_read_opcode(space, address + 0, halfsize, arg); + UINT64 r1 = debug_read_opcode(space, address + halfsize, halfsize, arg); + + if (info->endianness == CPU_IS_LE) + return r0 | (r1 << (8 * halfsize)); + else + return r1 | (r0 << (8 * halfsize)); + } + + /* translate to physical first */ + if (info->translate && !(*info->translate)(space->cpu, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH_DEBUG, &address)) + return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size)); + + /* keep in physical range */ + address &= info->space[ADDRESS_SPACE_PROGRAM].physbytemask; + + /* adjust the address */ + change_pc(address); + + switch (info->space[ADDRESS_SPACE_PROGRAM].databytes * 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: + address ^= (info->endianness == CPU_IS_LE) ? 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: + address ^= (info->endianness == CPU_IS_LE) ? BYTE4_XOR_LE(0) : BYTE4_XOR_BE(0); + break; + + /* dump opcodes in words from a dword-sized bus */ + case 42: + address ^= (info->endianness == CPU_IS_LE) ? 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: + address ^= (info->endianness == CPU_IS_LE) ? BYTE8_XOR_LE(0) : BYTE8_XOR_BE(0); + break; + + /* dump opcodes in words from a qword-sized bus */ + case 82: + address ^= (info->endianness == CPU_IS_LE) ? WORD2_XOR_LE(0) : WORD2_XOR_BE(0); + break; + + /* dump opcodes in dwords from a qword-sized bus */ + case 84: + address ^= (info->endianness == CPU_IS_LE) ? 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", info->space[ADDRESS_SPACE_PROGRAM].databytes * 10 + size); + break; + } + + /* get pointer to data */ + /* note that we query aligned to the bus width, and then add back the low bits */ + lowbits_mask = info->space[ADDRESS_SPACE_PROGRAM].databytes - 1; + if (!arg) + ptr = memory_decrypted_read_ptr(space, address & ~lowbits_mask); + else + ptr = memory_raw_read_ptr(space, address & ~lowbits_mask); + if (ptr == NULL) + return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size)); + ptr = (UINT8 *)ptr + (address & lowbits_mask); + + /* return based on the size */ + switch (size) + { + case 1: return *(UINT8 *) ptr; + case 2: return *(UINT16 *)ptr; + case 4: return *(UINT32 *)ptr; + case 8: return *(UINT64 *)ptr; + } + + return 0; /* appease compiler */ +} + + + +/*************************************************************************** + INTERNAL HELPERS +***************************************************************************/ + +/*------------------------------------------------- + debug_cpu_exit - free all memory +-------------------------------------------------*/ + +static void debug_cpu_exit(running_machine *machine) { debugcpu_private *global = machine->debugcpu_data; - return global->execution_state == EXECUTION_STATE_STOPPED; + int cpunum, spacenum; + + /* loop over all watchpoints and breakpoints to free their memory */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + { + cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); + + /* close any tracefiles */ + if (info->trace.file != NULL) + fclose(info->trace.file); + if (info->trace.action != NULL) + free(info->trace.action); + + /* free the symbol table */ + if (info->symtable != NULL) + symtable_free(info->symtable); + + /* free all breakpoints */ + while (info->bplist != NULL) + debug_cpu_breakpoint_clear(machine, info->bplist->index); + + /* loop over all address spaces */ + for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) + { + /* free all watchpoints */ + while (info->space[spacenum].wplist != NULL) + debug_cpu_watchpoint_clear(machine, info->space[spacenum].wplist->index); + } + } + + /* free the global symbol table */ + if (global != NULL && global->symtable != NULL) + symtable_free(global->symtable); +} + + +/*------------------------------------------------- + on_vblank - called when a VBLANK hits +-------------------------------------------------*/ + +static void on_vblank(const device_config *device, void *param, int 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) +{ + int cpunum; + + /* loop over CPUs and reset the transient flags */ + for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) + if (machine->cpu[cpunum] != NULL) + cpu_get_debug_data(machine->cpu[cpunum])->flags &= ~DEBUG_FLAG_TRANSIENT; +} + + +/*------------------------------------------------- + compute_debug_flags - compute the global + debug flags for optimal efficiency +-------------------------------------------------*/ + +static void compute_debug_flags(const device_config *device) +{ + cpu_debug_data *info = cpu_get_debug_data(device); + running_machine *machine = device->machine; + debugcpu_private *global = machine->debugcpu_data; + + /* clear out all global flags by default */ + machine->debug_flags = DEBUG_FLAG_ENABLED; + + /* if we are ignoring this CPU, or if events are pending, we're done */ + if ((info->flags & DEBUG_FLAG_OBSERVING) == 0 || mame_is_scheduled_event_pending(machine) || mame_is_save_or_load_pending(machine)) + return; + + /* many of our states require us to be called on each instruction */ + if (global->execution_state == EXECUTION_STATE_STOPPED) + machine->debug_flags |= DEBUG_FLAG_CALL_HOOK; + if ((info->flags & (DEBUG_FLAG_HISTORY | DEBUG_FLAG_TRACING_ANY | DEBUG_FLAG_HOOKED | + DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC | DEBUG_FLAG_LIVE_BP)) != 0) + 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 ((info->flags & DEBUG_FLAG_STOP_TIME) && attotime_compare(info->endexectime, info->stoptime) <= 0) + machine->debug_flags |= DEBUG_FLAG_CALL_HOOK; } @@ -1038,29 +1914,9 @@ int debug_cpu_is_stopped(running_machine *machine) data for a given instruction -------------------------------------------------*/ -static UINT32 dasm_wrapped(running_machine *machine, char *buffer, offs_t pc) +static void perform_trace(cpu_debug_data *info) { - const cpu_debug_data *cpuinfo = cpu_get_debug_data(machine->activecpu); - int maxbytes = cpu_get_max_opcode_bytes(machine->activecpu); - UINT8 opbuf[64], argbuf[64]; - offs_t pcbyte; - int numbytes; - - /* fetch the bytes up to the maximum */ - pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM); - for (numbytes = 0; numbytes < maxbytes; numbytes++) - { - opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE); - argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE); - } - - return cpu_dasm(machine->activecpu, buffer, pc, opbuf, argbuf); -} - - -static void perform_trace(running_machine *machine, cpu_debug_data *info) -{ - offs_t pc = cpu_get_pc(machine->activecpu); + offs_t pc = cpu_get_pc(info->device); int offset, count, i; char buffer[100]; offs_t dasmresult; @@ -1088,13 +1944,13 @@ static void perform_trace(running_machine *machine, cpu_debug_data *info) /* execute any trace actions first */ if (info->trace.action != NULL) - debug_console_execute_command(machine, info->trace.action, 0); + debug_console_execute_command(info->device->machine, info->trace.action, 0); /* print the address */ offset = sprintf(buffer, "%0*X: ", info->space[ADDRESS_SPACE_PROGRAM].logchars, pc); /* print the disassembly */ - dasmresult = dasm_wrapped(machine, &buffer[offset], pc); + dasmresult = dasm_wrapped(info->device, &buffer[offset], pc); /* output the result */ fprintf(info->trace.file, "%s\n", buffer); @@ -1107,7 +1963,7 @@ static void perform_trace(running_machine *machine, cpu_debug_data *info) /* if we need to skip additional instructions, advance as requested */ while (extraskip-- > 0) - trace_over_target += dasm_wrapped(machine, buffer, trace_over_target) & DASMFLAG_LENGTHMASK; + trace_over_target += dasm_wrapped(info->device, buffer, trace_over_target) & DASMFLAG_LENGTHMASK; info->trace.trace_over_target = trace_over_target; } @@ -1128,14 +1984,14 @@ static void perform_trace(running_machine *machine, cpu_debug_data *info) stepping over an instruction -------------------------------------------------*/ -static void prepare_for_step_overout(running_machine *machine, cpu_debug_data *info) +static void prepare_for_step_overout(cpu_debug_data *info) { - offs_t pc = cpu_get_pc(machine->activecpu); + offs_t pc = cpu_get_pc(info->device); char dasmbuffer[100]; offs_t dasmresult; /* disassemble the current instruction and get the flags */ - dasmresult = dasm_wrapped(machine, dasmbuffer, pc); + dasmresult = dasm_wrapped(info->device, 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) @@ -1145,7 +2001,7 @@ static void prepare_for_step_overout(running_machine *machine, cpu_debug_data *i /* if we need to skip additional instructions, advance as requested */ while (extraskip-- > 0) - pc += dasm_wrapped(machine, dasmbuffer, pc) & DASMFLAG_LENGTHMASK; + pc += dasm_wrapped(info->device, dasmbuffer, pc) & DASMFLAG_LENGTHMASK; info->stepaddr = pc; } @@ -1170,23 +2026,23 @@ 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 (debug_source_file != NULL && global->execution_state == EXECUTION_STATE_STOPPED) + 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(debug_source_file)) + if (feof(global->source_file)) { - fclose(debug_source_file); - debug_source_file = NULL; + fclose(global->source_file); + global->source_file = NULL; return; } /* fetch the next line */ memset(buf, 0, sizeof(buf)); - fgets(buf, sizeof(buf), debug_source_file); + fgets(buf, sizeof(buf), global->source_file); /* strip out comments (text after '//') */ s = strstr(buf, "//"); @@ -1205,29 +2061,6 @@ static void process_source_file(running_machine *machine) } -/*------------------------------------------------- - debug_cpu_set_instruction_hook - set a hook to - be called on each instruction for a given CPU --------------------------------------------------*/ - -void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook) -{ - cpu_debug_data *info = cpu_get_debug_data(device); - - /* set the hook and also the CPU's flag for fast knowledge of the hook */ - info->instrhook = hook; - if (hook != NULL) - info->flags |= DEBUG_FLAG_HOOKED; - else - info->flags &= ~DEBUG_FLAG_HOOKED; -} - - - -/*************************************************************************** - BREAKPOINTS -***************************************************************************/ - /*------------------------------------------------- breakpoint_update_flags - update the CPU's breakpoint flags @@ -1286,115 +2119,6 @@ static void breakpoint_check(running_machine *machine, cpu_debug_data *info, off } -/*------------------------------------------------- - debug_cpu_breakpoint_set - set a new breakpoint --------------------------------------------------*/ - -int debug_cpu_breakpoint_set(const device_config *device, offs_t address, parsed_expression *condition, const char *action) -{ - debugcpu_private *global = device->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(device); - debug_cpu_breakpoint *bp; - - assert_always(device != NULL, "debug_cpu_breakpoint_set() called with invalid cpu!"); - - /* allocate breakpoint */ - bp = malloc_or_die(sizeof(*bp)); - bp->index = global->bpindex++; - bp->enabled = TRUE; - bp->address = address; - bp->condition = condition; - bp->action = NULL; - if (action != NULL) - { - bp->action = malloc_or_die(strlen(action) + 1); - strcpy(bp->action, action); - } - - /* hook us in */ - bp->next = info->bplist; - info->bplist = bp; - - /* ensure the live breakpoint flag is set */ - breakpoint_update_flags(info); - return bp->index; -} - - -/*------------------------------------------------- - debug_cpu_breakpoint_clear - clear a breakpoint --------------------------------------------------*/ - -int debug_cpu_breakpoint_clear(running_machine *machine, int bpnum) -{ - debug_cpu_breakpoint *bp, *pbp; - int cpunum; - - /* loop over CPUs and find the requested breakpoint */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - { - cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); - for (pbp = NULL, bp = info->bplist; bp != NULL; pbp = bp, bp = bp->next) - if (bp->index == bpnum) - { - /* unlink us from the list */ - if (pbp == NULL) - info->bplist = bp->next; - else - pbp->next = bp->next; - - /* free the memory */ - if (bp->condition != NULL) - expression_free(bp->condition); - if (bp->action != NULL) - free(bp->action); - free(bp); - - /* update the flags */ - breakpoint_update_flags(info); - return 1; - } - } - - /* we didn't find it; return an error */ - return 0; -} - - -/*------------------------------------------------- - debug_cpu_breakpoint_enable - enable/disable a - breakpoint --------------------------------------------------*/ - -int debug_cpu_breakpoint_enable(running_machine *machine, int bpnum, int enable) -{ - debug_cpu_breakpoint *bp; - int cpunum; - - /* loop over CPUs and find the requested breakpoint */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - { - cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); - for (bp = info->bplist; bp != NULL; bp = bp->next) - if (bp->index == bpnum) - { - bp->enabled = (enable != 0); - breakpoint_update_flags(info); - return 1; - } - } - - return 0; -} - - - -/*************************************************************************** - WATCHPOINTS -***************************************************************************/ - /*------------------------------------------------- watchpoint_update_flags - update the CPU's watchpoint flags @@ -1510,7 +2234,7 @@ static void watchpoint_check(const address_space *space, int type, offs_t addres else sprintf(buffer, "Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index, sizes[size], cpu_byte_to_address(space->cpu, space->spacenum, address), cpu_get_pc(space->cpu)); debug_console_printf("%s\n", buffer); - compute_debug_flags(info); + compute_debug_flags(space->cpu); } break; } @@ -1519,147 +2243,6 @@ static void watchpoint_check(const address_space *space, int type, offs_t addres } -/*------------------------------------------------- - debug_cpu_watchpoint_set - set a new watchpoint --------------------------------------------------*/ - -int debug_cpu_watchpoint_set(const address_space *space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - debug_cpu_watchpoint *wp = malloc_or_die(sizeof(*wp)); - - /* fill in the structure */ - wp->index = global->wpindex++; - wp->enabled = TRUE; - wp->type = type; - wp->address = ADDR2BYTE_MASKED(address, info, space->spacenum); - wp->length = ADDR2BYTE(length, info, space->spacenum); - wp->condition = condition; - wp->action = NULL; - if (action != NULL) - { - wp->action = malloc_or_die(strlen(action) + 1); - strcpy(wp->action, action); - } - - /* hook us in */ - wp->next = info->space[space->spacenum].wplist; - info->space[space->spacenum].wplist = wp; - - watchpoint_update_flags(space); - - return wp->index; -} - - -/*------------------------------------------------- - debug_cpu_watchpoint_clear - clear a watchpoint --------------------------------------------------*/ - -int debug_cpu_watchpoint_clear(running_machine *machine, int wpnum) -{ - debug_cpu_watchpoint *wp, *pwp; - int cpunum, spacenum; - - /* loop over CPUs and find the requested watchpoint */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - { - cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); - - for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) - for (pwp = NULL, wp = info->space[spacenum].wplist; wp != NULL; pwp = wp, wp = wp->next) - if (wp->index == wpnum) - { - /* unlink us from the list */ - if (pwp == NULL) - info->space[spacenum].wplist = wp->next; - else - pwp->next = wp->next; - - /* free the memory */ - if (wp->condition != NULL) - expression_free(wp->condition); - if (wp->action != NULL) - free(wp->action); - free(wp); - - watchpoint_update_flags(cpu_get_address_space(machine->cpu[cpunum], spacenum)); - return 1; - } - } - - /* we didn't find it; return an error */ - return 0; -} - - -/*------------------------------------------------- - debug_cpu_watchpoint_enable - enable/disable a - watchpoint --------------------------------------------------*/ - -int debug_cpu_watchpoint_enable(running_machine *machine, int wpnum, int enable) -{ - debug_cpu_watchpoint *wp; - int cpunum, spacenum; - - /* loop over CPUs and address spaces and find the requested watchpoint */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - { - cpu_debug_data *info = cpu_get_debug_data(machine->cpu[cpunum]); - - for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++) - for (wp = info->space[spacenum].wplist; wp; wp = wp->next) - if (wp->index == wpnum) - { - wp->enabled = (enable != 0); - watchpoint_update_flags(cpu_get_address_space(machine->cpu[cpunum], spacenum)); - return 1; - } - } - return 0; -} - - - -/*************************************************************************** - HOTSPOTS -***************************************************************************/ - -/*------------------------------------------------- - debug_cpu_hotspot_track - enable/disable tracking - of hotspots --------------------------------------------------*/ - -int debug_cpu_hotspot_track(const device_config *device, int numspots, int threshhold) -{ - cpu_debug_data *info = cpu_get_debug_data(device); - - /* if we already have tracking info, kill it */ - if (info->hotspots) - free(info->hotspots); - info->hotspots = NULL; - - /* only start tracking if we have a non-zero count */ - if (numspots > 0) - { - /* allocate memory for hotspots */ - info->hotspots = malloc_or_die(sizeof(*info->hotspots) * numspots); - memset(info->hotspots, 0xff, sizeof(*info->hotspots) * numspots); - - /* fill in the info */ - info->hotspot_count = numspots; - info->hotspot_threshhold = threshhold; - } - - watchpoint_update_flags(cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM)); - return 1; -} - - /*------------------------------------------------- check_hotspots - check for hotspots on a memory read access @@ -1706,523 +2289,38 @@ static void check_hotspots(const address_space *space, offs_t address) } +/*------------------------------------------------- + dasm_wrapped - wraps calls to the disassembler + by fetching the opcode bytes to a temporary + buffer and then disassembling them +-------------------------------------------------*/ + +static UINT32 dasm_wrapped(const device_config *device, char *buffer, offs_t pc) +{ + const cpu_debug_data *cpuinfo = cpu_get_debug_data(device); + const address_space *space = cpu_get_address_space(device, ADDRESS_SPACE_PROGRAM); + int maxbytes = cpu_get_max_opcode_bytes(device); + UINT8 opbuf[64], argbuf[64]; + offs_t pcbyte; + int numbytes; + + /* fetch the bytes up to the maximum */ + pcbyte = ADDR2BYTE_MASKED(pc, cpuinfo, ADDRESS_SPACE_PROGRAM); + for (numbytes = 0; numbytes < maxbytes; numbytes++) + { + opbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, FALSE); + argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, TRUE); + } + + return cpu_dasm(device, buffer, pc, opbuf, argbuf); +} + + + /*************************************************************************** - MEMORY ACCESSORS + EXPRESSION HANDLERS ***************************************************************************/ -/*------------------------------------------------- - debug_read_byte - return a byte from the - current cpu in the specified memory space --------------------------------------------------*/ - -UINT8 debug_read_byte(const address_space *space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - UINT64 custom; - UINT8 result; - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].logbytemask; - - /* all accesses from this point on are for the debugger */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, return 0xff */ - if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) - result = 0xff; - - /* if there is a custom read handler, and it returns TRUE, use that value */ - else if (info->read != NULL && (*info->read)(space->cpu, space->spacenum, address, 1, &custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = memory_read_byte(space, address); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - return result; -} - - -/*------------------------------------------------- - debug_read_word - return a word from the - current cpu in the specified memory space --------------------------------------------------*/ - -UINT16 debug_read_word(const address_space *space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - UINT64 custom; - UINT16 result; - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) - result = byte0 | (byte1 << 8); - else - result = byte1 | (byte0 << 8); - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, return 0xffff */ - if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) - result = 0xffff; - - /* if there is a custom read handler, and it returns TRUE, use that value */ - else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 2, &custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = memory_read_word(space, address); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - } - - return result; -} - - -/*------------------------------------------------- - debug_read_dword - return a dword from the - current cpu in the specified memory space --------------------------------------------------*/ - -UINT32 debug_read_dword(const address_space *space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - UINT64 custom; - UINT32 result; - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) - result = word0 | (word1 << 16); - else - result = word1 | (word0 << 16); - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, return 0xffffffff */ - if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) - result = 0xffffffff; - - /* if there is a custom read handler, and it returns TRUE, use that value */ - else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 4, &custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = memory_read_dword(space, address); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - } - - return result; -} - - -/*------------------------------------------------- - debug_read_qword - return a qword from the - current cpu in the specified memory space --------------------------------------------------*/ - -UINT64 debug_read_qword(const address_space *space, offs_t address, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - UINT64 custom; - UINT64 result; - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].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 (info->endianness == CPU_IS_LE) - result = dword0 | ((UINT64)dword1 << 32); - else - result = dword1 | ((UINT64)dword0 << 32); - } - - /* otherwise, this proceeds like the byte case */ - else - { - /* all accesses from this point on are for the debugger */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, return 0xffffffffffffffff */ - if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_READ_DEBUG, &address)) - result = ~(UINT64)0; - - /* if there is a custom read handler, and it returns TRUE, use that value */ - else if (info->read && (*info->read)(space->cpu, space->spacenum, address, 8, &custom)) - result = custom; - - /* otherwise, call the byte reading function for the translated address */ - else - result = memory_read_qword(space, address); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - } - - return result; -} - - -/*------------------------------------------------- - debug_write_byte - write a byte to the - current cpu in the specified memory space --------------------------------------------------*/ - -void debug_write_byte(const address_space *space, offs_t address, UINT8 data, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].logbytemask; - - /* all accesses from this point on are for the debugger */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && info->translate != NULL && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns TRUE, use that */ - else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 1, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - memory_write_byte(space, address, data); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - global->memory_modified = TRUE; -} - - -/*------------------------------------------------- - debug_write_word - write a word to the - current cpu in the specified memory space --------------------------------------------------*/ - -void debug_write_word(const address_space *space, offs_t address, UINT16 data, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].logbytemask; - - /* if this is a misaligned write, or if there are no word writers, just read two bytes */ - if ((address & 1) != 0) - { - if (info->endianness == CPU_IS_LE) - { - 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 */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns TRUE, use that */ - else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 2, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - memory_write_word(space, address, data); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - global->memory_modified = TRUE; - } -} - - -/*------------------------------------------------- - debug_write_dword - write a dword to the - current cpu in the specified memory space --------------------------------------------------*/ - -void debug_write_dword(const address_space *space, offs_t address, UINT32 data, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].logbytemask; - - /* if this is a misaligned write, or if there are no dword writers, just read two words */ - if ((address & 3) != 0) - { - if (info->endianness == CPU_IS_LE) - { - 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 */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns TRUE, use that */ - else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 4, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - memory_write_dword(space, address, data); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - global->memory_modified = TRUE; - } -} - - -/*------------------------------------------------- - debug_write_qword - write a qword to the - current cpu in the specified memory space --------------------------------------------------*/ - -void debug_write_qword(const address_space *space, offs_t address, UINT64 data, int apply_translation) -{ - debugcpu_private *global = space->machine->debugcpu_data; - cpu_debug_data *info = cpu_get_debug_data(space->cpu); - - /* mask against the logical byte mask */ - address &= info->space[space->spacenum].logbytemask; - - /* if this is a misaligned write, or if there are no qword writers, just read two dwords */ - if ((address & 7) != 0) - { - if (info->endianness == CPU_IS_LE) - { - 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 */ - memory_set_debugger_access(space, global->debugger_access = TRUE); - - /* translate if necessary; if not mapped, we're done */ - if (apply_translation && info->translate && !(*info->translate)(space->cpu, space->spacenum, TRANSLATE_WRITE_DEBUG, &address)) - ; - - /* if there is a custom write handler, and it returns TRUE, use that */ - else if (info->write && (*info->write)(space->cpu, space->spacenum, address, 8, data)) - ; - - /* otherwise, call the byte reading function for the translated address */ - else - memory_write_qword(space, address, data); - - /* no longer accessing via the debugger */ - memory_set_debugger_access(space, global->debugger_access = FALSE); - global->memory_modified = TRUE; - } -} - - -/*------------------------------------------------- - debug_read_opcode - read 1,2,4 or 8 bytes at - the given offset from opcode space --------------------------------------------------*/ - -UINT64 debug_read_opcode(offs_t address, int size, int arg) -{ - const address_space *space = cpu_get_address_space(Machine->activecpu, ADDRESS_SPACE_PROGRAM); - cpu_debug_data *info = cpu_get_debug_data(Machine->activecpu); - offs_t lowbits_mask; - const void *ptr; - - /* keep in logical range */ - address &= info->space[ADDRESS_SPACE_PROGRAM].logbytemask; - - /* shortcut if we have a custom routine */ - if (info->readop) - { - UINT64 result; - if ((*info->readop)(info->device, address, size, &result)) - return result; - } - - /* if we're bigger than the address bus, break into smaller pieces */ - if (size > info->space[ADDRESS_SPACE_PROGRAM].databytes) - { - int halfsize = size / 2; - UINT64 r0 = debug_read_opcode(address + 0, halfsize, arg); - UINT64 r1 = debug_read_opcode(address + halfsize, halfsize, arg); - - if (info->endianness == CPU_IS_LE) - return r0 | (r1 << (8 * halfsize)); - else - return r1 | (r0 << (8 * halfsize)); - } - - /* translate to physical first */ - if (info->translate && !(*info->translate)(info->device, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH_DEBUG, &address)) - return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size)); - - /* keep in physical range */ - address &= info->space[ADDRESS_SPACE_PROGRAM].physbytemask; - - /* adjust the address */ - change_pc(address); - - switch (info->space[ADDRESS_SPACE_PROGRAM].databytes * 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: - address ^= (info->endianness == CPU_IS_LE) ? 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: - address ^= (info->endianness == CPU_IS_LE) ? BYTE4_XOR_LE(0) : BYTE4_XOR_BE(0); - break; - - /* dump opcodes in words from a dword-sized bus */ - case 42: - address ^= (info->endianness == CPU_IS_LE) ? 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: - address ^= (info->endianness == CPU_IS_LE) ? BYTE8_XOR_LE(0) : BYTE8_XOR_BE(0); - break; - - /* dump opcodes in words from a qword-sized bus */ - case 82: - address ^= (info->endianness == CPU_IS_LE) ? WORD2_XOR_LE(0) : WORD2_XOR_BE(0); - break; - - /* dump opcodes in dwords from a qword-sized bus */ - case 84: - address ^= (info->endianness == CPU_IS_LE) ? 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", info->space[ADDRESS_SPACE_PROGRAM].databytes * 10 + size); - break; - } - - /* get pointer to data */ - /* note that we query aligned to the bus width, and then add back the low bits */ - lowbits_mask = info->space[ADDRESS_SPACE_PROGRAM].databytes - 1; - if (!arg) - ptr = memory_decrypted_read_ptr(space, address & ~lowbits_mask); - else - ptr = memory_raw_read_ptr(space, address & ~lowbits_mask); - if (ptr == NULL) - return ~(UINT64)0 & (~(UINT64)0 >> (64 - 8*size)); - ptr = (UINT8 *)ptr + (address & lowbits_mask); - - /* return based on the size */ - switch (size) - { - case 1: return *(UINT8 *) ptr; - case 2: return *(UINT16 *)ptr; - case 4: return *(UINT32 *)ptr; - case 8: return *(UINT64 *)ptr; - } - - return 0; /* appease compiler */ -} - - /*------------------------------------------------- expression_cpu_index - return the CPU index based on a case insensitive tag search @@ -2745,73 +2843,6 @@ static EXPRERR expression_validate(void *param, const char *name, int space) } -/*------------------------------------------------- - debug_cpu_trace_printf - writes text to a given - CPU's trace file --------------------------------------------------*/ - -void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) -{ - va_list va; - - cpu_debug_data *info = cpu_get_debug_data(device); - - if (info->trace.file) - { - va_start(va, fmt); - vfprintf(info->trace.file, fmt, va); - va_end(va); - } -} - - -/*------------------------------------------------- - debug_cpu_source_script - specifies a debug command - script to use --------------------------------------------------*/ - -void debug_cpu_source_script(running_machine *machine, const char *file) -{ - if (debug_source_file) - { - fclose(debug_source_file); - debug_source_file = NULL; - } - - if (file) - { - debug_source_file = fopen(file, "r"); - if (!debug_source_file) - { - if (mame_get_phase(machine) == MAME_PHASE_RUNNING) - debug_console_printf("Cannot open command file '%s'\n", file); - else - fatalerror("Cannot open command file '%s'", file); - } - } -} - - -/*------------------------------------------------- - debug_cpu_flush_traces - flushes all traces; this is - useful if a trace is going on when we fatalerror --------------------------------------------------*/ - -void debug_cpu_flush_traces(void) -{ - int cpunum; - - if (Machine != NULL) - for (cpunum = 0; cpunum < ARRAY_LENGTH(Machine->cpu); cpunum++) - if (Machine->cpu[cpunum] != NULL) - { - cpu_debug_data *info = cpu_get_debug_data(Machine->cpu[cpunum]); - if (info->trace.file != NULL) - fflush(info->trace.file); - } -} - - /*************************************************************************** VARIABLE GETTERS/SETTERS @@ -2822,10 +2853,10 @@ void debug_cpu_flush_traces(void) 'wpaddr' symbol -------------------------------------------------*/ -static UINT64 get_wpaddr(void *ref) +static UINT64 get_wpaddr(void *globalref, void *ref) { - debugcpu_private *global = Machine->debugcpu_data; - return global->wpaddr; + running_machine *machine = globalref; + return machine->debugcpu_data->wpaddr; } @@ -2834,21 +2865,10 @@ static UINT64 get_wpaddr(void *ref) 'wpdata' symbol -------------------------------------------------*/ -static UINT64 get_wpdata(void *ref) +static UINT64 get_wpdata(void *globalref, void *ref) { - debugcpu_private *global = Machine->debugcpu_data; - return global->wpdata; -} - - -/*------------------------------------------------- - get_cycles - getter callback for the - 'cycles' symbol --------------------------------------------------*/ - -static UINT64 get_cycles(void *ref) -{ - return *cpu_get_icount_ptr(Machine->activecpu); + running_machine *machine = globalref; + return machine->debugcpu_data->wpdata; } @@ -2857,9 +2877,10 @@ static UINT64 get_cycles(void *ref) 'cpunum' symbol -------------------------------------------------*/ -static UINT64 get_cpunum(void *ref) +static UINT64 get_cpunum(void *globalref, void *ref) { - return cpunum_get_active(); + running_machine *machine = globalref; + return cpu_get_index(machine->debugcpu_data->visiblecpu); } @@ -2868,7 +2889,7 @@ static UINT64 get_cpunum(void *ref) 'tempX' symbols -------------------------------------------------*/ -static UINT64 get_tempvar(void *ref) +static UINT64 get_tempvar(void *globalref, void *ref) { return *(UINT64 *)ref; } @@ -2879,37 +2900,20 @@ static UINT64 get_tempvar(void *ref) 'tempX' symbols -------------------------------------------------*/ -static void set_tempvar(void *ref, UINT64 value) +static void set_tempvar(void *globalref, void *ref, UINT64 value) { *(UINT64 *)ref = value; } -/*------------------------------------------------- - get_logunmap - getter callback for the logumap - symbols --------------------------------------------------*/ - -static UINT64 get_logunmap(void *ref) -{ - const address_space *space = cpu_get_address_space(Machine->activecpu, (FPTR)ref); - return (space != NULL) ? memory_get_log_unmap(space) : TRUE; -} - - /*------------------------------------------------- get_beamx - get beam horizontal position -------------------------------------------------*/ -static UINT64 get_beamx(void *ref) +static UINT64 get_beamx(void *globalref, void *ref) { - UINT64 ret = 0; - const device_config *screen = device_list_find_by_index(Machine->config->devicelist, VIDEO_SCREEN, 0); - - if (screen != NULL) - ret = video_screen_get_hpos(screen); - - return ret; + const device_config *screen = ref; + return (screen != NULL) ? video_screen_get_hpos(screen) : 0; } @@ -2917,15 +2921,10 @@ static UINT64 get_beamx(void *ref) get_beamy - get beam vertical position -------------------------------------------------*/ -static UINT64 get_beamy(void *ref) +static UINT64 get_beamy(void *globalref, void *ref) { - UINT64 ret = 0; - const device_config *screen = device_list_find_by_index(Machine->config->devicelist, VIDEO_SCREEN, 0); - - if (screen != NULL) - ret = video_screen_get_vpos(screen); - - return ret; + const device_config *screen = ref; + return (screen != NULL) ? video_screen_get_vpos(screen) : 0; } @@ -2933,28 +2932,10 @@ static UINT64 get_beamy(void *ref) get_frame - get current frame number -------------------------------------------------*/ -static UINT64 get_frame(void *ref) +static UINT64 get_frame(void *globalref, void *ref) { - UINT64 ret = 0; - const device_config *screen = device_list_find_by_index(Machine->config->devicelist, VIDEO_SCREEN, 0); - - if (screen != NULL) - ret = video_screen_get_frame_number(screen); - - return ret; -} - - -/*------------------------------------------------- - set_logunmap - setter callback for the logumap - symbols --------------------------------------------------*/ - -static void set_logunmap(void *ref, UINT64 value) -{ - const address_space *space = cpu_get_address_space(Machine->activecpu, (FPTR)ref); - if (space != NULL) - memory_set_log_unmap(space, value ? 1 : 0); + const device_config *screen = ref; + return (screen != NULL) ? video_screen_get_frame_number(screen) : 0; } @@ -2963,10 +2944,47 @@ static void set_logunmap(void *ref, UINT64 value) current instruction pointer -------------------------------------------------*/ -static UINT64 get_current_pc(void *ref) +static UINT64 get_current_pc(void *globalref, void *ref) { - cpu_debug_data *info = ref; - return cpu_get_pc(info->device); + const device_config *device = globalref; + return cpu_get_pc(device); +} + + +/*------------------------------------------------- + get_cycles - getter callback for the + 'cycles' symbol +-------------------------------------------------*/ + +static UINT64 get_cycles(void *globalref, void *ref) +{ + const device_config *device = globalref; + return *cpu_get_icount_ptr(device); +} + + +/*------------------------------------------------- + get_logunmap - getter callback for the logumap + symbols +-------------------------------------------------*/ + +static UINT64 get_logunmap(void *globalref, void *ref) +{ + const address_space *space = ref; + return (space != NULL) ? memory_get_log_unmap(space) : TRUE; +} + + +/*------------------------------------------------- + set_logunmap - setter callback for the logumap + symbols +-------------------------------------------------*/ + +static void set_logunmap(void *globalref, void *ref, UINT64 value) +{ + const address_space *space = ref; + if (space != NULL) + memory_set_log_unmap(space, value ? 1 : 0); } @@ -2975,9 +2993,10 @@ static UINT64 get_current_pc(void *ref) register symbols -------------------------------------------------*/ -static UINT64 get_cpu_reg(void *ref) +static UINT64 get_cpu_reg(void *globalref, void *ref) { - return cpu_get_reg(Machine->activecpu, (FPTR)ref); + const device_config *device = globalref; + return cpu_get_reg(device, (FPTR)ref); } @@ -2986,7 +3005,8 @@ static UINT64 get_cpu_reg(void *ref) register symbols -------------------------------------------------*/ -static void set_cpu_reg(void *ref, UINT64 value) +static void set_cpu_reg(void *globalref, void *ref, UINT64 value) { - cpu_set_reg(Machine->activecpu, (FPTR)ref, value); + const device_config *device = globalref; + cpu_set_reg(device, (FPTR)ref, value); } diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h index 90800f56c4e..fcd648ac7a8 100644 --- a/src/emu/debug/debugcpu.h +++ b/src/emu/debug/debugcpu.h @@ -185,7 +185,6 @@ struct _debug_cpu_watchpoint GLOBAL VARIABLES ***************************************************************************/ -extern FILE *debug_source_file; extern const express_callbacks debug_expression_callbacks; @@ -194,14 +193,31 @@ extern const express_callbacks debug_expression_callbacks; FUNCTION PROTOTYPES ***************************************************************************/ -/* ----- initialization ----- */ +/* ----- initialization and cleanup ----- */ /* initialize the CPU tracking for the debugger */ void debug_cpu_init(running_machine *machine); +/* flushes all traces; this is useful if a trace is going on when we fatalerror */ +void debug_cpu_flush_traces(running_machine *machine); + + + +/* ----- debugging status & information ----- */ + /* return the visible CPU device (the one that commands should apply to) */ const device_config *debug_cpu_get_visible_cpu(running_machine *machine); +/* TRUE if the debugger is currently stopped within an instruction hook callback */ +int debug_cpu_within_instruction_hook(running_machine *machine); + +/* return TRUE if the current execution state is stopped */ +int debug_cpu_is_stopped(running_machine *machine); + + + +/* ----- symbol table interfaces ----- */ + /* return the global symbol table */ symbol_table *debug_cpu_get_global_symtable(running_machine *machine); @@ -238,54 +254,115 @@ void debug_cpu_memory_write_hook(const address_space *space, offs_t address, UIN -/* ----- core debugger functions ----- */ +/* ----- execution control ----- */ -int debug_cpu_within_instruction_hook(running_machine *machine); -void debug_cpu_halt_on_next_instruction(running_machine *machine, int cpunum, const char *fmt, ...) ATTR_PRINTF(3,4); -int debug_cpu_is_stopped(running_machine *machine); -void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3); -void debug_cpu_source_script(running_machine *machine, const char *file); -void debug_cpu_flush_traces(void); +/* halt in the debugger on the next instruction */ +void debug_cpu_halt_on_next_instruction(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3); -/* debugging hooks */ -void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook); +/* ignore/observe a given CPU */ +void debug_cpu_ignore_cpu(const device_config *cpu, int ignore); -/* execution control */ -void debug_cpu_single_step(int numsteps); -void debug_cpu_single_step_over(int numsteps); -void debug_cpu_single_step_out(void); -void debug_cpu_go(offs_t targetpc); -void debug_cpu_go_vblank(void); -void debug_cpu_go_interrupt(int irqline); -void debug_cpu_go_milliseconds(UINT64 milliseconds); -void debug_cpu_next_cpu(void); -void debug_cpu_ignore_cpu(const device_config *cpu, int ignore); +/* single step the visible CPU past the requested number of instructions */ +void debug_cpu_single_step(running_machine *machine, int numsteps); -/* tracing support */ -void debug_cpu_trace(const device_config *device, FILE *file, int trace_over, const char *action); +/* single step the visible over the requested number of instructions */ +void debug_cpu_single_step_over(running_machine *machine, int numsteps); -/* breakpoints */ +/* single step the visible CPU out of the current function */ +void debug_cpu_single_step_out(running_machine *machine); + +/* execute the visible CPU until it hits the given address */ +void debug_cpu_go(running_machine *machine, offs_t targetpc); + +/* execute until the next VBLANK */ +void debug_cpu_go_vblank(running_machine *machine); + +/* execute until the specified interrupt fires on the visible CPU */ +void debug_cpu_go_interrupt(running_machine *machine, int irqline); + +/* execute until the specified exception fires on the visible CPU */ +void debug_cpu_go_exception(running_machine *machine, int exception); + +/* execute until the specified delay elapses */ +void debug_cpu_go_milliseconds(running_machine *machine, UINT64 milliseconds); + +/* execute until we hit the next CPU */ +void debug_cpu_next_cpu(running_machine *machine); + + + +/* ----- breakpoints ----- */ + +/* set a new breakpoint, returning its index */ int debug_cpu_breakpoint_set(const device_config *device, offs_t address, parsed_expression *condition, const char *action); + +/* clear a breakpoint by index */ int debug_cpu_breakpoint_clear(running_machine *machine, int bpnum); + +/* enable/disable a breakpoint by index */ int debug_cpu_breakpoint_enable(running_machine *machine, int bpnum, int enable); -/* watchpoints */ + + +/* ----- watchpoints ----- */ + +/* set a new watchpoint, returning its index */ int debug_cpu_watchpoint_set(const address_space *space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action); + +/* clear a watchpoint by index */ int debug_cpu_watchpoint_clear(running_machine *machine, int wpnum); + +/* enable/disable a watchpoint by index */ int debug_cpu_watchpoint_enable(running_machine *machine, int wpnum, int enable); + + +/* ----- misc debugger functions ----- */ + +/* specifies a debug command script to execute */ +void debug_cpu_source_script(running_machine *machine, const char *file); + +/* trace execution of a given CPU */ +void debug_cpu_trace(const device_config *device, FILE *file, int trace_over, const char *action); + +/* output data into the given CPU's tracefile, if tracing */ +void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3); + +/* set a hook to be called on each instruction for a given CPU */ +void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook); + /* hotspots */ int debug_cpu_hotspot_track(const device_config *device, int numspots, int threshhold); -/* memory accessors */ -UINT8 debug_read_byte(const address_space *space, offs_t address, int apply_translation); -UINT16 debug_read_word(const address_space *space, offs_t address, int apply_translation); -UINT32 debug_read_dword(const address_space *space, offs_t address, int apply_translation); -UINT64 debug_read_qword(const address_space *space, offs_t address, int apply_translation); -void debug_write_byte(const address_space *space, offs_t address, UINT8 data, int apply_translation); -void debug_write_word(const address_space *space, offs_t address, UINT16 data, int apply_translation); -void debug_write_dword(const address_space *space, offs_t address, UINT32 data, int apply_translation); -void debug_write_qword(const address_space *space, offs_t address, UINT64 data, int apply_translation); -UINT64 debug_read_opcode(UINT32 offset, int size, int arg); + + +/* ----- debugger memory accessors ----- */ + +/* return a byte from the the specified memory space */ +UINT8 debug_read_byte(const address_space *space, offs_t address, int apply_translation); + +/* return a word from the the specified memory space */ +UINT16 debug_read_word(const address_space *space, offs_t address, int apply_translation); + +/* return a dword from the the specified memory space */ +UINT32 debug_read_dword(const address_space *space, offs_t address, int apply_translation); + +/* return a qword from the the specified memory space */ +UINT64 debug_read_qword(const address_space *space, offs_t address, int apply_translation); + +/* write a byte to the specified memory space */ +void debug_write_byte(const address_space *space, offs_t address, UINT8 data, int apply_translation); + +/* write a word to the specified memory space */ +void debug_write_word(const address_space *space, offs_t address, UINT16 data, int apply_translation); + +/* write a dword to the specified memory space */ +void debug_write_dword(const address_space *space, offs_t address, UINT32 data, int apply_translation); + +/* write a qword to the specified memory space */ +void debug_write_qword(const address_space *space, offs_t address, UINT64 data, int apply_translation); + +/* read 1,2,4 or 8 bytes at the given offset from opcode space */ +UINT64 debug_read_opcode(const address_space *space, offs_t offset, int size, int arg); #endif diff --git a/src/emu/debug/debugvw.c b/src/emu/debug/debugvw.c index 3dae5441030..1567d118dd3 100644 --- a/src/emu/debug/debugvw.c +++ b/src/emu/debug/debugvw.c @@ -1327,8 +1327,9 @@ static void disasm_free(debug_view *view) static offs_t disasm_back_up(int cpunum, const cpu_debug_data *cpuinfo, offs_t startpc, int numinstrs) { - int minlen = BYTE2ADDR(cpu_get_min_opcode_bytes(Machine->activecpu), cpuinfo, ADDRESS_SPACE_PROGRAM); - int maxlen = BYTE2ADDR(cpu_get_max_opcode_bytes(Machine->activecpu), cpuinfo, ADDRESS_SPACE_PROGRAM); + int minlen = BYTE2ADDR(cpu_get_min_opcode_bytes(cpuinfo->device), cpuinfo, ADDRESS_SPACE_PROGRAM); + int maxlen = BYTE2ADDR(cpu_get_max_opcode_bytes(cpuinfo->device), cpuinfo, ADDRESS_SPACE_PROGRAM); + const address_space *space = cpu_get_address_space(cpuinfo->device, ADDRESS_SPACE_PROGRAM); UINT32 addrmask = cpuinfo->space[ADDRESS_SPACE_PROGRAM].logaddrmask; offs_t curpc, lastgoodpc = startpc, temppc; UINT8 opbuf[1024], argbuf[1024]; @@ -1346,8 +1347,8 @@ static offs_t disasm_back_up(int cpunum, const cpu_debug_data *cpuinfo, offs_t s /* prefetch the opcode bytes */ for (temppc = curpc; temppc < startpc; temppc++) { - opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE); - argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE); + opbuf[1000 + temppc - startpc] = debug_read_opcode(space, temppc, 1, FALSE); + argbuf[1000 + temppc - startpc] = debug_read_opcode(space, temppc, 1, TRUE); } /* loop until we hit it */ @@ -1364,7 +1365,7 @@ static offs_t disasm_back_up(int cpunum, const cpu_debug_data *cpuinfo, offs_t s /* get the disassembly, but only if mapped */ instlen = 1; if (cpuinfo->translate == NULL || (*cpuinfo->translate)(cpuinfo->device, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH_DEBUG, &pcbyte)) - instlen = cpu_dasm(Machine->activecpu, dasmbuffer, testpc & addrmask, &opbuf[1000 + testpc - startpc], &argbuf[1000 + testpc - startpc]) & DASMFLAG_LENGTHMASK; + instlen = cpu_dasm(cpuinfo->device, dasmbuffer, testpc & addrmask, &opbuf[1000 + testpc - startpc], &argbuf[1000 + testpc - startpc]) & DASMFLAG_LENGTHMASK; /* count this one */ instcount++; @@ -1390,8 +1391,8 @@ static offs_t disasm_back_up(int cpunum, const cpu_debug_data *cpuinfo, offs_t s /* prefetch the opcode bytes */ for (temppc = nextcurpc; temppc < curpc; temppc++) { - opbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, FALSE); - argbuf[1000 + temppc - startpc] = debug_read_opcode(temppc, 1, TRUE); + opbuf[1000 + temppc - startpc] = debug_read_opcode(space, temppc, 1, FALSE); + argbuf[1000 + temppc - startpc] = debug_read_opcode(space, temppc, 1, TRUE); } /* update curpc once we're done fetching */ @@ -1409,6 +1410,7 @@ static offs_t disasm_back_up(int cpunum, const cpu_debug_data *cpuinfo, offs_t s static void disasm_generate_bytes(offs_t pcbyte, int numbytes, const cpu_debug_data *cpuinfo, int minbytes, char *string, int maxchars, int encrypted) { + const address_space *space = cpu_get_address_space(cpuinfo->device, ADDRESS_SPACE_PROGRAM); int byte, offset = 0; UINT64 val; @@ -1416,32 +1418,32 @@ static void disasm_generate_bytes(offs_t pcbyte, int numbytes, const cpu_debug_d { case 1: if (maxchars >= 2) - offset = sprintf(string, "%02X", (UINT32)debug_read_opcode(pcbyte, 1, FALSE)); + offset = sprintf(string, "%02X", (UINT32)debug_read_opcode(space, pcbyte, 1, FALSE)); for (byte = 1; byte < numbytes && offset + 3 < maxchars; byte++) - offset += sprintf(&string[offset], " %02X", (UINT32)debug_read_opcode(pcbyte + byte, 1, encrypted)); + offset += sprintf(&string[offset], " %02X", (UINT32)debug_read_opcode(space, pcbyte + byte, 1, encrypted)); break; case 2: if (maxchars >= 4) - offset = sprintf(string, "%04X", (UINT32)debug_read_opcode(pcbyte, 2, FALSE)); + offset = sprintf(string, "%04X", (UINT32)debug_read_opcode(space, pcbyte, 2, FALSE)); for (byte = 2; byte < numbytes && offset + 5 < maxchars; byte += 2) - offset += sprintf(&string[offset], " %04X", (UINT32)debug_read_opcode(pcbyte + byte, 2, encrypted)); + offset += sprintf(&string[offset], " %04X", (UINT32)debug_read_opcode(space, pcbyte + byte, 2, encrypted)); break; case 4: if (maxchars >= 8) - offset = sprintf(string, "%08X", (UINT32)debug_read_opcode(pcbyte, 4, FALSE)); + offset = sprintf(string, "%08X", (UINT32)debug_read_opcode(space, pcbyte, 4, FALSE)); for (byte = 4; byte < numbytes && offset + 9 < maxchars; byte += 4) - offset += sprintf(&string[offset], " %08X", (UINT32)debug_read_opcode(pcbyte + byte, 4, encrypted)); + offset += sprintf(&string[offset], " %08X", (UINT32)debug_read_opcode(space, pcbyte + byte, 4, encrypted)); break; case 8: - val = debug_read_opcode(pcbyte, 8, FALSE); + val = debug_read_opcode(space, pcbyte, 8, FALSE); if (maxchars >= 16) offset = sprintf(string, "%08X%08X", (UINT32)(val >> 32), (UINT32)val); for (byte = 8; byte < numbytes && offset + 17 < maxchars; byte += 8) { - val = debug_read_opcode(pcbyte + byte, 8, encrypted); + val = debug_read_opcode(space, pcbyte + byte, 8, encrypted); offset += sprintf(&string[offset], " %08X%08X", (UINT32)(val >> 32), (UINT32)val); } break; @@ -1483,13 +1485,13 @@ static int disasm_recompute(debug_view *view, offs_t pc, int startline, int line dasmdata->divider2 = dasmdata->divider1 + 1 + dasmdata->dasm_width + 1; /* determine how many bytes we might need to display */ - minbytes = cpu_get_min_opcode_bytes(Machine->activecpu); - maxbytes = cpu_get_max_opcode_bytes(Machine->activecpu); + minbytes = cpu_get_min_opcode_bytes(cpuinfo->device); + maxbytes = cpu_get_max_opcode_bytes(cpuinfo->device); /* set the width of the third column according to display mode */ if (dasmdata->right_column == DVP_DASM_RIGHTCOL_RAW || dasmdata->right_column == DVP_DASM_RIGHTCOL_ENCRYPTED) { - chunksize = cpu_get_databus_width(Machine->activecpu, ADDRESS_SPACE_PROGRAM) / 8; + chunksize = cpu_get_databus_width(cpuinfo->device, ADDRESS_SPACE_PROGRAM) / 8; maxbytes_clamped = maxbytes; if (maxbytes_clamped > DASM_MAX_BYTES) maxbytes_clamped = DASM_MAX_BYTES; @@ -1548,12 +1550,12 @@ static int disasm_recompute(debug_view *view, offs_t pc, int startline, int line /* fetch the bytes up to the maximum */ for (numbytes = 0; numbytes < maxbytes; numbytes++) { - opbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, FALSE); - argbuf[numbytes] = debug_read_opcode(pcbyte + numbytes, 1, TRUE); + opbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, FALSE); + argbuf[numbytes] = debug_read_opcode(space, pcbyte + numbytes, 1, TRUE); } /* disassemble the result */ - pc += numbytes = cpu_dasm(Machine->activecpu, buffer, pc & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK; + pc += numbytes = cpu_dasm(cpuinfo->device, buffer, pc & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK; } else sprintf(buffer, ""); @@ -1571,7 +1573,7 @@ static int disasm_recompute(debug_view *view, offs_t pc, int startline, int line offs_t comment_address = BYTE2ADDR(dasmdata->address[instr], cpuinfo, ADDRESS_SPACE_PROGRAM) ; /* get and add the comment */ - if (debug_comment_get_text(Machine->activecpu, comment_address, debug_comment_get_opcode_crc32(Machine->activecpu, comment_address)) != 0x00) + if (debug_comment_get_text(cpuinfo->device, comment_address, debug_comment_get_opcode_crc32(cpuinfo->device, comment_address)) != 0x00) { int i ; char bob[DEBUG_COMMENT_MAX_LINE_LENGTH] ; @@ -1583,7 +1585,7 @@ static int disasm_recompute(debug_view *view, offs_t pc, int startline, int line destbuf[dasmdata->divider2+i] = pre[i] ; // Stick in the comment itself - strcpy(bob, debug_comment_get_text(Machine->activecpu, comment_address, debug_comment_get_opcode_crc32(Machine->activecpu, comment_address))) ; + strcpy(bob, debug_comment_get_text(cpuinfo->device, comment_address, debug_comment_get_opcode_crc32(cpuinfo->device, comment_address))) ; for (i = 0; i < (dasmdata->allocated_cols - dasmdata->divider2 - strlen(pre) - 1); i++) destbuf[dasmdata->divider2+i+strlen(pre)] = bob[i] ; } @@ -1598,7 +1600,7 @@ static int disasm_recompute(debug_view *view, offs_t pc, int startline, int line /* reset the opcode base */ if (dasmdata->cpunum == original_cpunum) - change_pc(cpu_get_physical_pc_byte(Machine->activecpu)); + change_pc(cpu_get_physical_pc_byte(cpuinfo->device)); /* update opcode base information */ dasmdata->last_direct_decrypted = space->direct.decrypted; diff --git a/src/emu/debug/express.c b/src/emu/debug/express.c index c638c910d28..ccba47c0547 100644 --- a/src/emu/debug/express.c +++ b/src/emu/debug/express.c @@ -184,6 +184,7 @@ struct _internal_symbol_entry struct _symbol_table { symbol_table * parent; /* pointer to the parent symbol table */ + void * globalref; /* global reference parameter */ internal_symbol_entry * hash[SYM_TABLE_HASH_SIZE]; /* hash table */ }; @@ -336,7 +337,7 @@ INLINE EXPRERR pop_token_rval(parsed_expression *expr, parse_token *token, const return MAKE_EXPRERR_NOT_RVAL(token->offset); token->type = TOK_NUMBER; if (symbol->type == SMT_REGISTER) - token->value.i = (*symbol->info.reg.getter)(symbol->ref); + token->value.i = (*symbol->info.reg.getter)(symbol->table->globalref, symbol->ref); else token->value.i = symbol->info.gen.value; } @@ -372,7 +373,7 @@ INLINE UINT64 get_lval_value(parsed_expression *expr, parse_token *token, const { symbol_entry *symbol = token->value.p; if (symbol != NULL && symbol->type == SMT_REGISTER) - return (*symbol->info.reg.getter)(symbol->ref); + return (*symbol->info.reg.getter)(symbol->table->globalref, symbol->ref); } else if (token->type == TOK_MEMORY) { @@ -397,7 +398,7 @@ INLINE void set_lval_value(parsed_expression *expr, parse_token *token, const sy { symbol_entry *symbol = token->value.p; if (symbol != NULL && symbol->type == SMT_REGISTER && symbol->info.reg.setter) - (*symbol->info.reg.setter)(symbol->ref, value); + (*symbol->info.reg.setter)(symbol->table->globalref, symbol->ref, value); } else if (token->type == TOK_MEMORY) { @@ -1233,7 +1234,7 @@ static EXPRERR execute_function(parsed_expression *expr, parse_token *token) /* execute the function and push the result */ t1.type = TOK_NUMBER; t1.offset = token->offset; - t1.value.i = (*symbol->info.func.execute)(symbol->ref, paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount]); + t1.value.i = (*symbol->info.func.execute)(symbol->table->globalref, symbol->ref, paramcount, &funcparams[MAX_FUNCTION_PARAMS - paramcount]); push_token(expr, &t1); return EXPRERR_NONE; @@ -1910,7 +1911,7 @@ INLINE UINT32 hash_string(const char *string) symtable_alloc - allocate a symbol table -------------------------------------------------*/ -symbol_table *symtable_alloc(symbol_table *parent) +symbol_table *symtable_alloc(symbol_table *parent, void *globalref) { symbol_table *table; @@ -1922,10 +1923,22 @@ symbol_table *symtable_alloc(symbol_table *parent) /* initialize the data */ memset(table, 0, sizeof(*table)); table->parent = parent; + table->globalref = globalref; return table; } +/*------------------------------------------------- + symtable_get_globalref - return the globalref + value for a given symtable +-------------------------------------------------*/ + +void *symtable_get_globalref(symbol_table *table) +{ + return table->globalref; +} + + /*------------------------------------------------- symtable_add - add a new symbol to a symbol table @@ -1982,6 +1995,7 @@ int symtable_add(symbol_table *table, const char *name, const symbol_entry *entr /* fill in the details */ symbol->name = newstring; symbol->entry = *entry; + symbol->entry.table = table; /* add the entry to the hash table */ hash_index = hash_string(newstring) % SYM_TABLE_HASH_SIZE; @@ -1996,11 +2010,11 @@ int symtable_add(symbol_table *table, const char *name, const symbol_entry *entr register symbol to a symbol table -------------------------------------------------*/ -int symtable_add_register(symbol_table *table, const char *name, void *ref, symbol_getter_func getter, symbol_setter_func setter) +int symtable_add_register(symbol_table *table, const char *name, void *symref, symbol_getter_func getter, symbol_setter_func setter) { symbol_entry symbol; - symbol.ref = ref; + symbol.ref = symref; symbol.type = SMT_REGISTER; symbol.info.reg.getter = getter; symbol.info.reg.setter = setter; @@ -2013,11 +2027,11 @@ int symtable_add_register(symbol_table *table, const char *name, void *ref, symb function symbol to a symbol table -------------------------------------------------*/ -int symtable_add_function(symbol_table *table, const char *name, void *ref, UINT16 minparams, UINT16 maxparams, function_execute_func execute) +int symtable_add_function(symbol_table *table, const char *name, void *symref, UINT16 minparams, UINT16 maxparams, function_execute_func execute) { symbol_entry symbol; - symbol.ref = ref; + symbol.ref = symref; symbol.type = SMT_FUNCTION; symbol.info.func.minparams = minparams; symbol.info.func.maxparams = maxparams; diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h index 39c03e095e5..176fd13b3b2 100644 --- a/src/emu/debug/express.h +++ b/src/emu/debug/express.h @@ -97,11 +97,11 @@ typedef UINT32 EXPRERR; /* callback functions for getting/setting a symbol value */ -typedef UINT64 (*symbol_getter_func)(void *ref); -typedef void (*symbol_setter_func)(void *ref, UINT64 value); +typedef UINT64 (*symbol_getter_func)(void *globalref, void *symref); +typedef void (*symbol_setter_func)(void *globalref, void *symref, UINT64 value); /* callback function for execution a function */ -typedef UINT64 (*function_execute_func)(void *ref, UINT32 numparams, const UINT64 *paramlist); +typedef UINT64 (*function_execute_func)(void *globalref, void *symref, UINT32 numparams, const UINT64 *paramlist); /* callback function for memory reads/writes */ typedef UINT64 (*express_read_func)(void *cbparam, const char *name, int space, UINT32 offset, int size); @@ -119,11 +119,16 @@ struct _express_callbacks }; +/* symbol_table is an opaque structure for holding a collection of symbols */ +typedef struct _symbol_table symbol_table; + + /* symbol_entry describes a symbol in a symbol table */ typedef struct _symbol_entry symbol_entry; struct _symbol_entry { void * ref; /* internal reference */ + symbol_table * table; /* pointer back to the owning table */ UINT32 type; /* type of symbol */ union { @@ -152,10 +157,6 @@ struct _symbol_entry }; -/* symbol_table is an opaque structure for holding a collection of symbols */ -typedef struct _symbol_table symbol_table; - - /* parsed_expression is an opaque structure for holding a pre-parsed expression */ typedef struct _parsed_expression parsed_expression; @@ -174,10 +175,11 @@ const char * expression_original_string(parsed_expression *expr); const char * exprerr_to_string(EXPRERR error); /* symbol table manipulation */ -symbol_table * symtable_alloc(symbol_table *parent); +symbol_table * symtable_alloc(symbol_table *parent, void *globalref); +void * symtable_get_globalref(symbol_table *table); int symtable_add(symbol_table *table, const char *name, const symbol_entry *entry); -int symtable_add_register(symbol_table *table, const char *name, void *ref, symbol_getter_func getter, symbol_setter_func setter); -int symtable_add_function(symbol_table *table, const char *name, void *ref, UINT16 minparams, UINT16 maxparams, function_execute_func execute); +int symtable_add_register(symbol_table *table, const char *name, void *symref, symbol_getter_func getter, symbol_setter_func setter); +int symtable_add_function(symbol_table *table, const char *name, void *symref, UINT16 minparams, UINT16 maxparams, function_execute_func execute); int symtable_add_value(symbol_table *table, const char *name, UINT64 value); const symbol_entry * symtable_find(const symbol_table *table, const char *name); const char * symtable_find_indexed(const symbol_table *table, int index, const symbol_entry **entry); diff --git a/src/emu/debugger.c b/src/emu/debugger.c index 214ce135d44..3ec7cae249c 100644 --- a/src/emu/debugger.c +++ b/src/emu/debugger.c @@ -21,6 +21,14 @@ +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void debugger_flush_traces(void); + + + /*************************************************************************** CENTRAL INITIALIZATION POINT ***************************************************************************/ @@ -39,7 +47,7 @@ void debugger_init(running_machine *machine) debug_console_init(machine); debug_view_init(machine); debug_comment_init(machine); - atexit(debug_cpu_flush_traces); + atexit(debugger_flush_traces); add_logerror_callback(machine, debug_errorlog_write_line); } } @@ -56,3 +64,14 @@ void debugger_refresh_display(running_machine *machine) } +/*------------------------------------------------- + debugger_flush_traces - flush any traces in + the event of an aborted execution +-------------------------------------------------*/ + +static void debugger_flush_traces(void) +{ + extern running_machine *Machine; + if (Machine != NULL) + debug_cpu_flush_traces(Machine); +} diff --git a/src/emu/debugger.h b/src/emu/debugger.h index 37e5c3fad87..d7135caca3d 100644 --- a/src/emu/debugger.h +++ b/src/emu/debugger.h @@ -117,7 +117,7 @@ INLINE void debugger_interrupt_hook(const device_config *device, int irqline) INLINE void debugger_break(running_machine *machine) { if ((machine->debug_flags & DEBUG_FLAG_ENABLED) != 0) - debug_cpu_halt_on_next_instruction(machine, cpunum_get_active(), "Internal breakpoint\n"); + debug_cpu_halt_on_next_instruction(debug_cpu_get_visible_cpu(machine), "Internal breakpoint\n"); } diff --git a/src/mame/machine/fddebug.c b/src/mame/machine/fddebug.c index 18427e142cf..217993f6dca 100644 --- a/src/mame/machine/fddebug.c +++ b/src/mame/machine/fddebug.c @@ -949,7 +949,7 @@ static void execute_fdignore(running_machine *machine, int ref, int params, cons /* if no parameter given, implicitly run as well */ if (params == 0) - debug_cpu_go(~0); + debug_cpu_go(machine, ~0); } diff --git a/src/osd/windows/debugwin.c b/src/osd/windows/debugwin.c index 87c74e253f1..d9470e317fc 100644 --- a/src/osd/windows/debugwin.c +++ b/src/osd/windows/debugwin.c @@ -494,7 +494,7 @@ void debugwin_update_during_game(running_machine *machine) HWND focuswnd = GetFocus(); debugwin_info *info; - debug_cpu_halt_on_next_instruction(machine, -1, "User-initiated break\n"); + debug_cpu_halt_on_next_instruction(debug_cpu_get_visible_cpu(machine), "User-initiated break\n"); // if we were focused on some window's edit box, reset it to default for (info = window_list; info; info = info->next) @@ -778,7 +778,7 @@ static LRESULT CALLBACK debug_window_proc(HWND wnd, UINT message, WPARAM wparam, if (main_console && main_console->wnd == wnd) { smart_show_all(FALSE); - debug_cpu_go(~0); + debug_cpu_go(info->machine, ~0); } else DestroyWindow(wnd); @@ -2767,7 +2767,7 @@ static void console_process_string(debugwin_info *info, const char *string) // an empty string is a single step if (string[0] == 0) - debug_cpu_single_step(1); + debug_cpu_single_step(info->machine, 1); // otherwise, just process the command else @@ -2870,31 +2870,31 @@ static int global_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lpar case ID_RUN_AND_HIDE: smart_show_all(FALSE); case ID_RUN: - debug_cpu_go(~0); + debug_cpu_go(info->machine, ~0); return 1; case ID_NEXT_CPU: - debug_cpu_next_cpu(); + debug_cpu_next_cpu(info->machine); return 1; case ID_RUN_VBLANK: - debug_cpu_go_vblank(); + debug_cpu_go_vblank(info->machine); return 1; case ID_RUN_IRQ: - debug_cpu_go_interrupt(-1); + debug_cpu_go_interrupt(info->machine, -1); return 1; case ID_STEP: - debug_cpu_single_step(1); + debug_cpu_single_step(info->machine, 1); return 1; case ID_STEP_OVER: - debug_cpu_single_step_over(1); + debug_cpu_single_step_over(info->machine, 1); return 1; case ID_STEP_OUT: - debug_cpu_single_step_out(); + debug_cpu_single_step_out(info->machine); return 1; case ID_HARD_RESET: @@ -2903,7 +2903,7 @@ static int global_handle_command(debugwin_info *info, WPARAM wparam, LPARAM lpar case ID_SOFT_RESET: mame_schedule_soft_reset(info->machine); - debug_cpu_go(~0); + debug_cpu_go(info->machine, ~0); return 1; case ID_EXIT: diff --git a/src/osd/windows/winmain.c b/src/osd/windows/winmain.c index c21186648f2..11e681c1fb0 100644 --- a/src/osd/windows/winmain.c +++ b/src/osd/windows/winmain.c @@ -455,7 +455,11 @@ static LONG CALLBACK exception_filter(struct _EXCEPTION_POINTERS *info) already_hit = 1; // flush any debugging traces that were live - debug_cpu_flush_traces(); + { + extern running_machine *Machine; + if (Machine != NULL) + debug_cpu_flush_traces(Machine); + } // find our man for (i = 0; exception_table[i].code != 0; i++)