diff options
Diffstat (limited to 'src/emu/debug')
-rw-r--r-- | src/emu/debug/debugcmd.cpp | 29 | ||||
-rw-r--r-- | src/emu/debug/debugcmd.h | 1 | ||||
-rw-r--r-- | src/emu/debug/debugcpu.cpp | 98 | ||||
-rw-r--r-- | src/emu/debug/debughlp.cpp | 16 | ||||
-rw-r--r-- | src/emu/debug/dvdisasm.cpp | 8 | ||||
-rw-r--r-- | src/emu/debug/dvmemory.cpp | 57 | ||||
-rw-r--r-- | src/emu/debug/dvmemory.h | 1 |
7 files changed, 121 insertions, 89 deletions
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index 38bff17b8c4..1b48be30e1f 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -206,6 +206,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu m_console.register_command("stateload", CMDFLAG_NONE, 0, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1, _2)); m_console.register_command("sl", CMDFLAG_NONE, 0, 1, 1, std::bind(&debugger_commands::execute_stateload, this, _1, _2)); + m_console.register_command("rewind", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_rewind, this, _1, _2)); + m_console.register_command("rw", CMDFLAG_NONE, 0, 0, 0, std::bind(&debugger_commands::execute_rewind, this, _1, _2)); + m_console.register_command("save", CMDFLAG_NONE, AS_PROGRAM, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2)); m_console.register_command("saved", CMDFLAG_NONE, AS_DATA, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2)); m_console.register_command("savei", CMDFLAG_NONE, AS_IO, 3, 4, std::bind(&debugger_commands::execute_save, this, _1, _2)); @@ -1627,7 +1630,7 @@ void debugger_commands::execute_stateload(int ref, const std::vector<std::string const std::string &filename(params[0]); m_machine.immediate_load(filename.c_str()); - // Clear all PC & memory tracks + // clear all PC & memory tracks for (device_t &device : device_iterator(m_machine.root_device())) { device.debug()->track_pc_data_clear(); @@ -1638,6 +1641,30 @@ void debugger_commands::execute_stateload(int ref, const std::vector<std::string /*------------------------------------------------- + execute_rewind - execute the rewind command +-------------------------------------------------*/ + +void debugger_commands::execute_rewind(int ref, const std::vector<std::string> ¶ms) +{ + if (!m_machine.save().rewind()->enabled()) + { + m_console.printf("Rewind not enabled\n"); + return; + } + + m_machine.rewind_step(); + + // clear all PC & memory tracks + for (device_t &device : device_iterator(m_machine.root_device())) + { + device.debug()->track_pc_data_clear(); + device.debug()->track_mem_data_clear(); + } + m_console.printf("Rewind step attempted. Please refer to window message popup for results.\n"); +} + + +/*------------------------------------------------- execute_save - execute the save command -------------------------------------------------*/ diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h index 98b6d8ae03d..41405ec0a71 100644 --- a/src/emu/debug/debugcmd.h +++ b/src/emu/debug/debugcmd.h @@ -131,6 +131,7 @@ private: void execute_hotspot(int ref, const std::vector<std::string> ¶ms); void execute_statesave(int ref, const std::vector<std::string> ¶ms); void execute_stateload(int ref, const std::vector<std::string> ¶ms); + void execute_rewind(int ref, const std::vector<std::string> ¶ms); void execute_save(int ref, const std::vector<std::string> ¶ms); void execute_load(int ref, const std::vector<std::string> ¶ms); void execute_dump(int ref, const std::vector<std::string> ¶ms); diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp index eab6f7771e7..17c26191186 100644 --- a/src/emu/debug/debugcpu.cpp +++ b/src/emu/debug/debugcpu.cpp @@ -389,34 +389,20 @@ u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_tran u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_translation) { + device_memory_interface &memory = space.device().memory(); + /* mask against the logical byte mask */ address &= space.logaddrmask(); u16 result; - if (!WORD_ALIGNED(address)) - { /* if this is misaligned read, or if there are no word readers, just read two bytes */ - u8 byte0 = read_byte(space, address + 0, apply_translation); - u8 byte1 = read_byte(space, address + 1, apply_translation); - - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = byte0 | (byte1 << 8); - else - result = byte1 | (byte0 << 8); + /* translate if necessary; if not mapped, return 0xffff */ + if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + { + result = 0xffff; } else - { /* otherwise, this proceeds like the byte case */ - device_memory_interface &memory = space.device().memory(); - - /* translate if necessary; if not mapped, return 0xffff */ - if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - { - result = 0xffff; - } - else - { /* otherwise, call the byte reading function for the translated address */ - result = space.read_word(address); - } + { /* otherwise, call the byte reading function for the translated address */ + result = space.read_word_unaligned(address); } return result; @@ -430,33 +416,20 @@ u16 debugger_cpu::read_word(address_space &space, offs_t address, bool apply_tra u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_translation) { + device_memory_interface &memory = space.device().memory(); + /* mask against the logical byte mask */ address &= space.logaddrmask(); u32 result; - if (!DWORD_ALIGNED(address)) - { /* if this is a misaligned read, or if there are no dword readers, just read two words */ - u16 word0 = read_word(space, address + 0, apply_translation); - u16 word1 = read_word(space, address + 2, apply_translation); - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = word0 | (word1 << 16); - else - result = word1 | (word0 << 16); + if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + { /* translate if necessary; if not mapped, return 0xffffffff */ + result = 0xffffffff; } else - { /* otherwise, this proceeds like the byte case */ - device_memory_interface &memory = space.device().memory(); - - if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - { /* translate if necessary; if not mapped, return 0xffffffff */ - result = 0xffffffff; - } - else - { /* otherwise, call the byte reading function for the translated address */ - result = space.read_dword(address); - } + { /* otherwise, call the byte reading function for the translated address */ + result = space.read_dword_unaligned(address); } return result; @@ -470,34 +443,21 @@ u32 debugger_cpu::read_dword(address_space &space, offs_t address, bool apply_tr u64 debugger_cpu::read_qword(address_space &space, offs_t address, bool apply_translation) { + device_memory_interface &memory = space.device().memory(); + /* mask against the logical byte mask */ address &= space.logaddrmask(); u64 result; - if (!QWORD_ALIGNED(address)) - { /* if this is a misaligned read, or if there are no qword readers, just read two dwords */ - u32 dword0 = read_dword(space, address + 0, apply_translation); - u32 dword1 = read_dword(space, address + 4, apply_translation); - /* based on the endianness, the result is assembled differently */ - if (space.endianness() == ENDIANNESS_LITTLE) - result = dword0 | (u64(dword1) << 32); - else - result = dword1 | (u64(dword0) << 32); + /* translate if necessary; if not mapped, return 0xffffffffffffffff */ + if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) + { + result = ~u64(0); } else - { /* otherwise, this proceeds like the byte case */ - device_memory_interface &memory = space.device().memory(); - - /* translate if necessary; if not mapped, return 0xffffffffffffffff */ - if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_READ_DEBUG, address)) - { - result = ~u64(0); - } - else - { /* otherwise, call the byte reading function for the translated address */ - result = space.read_qword(address); - } + { /* otherwise, call the byte reading function for the translated address */ + result = space.read_qword_unaligned(address); } return result; @@ -1902,6 +1862,7 @@ void device_debug::single_step(int numsteps) { assert(m_exec != nullptr); + m_device.machine().rewind_capture(); m_stepsleft = numsteps; m_stepaddr = ~0; m_flags |= DEBUG_FLAG_STEPPING; @@ -1918,6 +1879,7 @@ void device_debug::single_step_over(int numsteps) { assert(m_exec != nullptr); + m_device.machine().rewind_capture(); m_stepsleft = numsteps; m_stepaddr = ~0; m_flags |= DEBUG_FLAG_STEPPING_OVER; @@ -1934,6 +1896,7 @@ void device_debug::single_step_out() { assert(m_exec != nullptr); + m_device.machine().rewind_capture(); m_stepsleft = 100; m_stepaddr = ~0; m_flags |= DEBUG_FLAG_STEPPING_OUT; @@ -1950,6 +1913,7 @@ void device_debug::go(offs_t targetpc) { assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); m_stopaddr = targetpc; m_flags |= DEBUG_FLAG_STOP_PC; m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING); @@ -1964,6 +1928,7 @@ void device_debug::go_vblank() { assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); m_flags |= DEBUG_FLAG_STOP_VBLANK; m_device.machine().debugger().cpu().go_vblank(); } @@ -1978,6 +1943,7 @@ void device_debug::go_interrupt(int irqline) { assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); m_stopirq = irqline; m_flags |= DEBUG_FLAG_STOP_INTERRUPT; m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING); @@ -1997,6 +1963,7 @@ void device_debug::go_exception(int exception) { assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); m_stopexception = exception; m_flags |= DEBUG_FLAG_STOP_EXCEPTION; m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING); @@ -2012,6 +1979,7 @@ void device_debug::go_milliseconds(u64 milliseconds) { assert(m_exec != nullptr); + m_device.machine().rewind_invalidate(); m_stoptime = m_device.machine().time() + attotime::from_msec(milliseconds); m_flags |= DEBUG_FLAG_STOP_TIME; m_device.machine().debugger().cpu().set_execution_state(EXECUTION_STATE_RUNNING); @@ -2822,14 +2790,14 @@ void debugger_cpu::watchpoint_check(address_space& space, int type, offs_t addre if (type & WATCHPOINT_WRITE) { - buffer = string_format("Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index(), sizes[size], space.byte_to_address(address), pc); + buffer = string_format("Stopped at watchpoint %X writing %s to %08X (PC=%X)", wp->index(), sizes[size], address, pc); if (value_to_write >> 32) buffer.append(string_format(" (data=%X%08X)", u32(value_to_write >> 32), u32(value_to_write))); else buffer.append(string_format(" (data=%X)", u32(value_to_write))); } else - buffer = string_format("Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index(), sizes[size], space.byte_to_address(address), pc); + buffer = string_format("Stopped at watchpoint %X reading %s from %08X (PC=%X)", wp->index(), sizes[size], address, pc); m_machine.debugger().console().printf("%s\n", buffer.c_str()); space.device().debug()->compute_debug_flags(); } diff --git a/src/emu/debug/debughlp.cpp b/src/emu/debug/debughlp.cpp index 2848f970003..f25d52b3ae7 100644 --- a/src/emu/debug/debughlp.cpp +++ b/src/emu/debug/debughlp.cpp @@ -94,6 +94,7 @@ static const help_item static_help_list[] = " pcatmemd <address>[,<cpu>] -- query which PC wrote to a given data memory address for the current CPU\n" " pcatmemi <address>[,<cpu>] -- query which PC wrote to a given I/O memory address for the current CPU\n" " (Note: you can also query this info by right clicking in a memory window\n" + " rewind[rw] -- go back in time by loading the most recent rewind state" " statesave[ss] <filename> -- save a state file for the current driver\n" " stateload[sl] <filename> -- load a state file for the current driver\n" " snap [<filename>] -- save a screen snapshot.\n" @@ -455,6 +456,19 @@ static const help_item static_help_list[] = " Print which PC wrote this CPU's memory location 0x400000.\n" }, { + "rewind[rw]", + "\n" + " rewind[rw]" + "\n" + "The rewind command loads the most recent RAM-based state. Rewind states, when enabled, are " + "saved when \"step\", \"over\", or \"out\" command gets executed, storing the machine state as " + "of the moment before actually stepping. Consecutively loading rewind states can work like " + "reverse execution. Depending on which steps forward were taken previously, the bahavior can " + "be similar to GDB's \"reverse-stepi\" or \"reverse-next\". All output for this command is " + "currently echoed into the running machine window. Previous memory and PC tracking statistics " + "are cleared, actual reverse execution does not occur.\n" + }, + { "statesave[ss]", "\n" " statesave[ss] <filename>\n" @@ -472,7 +486,7 @@ static const help_item static_help_list[] = { "stateload[sl]", "\n" - " stateload[ss] <filename>\n" + " stateload[sl] <filename>\n" "\n" "The stateload command retrieves a save state from disk. " "The given state file gets read from the standard state directory (sta), and gets .sta to it - " diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp index 2292e766132..8084251c7b1 100644 --- a/src/emu/debug/dvdisasm.cpp +++ b/src/emu/debug/dvdisasm.cpp @@ -321,7 +321,7 @@ void debug_view_disasm::generate_dasm(debug_disasm_buffer &buffer, offs_t pc) if(pos != -1) { if(!pc_changed) return; - if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y) + if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y - 2) return; if(pos < m_total.y - m_visible.y) { m_topleft.x = 0; @@ -566,6 +566,8 @@ void debug_view_disasm::set_selected_address(offs_t address) void debug_view_disasm::set_source(const debug_view_source &source) { - debug_view::set_source(source); - m_dasm.clear(); + if(&source != m_source) { + debug_view::set_source(source); + m_dasm.clear(); + } } diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp index e32d576fa65..13297dbe7b9 100644 --- a/src/emu/debug/dvmemory.cpp +++ b/src/emu/debug/dvmemory.cpp @@ -98,6 +98,7 @@ debug_view_memory::debug_view_memory(running_machine &machine, debug_view_osd_up m_expression(machine), m_chunks_per_row(16), m_bytes_per_chunk(1), + m_steps_per_chunk(1), m_data_format(1), m_reverse_view(false), m_ascii_view(true), @@ -197,6 +198,7 @@ void debug_view_memory::view_notify(debug_view_notification type) if (m_bytes_per_chunk > 8) m_bytes_per_chunk = 8; m_data_format = m_bytes_per_chunk; + m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; if (source.m_space != nullptr) m_expression.set_context(&source.m_space->device().debug()->symtable()); else @@ -290,7 +292,8 @@ void debug_view_memory::view_update() if (dest >= destmin && dest < destmax) dest->byte = addrtext[ch]; - // generate the data + // generate the data and the ascii string + std::string chunkascii; for (int chunknum = 0; chunknum < m_chunks_per_row; chunknum++) { int chunkindex = m_reverse_view ? (m_chunks_per_row - 1 - chunknum) : chunknum; @@ -298,7 +301,7 @@ void debug_view_memory::view_update() if (m_data_format <= 8) { u64 chunkdata; - bool ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata); + bool ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; for (int ch = 0; ch < posdata.m_spacing; ch++, dest++) if (dest >= destmin && dest < destmax) @@ -307,6 +310,10 @@ void debug_view_memory::view_update() if (shift < 64) dest->byte = ismapped ? "0123456789ABCDEF"[(chunkdata >> shift) & 0x0f] : '*'; } + for (int i=0; i < m_bytes_per_chunk; i++) { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + } } else { int ch; @@ -316,9 +323,9 @@ void debug_view_memory::view_update() bool ismapped; if (m_data_format != 11) - ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata); + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata); else - ismapped = read(m_bytes_per_chunk, addrbyte + chunknum * m_bytes_per_chunk, chunkdata80); + ismapped = read(m_bytes_per_chunk, address + chunknum * m_steps_per_chunk, chunkdata80); if (ismapped) switch (m_data_format) @@ -338,6 +345,7 @@ void debug_view_memory::view_update() valuetext[0] = '*'; valuetext[1] = 0; } + dest = destrow + m_section[1].m_pos + 1 + chunkindex * spacing; // first copy the text for (ch = 0; (ch < spacing) && (valuetext[ch] != 0); ch++, dest++) @@ -347,20 +355,23 @@ void debug_view_memory::view_update() for (; ch < spacing; ch++, dest++) if (dest >= destmin && dest < destmax) dest->byte = ' '; + + for (int i=0; i < m_bytes_per_chunk; i++) { + u8 chval = chunkdata >> (8 * (m_bytes_per_chunk - i - 1)); + chunkascii += char((ismapped && isprint(chval)) ? chval : '.'); + } } } - // generate the ASCII data + // generate the ASCII data, but follow the chunks if (m_section[2].m_width > 0) { dest = destrow + m_section[2].m_pos + 1; - for (int ch = 0; ch < m_bytes_per_row; ch++, dest++) + for (size_t i = 0; i != chunkascii.size(); i++) { if (dest >= destmin && dest < destmax) - { - u64 chval; - bool ismapped = read(1, addrbyte + ch, chval); - dest->byte = (ismapped && isprint(chval)) ? chval : '.'; - } + dest->byte = chunkascii[i]; + dest++; + } } } } @@ -563,7 +574,10 @@ void debug_view_memory::recompute() // recompute the byte offset based on the most recent expression result m_bytes_per_row = m_bytes_per_chunk * m_chunks_per_row; - m_byte_offset = m_expression.value() % m_bytes_per_row; + offs_t val = m_expression.value(); + if (source.m_space) + val = source.m_space->address_to_byte(val); + m_byte_offset = val % m_bytes_per_row; // compute the section widths m_section[0].m_width = 1 + 8 + 1; @@ -612,17 +626,20 @@ bool debug_view_memory::needs_recompute() // handle expression changes if (m_expression.dirty()) { + const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); + offs_t val = m_expression.value(); + if (source.m_space) + val = source.m_space->address_to_byte(val); recompute = true; - m_topleft.y = (m_expression.value() - m_byte_offset) / m_bytes_per_row; + m_topleft.y = (val - m_byte_offset) / m_bytes_per_row; m_topleft.y = std::max(m_topleft.y, 0); m_topleft.y = std::min(m_topleft.y, m_total.y - 1); - const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); offs_t resultbyte; if (source.m_space != nullptr) - resultbyte = m_expression.value() & source.m_space->logaddrmask(); + resultbyte = val & source.m_space->logaddrmask(); else - resultbyte = m_expression.value(); + resultbyte = val; set_cursor_pos(cursor_pos(resultbyte, m_bytes_per_chunk * 8 - 4)); } @@ -740,7 +757,7 @@ bool debug_view_memory::read(u8 size, offs_t offs, u64 &data) const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); // if no raw data, just use the standard debug routines - if (source.m_space != nullptr) + if (source.m_space) { auto dis = machine().disable_side_effect(); @@ -823,7 +840,7 @@ void debug_view_memory::write(u8 size, offs_t offs, u64 data) const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); // if no raw data, just use the standard debug routines - if (source.m_space != nullptr) + if (source.m_space) { auto dis = machine().disable_side_effect(); @@ -919,13 +936,14 @@ void debug_view_memory::set_data_format(int format) return; pos = begin_update_and_get_cursor_pos(); + const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); if ((format <= 8) && (m_data_format <= 8)) { - const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source); pos.m_address += (pos.m_shift / 8) ^ ((source.m_endianness == ENDIANNESS_LITTLE) ? 0 : (m_bytes_per_chunk - 1)); pos.m_shift %= 8; m_bytes_per_chunk = format; + m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; m_chunks_per_row = m_bytes_per_row / format; if (m_chunks_per_row < 1) m_chunks_per_row = 1; @@ -958,6 +976,7 @@ void debug_view_memory::set_data_format(int format) } } m_chunks_per_row = m_bytes_per_row / m_bytes_per_chunk; + m_steps_per_chunk = source.m_space ? source.m_space->byte_to_address(m_bytes_per_chunk) : m_bytes_per_chunk; pos.m_shift = 0; pos.m_address -= pos.m_address % m_bytes_per_chunk; } diff --git a/src/emu/debug/dvmemory.h b/src/emu/debug/dvmemory.h index 1927e030d2b..c354b644053 100644 --- a/src/emu/debug/dvmemory.h +++ b/src/emu/debug/dvmemory.h @@ -107,6 +107,7 @@ private: debug_view_expression m_expression; // expression describing the start address u32 m_chunks_per_row; // number of chunks displayed per line u8 m_bytes_per_chunk; // bytes per chunk + u8 m_steps_per_chunk; // bytes per chunk int m_data_format; // 1-8 current values 9 32bit floating point bool m_reverse_view; // reverse-endian view? bool m_ascii_view; // display ASCII characters? |