summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugbuf.cpp
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2017-07-05 11:44:49 +0200
committer Olivier Galibert <galibert@pobox.com>2017-11-26 17:41:27 +0100
commit6caef2579a1490f05d28bcede731cbdd45fc5c65 (patch)
tree8055384e183be3cb27e7d0894ac53dc96c09e6fa /src/emu/debug/debugbuf.cpp
parent34b222062c89adbeed822f56be6130421777e11f (diff)
dvdisasm: Overhaul [O. Galibert]
Disassemblers are now independant classes. Not only the code is cleaner, but unidasm has access to all the cpu cores again. The interface to the disassembly method has changed from byte buffers to objects that give a result to read methods. This also adds support for lfsr and/or paged PCs.
Diffstat (limited to 'src/emu/debug/debugbuf.cpp')
-rw-r--r--src/emu/debug/debugbuf.cpp1381
1 files changed, 1381 insertions, 0 deletions
diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp
new file mode 100644
index 00000000000..96392f60bf5
--- /dev/null
+++ b/src/emu/debug/debugbuf.cpp
@@ -0,0 +1,1381 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Buffering interface for the disassembly windows
+
+#include "emu.h"
+#include "debugbuf.h"
+
+debug_disasm_buffer::debug_data_buffer::debug_data_buffer(util::disasm_interface *intf) : m_intf(intf)
+{
+ m_space = nullptr;
+ m_back = nullptr;
+ m_opcode = true;
+ m_lstart = m_lend = 0;
+ m_wrapped = false;
+}
+
+bool debug_disasm_buffer::debug_data_buffer::active() const
+{
+ return m_space || m_back;
+}
+
+void debug_disasm_buffer::debug_data_buffer::set_source(address_space &space)
+{
+ m_space = &space;
+ setup_methods();
+}
+
+void debug_disasm_buffer::debug_data_buffer::set_source(debug_data_buffer &back, bool opcode)
+{
+ m_back = &back;
+ m_opcode = opcode;
+ setup_methods();
+}
+
+u8 debug_disasm_buffer::debug_data_buffer::r8 (offs_t pc) const
+{
+ return m_do_r8(pc);
+}
+
+u16 debug_disasm_buffer::debug_data_buffer::r16(offs_t pc) const
+{
+ return m_do_r16(pc);
+}
+
+u32 debug_disasm_buffer::debug_data_buffer::r32(offs_t pc) const
+{
+ return m_do_r32(pc);
+}
+
+u64 debug_disasm_buffer::debug_data_buffer::r64(offs_t pc) const
+{
+ return m_do_r64(pc);
+}
+
+address_space *debug_disasm_buffer::debug_data_buffer::get_underlying_space() const
+{
+ return m_space;
+}
+
+void debug_disasm_buffer::debug_data_buffer::fill(offs_t lstart, offs_t size) const
+{
+ offs_t lend = (lstart + size) & m_pc_mask;
+ if(m_page_mask) {
+ if((lstart ^ lend) & ~m_page_mask) {
+ lstart = lstart & ~m_page_mask;
+ lend = (((lend - 1) | m_page_mask) + 1) & m_pc_mask;
+ }
+ }
+
+ if(!m_buffer.empty()) {
+ if(m_wrapped) {
+ if(lstart >= m_lstart && (lend > m_lstart || lend <= m_lend))
+ return;
+ if(lstart < m_lend && lend <= m_lend)
+ return;
+ } else {
+ if(m_lend && lstart >= m_lstart && lend <= m_lend)
+ return;
+ if(!m_lend && lstart >= m_lstart)
+ return;
+ if(m_lstart == m_lend)
+ return;
+ }
+ }
+
+ if(m_buffer.empty()) {
+ m_lstart = lstart;
+ m_lend = lend;
+ m_wrapped = lend < lstart;
+ offs_t size = m_pc_delta_to_bytes((lend - lstart) & m_pc_mask);
+ m_buffer.resize(size);
+ m_do_fill(lstart, lend);
+
+ } else {
+ offs_t n_lstart, n_lend;
+ if(lstart > lend) {
+ if(m_wrapped) {
+ // Old is wrapped, new is wrapped, just extend
+ n_lstart = std::min(m_lstart, lstart);
+ n_lend = std::max(m_lend, lend);
+ } else {
+ // Old is unwrapped, new is wrapped. Reduce the amount of "useless" data.
+ offs_t gap_post = m_lend >= lstart ? 0 : lstart - m_lend;
+ offs_t gap_pre = m_lstart <= lend ? 0 : m_lstart - lend;
+ if(gap_post < gap_pre) {
+ // extend the old one end until it reaches the new one
+ n_lstart = std::min(m_lstart, lstart);
+ n_lend = lend;
+ } else {
+ // extend the old one start until it reaches the new one
+ n_lstart = lstart;
+ n_lend = std::max(m_lend, lend);
+ }
+ m_wrapped = true;
+ }
+ } else if(m_wrapped) {
+ // Old is wrapped, new is unwrapped. Reduce the amount of "useless" data.
+ offs_t gap_post = m_lend >= lstart ? 0 : lstart - m_lend;
+ offs_t gap_pre = m_lstart <= lend ? 0 : m_lstart - lend;
+ if(gap_post < gap_pre) {
+ // extend the old one end until it reaches the new one
+ n_lstart = m_lstart;
+ n_lend = lend;
+ } else {
+ // extend the old one start until it reaches the new one
+ n_lstart = lstart;
+ n_lend = m_lend;
+ }
+ } else {
+ // Both are unwrapped, decide whether to wrap.
+ // If there's overlap, don't wrap, just extend
+ if(lend >= m_lstart && lstart < m_lend) {
+ n_lstart = std::min(m_lstart, lstart);
+ n_lend = std::max(m_lend, lend);
+ } else {
+ // If there's no overlap, compute the gap with wrapping or without
+ offs_t gap_unwrapped = lstart > m_lstart ? lstart - m_lend : m_lstart - lend;
+ offs_t gap_wrapped = lstart > m_lstart ? (m_lstart - lend) & m_pc_mask : (lstart - m_lend) & m_pc_mask;
+ if(gap_unwrapped < gap_wrapped) {
+ n_lstart = std::min(m_lstart, lstart);
+ n_lend = std::max(m_lend, lend);
+ } else {
+ n_lstart = std::max(m_lstart, lstart);
+ n_lend = std::min(m_lend, lend);
+ m_wrapped = true;
+ }
+ }
+ }
+
+ if(n_lstart != m_lstart) {
+ offs_t size = m_pc_delta_to_bytes((m_lstart - n_lstart) & m_pc_mask);
+ m_buffer.insert(m_buffer.begin(), size, 0);
+ offs_t old_lstart = m_lstart;
+ m_lstart = n_lstart;
+ m_do_fill(m_lstart, old_lstart);
+ }
+ if(n_lend != m_lend) {
+ offs_t size = m_pc_delta_to_bytes((n_lend - m_lstart) & m_pc_mask);
+ m_buffer.resize(size);
+ offs_t old_lend = m_lend;
+ m_lend = n_lend;
+ m_do_fill(old_lend, m_lend);
+ }
+ }
+}
+
+std::string debug_disasm_buffer::debug_data_buffer::data_to_string(offs_t pc, offs_t size) const
+{
+ return m_data_to_string(pc, size);
+}
+
+void debug_disasm_buffer::debug_data_buffer::data_get(offs_t pc, offs_t size, std::vector<u8> &data) const
+{
+ return m_data_get(pc, size, data);
+}
+
+void debug_disasm_buffer::debug_data_buffer::setup_methods()
+{
+ address_space *space = m_space ? m_space : m_back->get_underlying_space();
+ int shift = space->addrbus_shift();
+ int alignment = m_intf->opcode_alignment();
+ endianness_t endian = space->endianness();
+
+ m_pc_mask = space->logaddrmask();
+
+ if(m_intf->interface_flags() & util::disasm_interface::PAGED)
+ m_page_mask = (1 << m_intf->page_address_bits()) - 1;
+ else
+ m_page_mask = 0;
+
+ // Define the byte counter
+ switch(shift) {
+ case -3: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 3; }; break;
+ case -2: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 2; }; break;
+ case -1: m_pc_delta_to_bytes = [](offs_t delta) { return delta << 1; }; break;
+ case 0: m_pc_delta_to_bytes = [](offs_t delta) { return delta; }; break;
+ case 3: m_pc_delta_to_bytes = [](offs_t delta) { return delta >> 3; }; break;
+ default: throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer::setup_methods: Abnormal address buf shift\n");
+ }
+
+ // Define the filler
+ if(m_space) {
+ // get the data from given space
+ if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) {
+ switch(shift) {
+ case -1:
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = m_intf->pc_linear_to_real(lpc);
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_word(tpc << 1);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+ case 0:
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u8 *dest = get_ptr<u8>(lstart);
+ u32 steps = 0;
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = m_intf->pc_linear_to_real(lpc);
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_byte(tpc);
+ else
+ *dest++ = 0;
+ steps++;
+ }
+ };
+ break;
+ }
+
+ } else {
+ switch(shift) {
+ case -3: // bus granularity 64
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u64 *dest = get_ptr<u64>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = lpc;
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_qword(tpc << 3);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+
+ case -2: // bus granularity 32
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u32 *dest = get_ptr<u32>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = lpc;
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_dword(tpc << 2);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+
+ case -1: // bus granularity 16
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = lpc;
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_word(tpc << 1);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+
+ case 0: // bus granularity 8
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask) {
+ offs_t tpc = lpc;
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_byte(tpc);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+
+ case 3: // bus granularity 1, stored as u16
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ auto dis = m_space->machine().disable_side_effect();
+ u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask) {
+ offs_t tpc = lpc;
+ if (m_space->device().memory().translate(m_space->spacenum(), TRANSLATE_FETCH_DEBUG, tpc))
+ *dest++ = m_space->read_word(tpc >> 3);
+ else
+ *dest++ = 0;
+ }
+ };
+ break;
+ }
+ }
+ } else {
+ // get the data from a back buffer and decrypt it through the device
+ // size chosen is alignment * granularity
+ assert(!(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC));
+
+ switch(shift) {
+ case -3: // bus granularity 64, endianness irrelevant
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u64 *dest = get_ptr<u64>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask)
+ *dest++ = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ };
+ break;
+
+ case -2: // bus granularity 32
+ switch(alignment) {
+ case 1: // bus granularity 32, alignment 32, endianness irrelevant
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u32 *dest = get_ptr<u32>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask)
+ *dest++ = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode);
+ };
+ break;
+
+ case 2: // bus granularity 32, alignment 64
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 32, alignment 64, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u32 *dest = get_ptr<u32>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 32;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 32, bus width 64, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u32 *dest = get_ptr<u32>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val >> 32;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+ }
+ break;
+
+ case -1: // bus granularity 16
+ switch(alignment) {
+ case 1: // bus granularity 16, alignment 16, endianness irrelevant
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask)
+ *dest++ = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode);
+ };
+ break;
+
+ case 2: // bus granularity 16, alignment 32
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 16, alignment 32, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 16;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 16, alignment 32, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode);
+ *dest++ = val >> 16;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+
+ case 4: // bus granularity 16, alignment 64
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 16, alignment 64, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 16;
+ *dest++ = val >> 32;
+ *dest++ = val >> 48;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 16, alignment 64, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = get_ptr<u16>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val >> 48;
+ *dest++ = val >> 32;
+ *dest++ = val >> 16;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 0: // bus granularity 8
+ switch(alignment) {
+ case 1: // bus granularity 8, alignment 8, endianness irrelevant
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 1) & m_pc_mask)
+ *dest++ = m_intf->decrypt8(m_back->r8(lpc), lpc, m_opcode);
+ };
+ break;
+
+ case 2: // bus granularity 8, alignment 16
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 8, alignment 16, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u16 val = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 8;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 16, alignment 16, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u16 val = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode);
+ *dest++ = val >> 8;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+
+ case 4: // bus granularity 8, alignment 32
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 8, alignment 16, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) {
+ u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 8;
+ *dest++ = val >> 16;
+ *dest++ = val >> 24;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 16, alignment 32, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 4) & m_pc_mask) {
+ u32 val = m_intf->decrypt32(m_back->r32(lpc), lpc, m_opcode);
+ *dest++ = val >> 24;
+ *dest++ = val >> 16;
+ *dest++ = val >> 8;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+
+
+ case 8: // bus granularity 8, alignment 64
+ switch(endian) {
+ case ENDIANNESS_LITTLE: // bus granularity 8, alignment 64, little endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 8) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val;
+ *dest++ = val >> 8;
+ *dest++ = val >> 16;
+ *dest++ = val >> 24;
+ *dest++ = val >> 32;
+ *dest++ = val >> 40;
+ *dest++ = val >> 48;
+ *dest++ = val >> 56;
+ }
+ };
+ break;
+
+ case ENDIANNESS_BIG: // bus granularity 8, alignment 64, big endian
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u8 *dest = get_ptr<u8>(lstart);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 2) & m_pc_mask) {
+ u64 val = m_intf->decrypt64(m_back->r64(lpc), lpc, m_opcode);
+ *dest++ = val >> 56;
+ *dest++ = val >> 48;
+ *dest++ = val >> 40;
+ *dest++ = val >> 32;
+ *dest++ = val >> 24;
+ *dest++ = val >> 16;
+ *dest++ = val >> 8;
+ *dest++ = val;
+ }
+ };
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 3: // bus granularity 1, alignment 16, little endian (bit addressing, stored as u16, tms3401x)
+ assert(alignment == 16);
+ assert(endian == ENDIANNESS_LITTLE);
+ m_do_fill = [this](offs_t lstart, offs_t lend) {
+ u16 *dest = reinterpret_cast<u16 *>(&m_buffer[0]) + ((lstart - m_lstart) >> 4);
+ for(offs_t lpc = lstart; lpc != lend; lpc = (lpc + 0x10) & m_pc_mask)
+ *dest++ = m_intf->decrypt16(m_back->r16(lpc), lpc, m_opcode);
+ };
+ break;
+ }
+ }
+
+ // Define the accessors
+ if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) {
+ switch(shift) {
+ case -1:
+ m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 16-bits granularity bus\n"); };
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 1);
+ const u16 *src = get_ptr<u16>(lpc);
+ return src[0];
+ };
+
+ switch(endian) {
+ case ENDIANNESS_LITTLE:
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 2);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u16>(lpc) << (j*16);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 4);
+ u64 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= u64(get<u16>(lpc)) << (j*16);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ break;
+
+ case ENDIANNESS_BIG:
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 2);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u16>(lpc) << ((1-j)*16);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 4);
+ u64 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= u64(get<u16>(lpc)) << ((3-j)*16);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ break;
+ }
+ break;
+
+ case 0:
+ m_do_r8 = [this](offs_t pc) -> u8 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 1);
+ const u8 *src = get_ptr<u8>(lpc);
+ return src[0];
+ };
+
+ switch(endian) {
+ case ENDIANNESS_LITTLE:
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 2);
+ u16 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(lpc) << (j*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 4);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(lpc) << (j*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 8);
+ u64 r = 0;
+ for(int j=0; j != 8; j++) {
+ r |= u64(get<u8>(lpc)) << (j*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ break;
+
+ case ENDIANNESS_BIG:
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 2);
+ u16 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(lpc) << ((1-j)*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 4);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(lpc) << ((3-j)*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ fill(lpc, 8);
+ u64 r = 0;
+ for(int j=0; j != 8; j++) {
+ r |= u64(get<u8>(lpc)) << ((7-j)*8);
+ lpc = (lpc & ~m_page_mask) | ((lpc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ break;
+ }
+ break;
+ }
+ } else {
+ switch(shift) {
+ case -3: // bus granularity 64
+ m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 64-bits granularity bus\n"); };
+ m_do_r16 = [](offs_t pc) -> u16 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r16 access on 64-bits granularity bus\n"); };
+ m_do_r32 = [](offs_t pc) -> u32 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r32 access on 64-bits granularity bus\n"); };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 1);
+ const u64 *src = get_ptr<u64>(pc);
+ return src[0];
+ };
+ break;
+
+ case -2: // bus granularity 32
+ m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 32-bits granularity bus\n"); };
+ m_do_r16 = [](offs_t pc) -> u16 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r16 access on 32-bits granularity bus\n"); };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 1);
+ const u32 *src = get_ptr<u32>(pc);
+ return src[0];
+ };
+ switch(endian) {
+ case ENDIANNESS_LITTLE:
+ if(m_page_mask) {
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 2);
+ u64 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= u64(get<u32>(pc)) << (j*32);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 2);
+ const u32 *src = get_ptr<u32>(pc);
+ return src[0] | (u64(src[1]) << 32);
+ };
+ }
+ break;
+ case ENDIANNESS_BIG:
+ if(m_page_mask) {
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 2);
+ u64 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= u64(get<u32>(pc)) << ((1-j)*32);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 2);
+ const u32 *src = get_ptr<u32>(pc);
+ return (u64(src[0]) << 32) | u64(src[1]);
+ };
+ }
+ break;
+ }
+ break;
+
+ case -1: // bus granularity 16
+ m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 16-bits granularity bus\n"); };
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 1);
+ const u16 *src = get_ptr<u16>(pc);
+ return src[0];
+ };
+ switch(endian) {
+ case ENDIANNESS_LITTLE:
+ if(m_page_mask) {
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 2);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u16>(pc) << (j*16);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 4);
+ u64 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= u64(get<u16>(pc)) << (j*16);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 2);
+ const u16 *src = get_ptr<u16>(pc);
+ return src[0] | (src[1] << 16);
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 4);
+ const u16 *src = get_ptr<u16>(pc);
+ return src[0] | (src[1] << 16) | (u64(src[2]) << 32) | (u64(src[3]) << 48);
+ };
+ }
+ break;
+ case ENDIANNESS_BIG:
+ if(m_page_mask) {
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 2);
+ u32 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u16>(pc) << ((1-j)*16);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 4);
+ u64 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= u64(get<u16>(pc)) << ((3-j)*16);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 2);
+ const u16 *src = get_ptr<u16>(pc);
+ return (src[0] << 16) | src[1];
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 4);
+ const u16 *src = get_ptr<u16>(pc);
+ return (u64(src[0]) << 48) | (u64(src[1]) << 32) | (src[2] << 16) | src[3];
+ };
+ }
+ break;
+ }
+ break;
+
+ case 0: // bus granularity 8
+ m_do_r8 = [this](offs_t pc) -> u8 {
+ fill(pc, 1);
+ const u8 *src = get_ptr<u8>(pc);
+ return src[0];
+ };
+ switch(endian) {
+ case ENDIANNESS_LITTLE:
+ if(m_page_mask) {
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 2);
+ u16 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(pc) << (j*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 4);
+ u32 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= get<u8>(pc) << (j*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 8);
+ u64 r = 0;
+ for(int j=0; j != 8; j++) {
+ r |= u64(get<u8>(pc)) << (j*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 2);
+ const u8 *src = get_ptr<u8>(pc);
+ return src[0] | (src[1] << 8);
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 4);
+ const u8 *src = get_ptr<u8>(pc);
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 8);
+ const u8 *src = get_ptr<u8>(pc);
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24) |
+ (u64(src[4]) << 32) | (u64(src[5]) << 40) | (u64(src[6]) << 48) | (u64(src[7]) << 56);
+ };
+ }
+ break;
+ case ENDIANNESS_BIG:
+ if(m_page_mask) {
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 2);
+ u16 r = 0;
+ for(int j=0; j != 2; j++) {
+ r |= get<u8>(pc) << ((1-j)*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 4);
+ u32 r = 0;
+ for(int j=0; j != 4; j++) {
+ r |= get<u8>(pc) << ((3-j)*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 8);
+ u64 r = 0;
+ for(int j=0; j != 8; j++) {
+ r |= u64(get<u8>(pc)) << ((7-j)*8);
+ pc = (pc & ~m_page_mask) | ((pc + 1) & m_page_mask);
+ }
+ return r;
+ };
+ } else {
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 2);
+ const u8 *src = get_ptr<u8>(pc);
+ return (src[0] << 8) | src[1];
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 4);
+ const u8 *src = get_ptr<u8>(pc);
+ return (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 8);
+ const u8 *src = get_ptr<u8>(pc);
+ return (u64(src[0]) << 56) | (u64(src[1]) << 32) | (u64(src[2]) << 40) | (u64(src[3]) << 32) |
+ (src[4] << 24) | (src[5] << 16) | (src[6] << 8) | src[7];
+ };
+ }
+ break;
+ }
+ break;
+
+ case 3: // bus granularity 1, u16 storage, no paging
+ assert(endian == ENDIANNESS_LITTLE);
+ assert(!m_page_mask);
+ m_do_r8 = [](offs_t pc) -> u8 { throw emu_fatalerror("debug_disasm_buffer::debug_data_buffer: r8 access on 1-bit/16 wide granularity bus\n"); };
+ m_do_r16 = [this](offs_t pc) -> u16 {
+ fill(pc, 16);
+ const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4);
+ return src[0];
+ };
+ m_do_r32 = [this](offs_t pc) -> u32 {
+ fill(pc, 32);
+ const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4);
+ return src[0] | (src[1] << 16);
+ };
+ m_do_r64 = [this](offs_t pc) -> u64 {
+ fill(pc, 64);
+ const u16 *src = reinterpret_cast<u16 *>(&m_buffer[0]) + ((pc - m_lstart) >> 4);
+ return src[0] | (src[1] << 16) | (u64(src[2]) << 32) | (u64(src[3]) << 48);
+ };
+ break;
+ }
+ }
+
+ // Define the data -> string conversion
+ switch(shift) {
+ case -3:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i++) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%016x", r64(pc));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ return out.str();
+ };
+ break;
+
+ case -2:
+ switch(alignment) {
+ case 1:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i++) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%08x", r32(pc));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ return out.str();
+ };
+ break;
+
+ case 2:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 2) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%016x", r64(pc));
+ pc = m_next_pc_wrap(pc, 2);
+ }
+ return out.str();
+ };
+ break;
+ }
+ break;
+
+ case -1:
+ switch(alignment) {
+ case 1:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i++) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%04x", r16(pc));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ return out.str();
+ };
+ break;
+
+ case 2:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 2) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%08x", r32(pc));
+ pc = m_next_pc_wrap(pc, 2);
+ }
+ return out.str();
+ };
+ break;
+
+ case 4:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 4) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%016x", r64(pc));
+ pc = m_next_pc_wrap(pc, 4);
+ }
+ return out.str();
+ };
+ break;
+ }
+ break;
+
+ case 0:
+ switch(alignment) {
+ case 1:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i++) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%02x", r8(pc));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ return out.str();
+ };
+ break;
+
+ case 2:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 2) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%04x", r16(pc));
+ pc = m_next_pc_wrap(pc, 2);
+ }
+ return out.str();
+ };
+ break;
+
+ case 4:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 4) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%08x", r32(pc));
+ pc = m_next_pc_wrap(pc, 4);
+ }
+ return out.str();
+ };
+ break;
+
+ case 8:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 8) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%016x", r64(pc));
+ pc = m_next_pc_wrap(pc, 8);
+ }
+ return out.str();
+ };
+ break;
+ }
+ break;
+
+ case 3:
+ m_data_to_string = [this](offs_t pc, offs_t size) {
+ std::ostringstream out;
+ for(offs_t i=0; i != size; i += 16) {
+ if(i)
+ out << ' ';
+ util::stream_format(out, "%04x", r16(pc));
+ pc = m_next_pc_wrap(pc, 16);
+ }
+ return out.str();
+ };
+ break;
+ }
+
+ // Define the data extraction
+ switch(shift) {
+ case -3:
+ m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) {
+ for(offs_t i=0; i != size; i++) {
+ u64 r = r64(pc);
+ for(int j=0; j != 8; j++)
+ data.push_back(r >> (8*j));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ };
+ break;
+
+ case -2:
+ m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) {
+ for(offs_t i=0; i != size; i++) {
+ u32 r = r32(pc);
+ for(int j=0; j != 4; j++)
+ data.push_back(r >> (8*j));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ };
+ break;
+
+ case -1:
+ m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) {
+ for(offs_t i=0; i != size; i++) {
+ u16 r = r16(pc);
+ for(int j=0; j != 2; j++)
+ data.push_back(r >> (8*j));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ };
+ break;
+
+ case 0:
+ m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) {
+ for(offs_t i=0; i != size; i++) {
+ data.push_back(r8(pc));
+ pc = m_next_pc_wrap(pc, 1);
+ }
+ };
+ break;
+
+ case 3:
+ m_data_get = [this](offs_t pc, offs_t size, std::vector<u8> &data) {
+ for(offs_t i=0; i != size >> 4; i++) {
+ u16 r = r16(pc);
+ for(int j=0; j != 2; j++)
+ data.push_back(r >> (8*j));
+ pc = m_next_pc_wrap(pc, 16);
+ }
+ };
+ break;
+ }
+
+ // Wrapped next pc computation
+ if(m_intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) {
+ // lfsr pc is always paged
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ offs_t lpc = m_intf->pc_real_to_linear(pc);
+ offs_t lpce = (lpc & ~m_page_mask) | ((lpc + size) & m_page_mask);
+ return m_intf->pc_linear_to_real(lpce);
+ };
+ } else if(m_intf->interface_flags() & util::disasm_interface::PAGED) {
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ offs_t pce = (pc & ~m_page_mask) | ((pc + size) & m_page_mask);
+ return pce;
+ };
+ } else {
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ return (pc + size) & m_pc_mask;
+ };
+ }
+}
+
+debug_disasm_buffer::debug_disasm_buffer(device_t &device) :
+ m_buf_raw(dynamic_cast<device_disasm_interface &>(device).get_disassembler()),
+ m_buf_opcodes(dynamic_cast<device_disasm_interface &>(device).get_disassembler()),
+ m_buf_params(dynamic_cast<device_disasm_interface &>(device).get_disassembler())
+{
+ m_dintf = dynamic_cast<device_disasm_interface *>(&device)->get_disassembler();
+ m_mintf = dynamic_cast<device_memory_interface *>(&device);
+
+ m_flags = m_dintf->interface_flags();
+
+ if(m_flags & util::disasm_interface::INTERNAL_DECRYPTION) {
+ m_buf_raw.set_source(m_mintf->space(AS_PROGRAM));
+ m_buf_opcodes.set_source(m_buf_raw, true);
+ if((m_flags & util::disasm_interface::SPLIT_DECRYPTION) == util::disasm_interface::SPLIT_DECRYPTION)
+ m_buf_params.set_source(m_buf_raw, false);
+ } else {
+ if(m_mintf->has_space(AS_OPCODES)) {
+ m_buf_opcodes.set_source(m_mintf->space(AS_OPCODES));
+ m_buf_params.set_source(m_mintf->space(AS_PROGRAM));
+ } else
+ m_buf_opcodes.set_source(m_mintf->space(AS_PROGRAM));
+ }
+
+ m_pc_mask = m_mintf->space(AS_PROGRAM).logaddrmask();
+
+ if(m_flags & util::disasm_interface::PAGED)
+ m_page_mask = (1 << m_dintf->page_address_bits()) - 1;
+ else
+ m_page_mask = 0;
+
+ // Next pc computation
+ if(m_flags & util::disasm_interface::NONLINEAR_PC) {
+ // lfsr pc is always paged
+ m_next_pc = [this](offs_t pc, offs_t size) {
+ offs_t lpc = m_dintf->pc_real_to_linear(pc);
+ offs_t lpce = lpc + size;
+ if((lpc ^ lpce) & ~m_page_mask)
+ lpce = (lpc | m_page_mask) + 1;
+ lpce &= m_pc_mask;
+ return m_dintf->pc_linear_to_real(lpce);
+ };
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ offs_t lpc = m_dintf->pc_real_to_linear(pc);
+ offs_t lpce = (lpc & ~m_page_mask) | ((lpc + size) & m_page_mask);
+ return m_dintf->pc_linear_to_real(lpce);
+ };
+
+ } else if(m_flags & util::disasm_interface::PAGED) {
+ m_next_pc = [this](offs_t pc, offs_t size) {
+ offs_t pce = pc + size;
+ if((pc ^ pce) & ~m_page_mask)
+ pce = (pc | m_page_mask) + 1;
+ pce &= m_pc_mask;
+ return pce;
+ };
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ offs_t pce = (pc & ~m_page_mask) | ((pc + size) & m_page_mask);
+ return pce;
+ };
+
+ } else {
+ m_next_pc = [this](offs_t pc, offs_t size) {
+ return (pc + size) & m_pc_mask;
+ };
+ m_next_pc_wrap = [this](offs_t pc, offs_t size) {
+ return (pc + size) & m_pc_mask;
+ };
+ }
+
+ // pc to string conversion
+ int aw = m_mintf->space(AS_PROGRAM).addr_width();
+ bool is_octal = m_mintf->space(AS_PROGRAM).is_octal();
+ if((m_flags & util::disasm_interface::PAGED2LEVEL) == util::disasm_interface::PAGED2LEVEL) {
+ int bits1 = m_dintf->page_address_bits();
+ int bits2 = m_dintf->page2_address_bits();
+ int bits3 = aw - bits1 - bits2;
+ offs_t sm1 = (1 << bits1) - 1;
+ int sh2 = bits1;
+ offs_t sm2 = (1 << bits2) - 1;
+ int sh3 = bits1+bits2;
+
+ if(is_octal) {
+ int nc1 = (bits1+2)/3;
+ int nc2 = (bits2+2)/3;
+ int nc3 = (bits3+2)/3;
+ m_pc_to_string = [nc1, nc2, nc3, sm1, sm2, sh2, sh3](offs_t pc) -> std::string {
+ return util::string_format("%0*o:%0*o:%0*o",
+ nc3, pc >> sh3,
+ nc2, (pc >> sh2) & sm2,
+ nc1, pc & sm1);
+ };
+ } else {
+ int nc1 = (bits1+3)/4;
+ int nc2 = (bits2+3)/4;
+ int nc3 = (bits3+3)/4;
+ m_pc_to_string = [nc1, nc2, nc3, sm1, sm2, sh2, sh3](offs_t pc) -> std::string {
+ return util::string_format("%0*x:%0*x:%0*x",
+ nc3, pc >> sh3,
+ nc2, (pc >> sh2) & sm2,
+ nc1, pc & sm1);
+ };
+ }
+
+ } else if(m_flags & util::disasm_interface::PAGED) {
+ int bits1 = m_dintf->page_address_bits();
+ int bits2 = aw - bits1;
+ offs_t sm1 = (1 << bits1) - 1;
+ int sh2 = bits1;
+
+ if(is_octal) {
+ int nc1 = (bits1+2)/3;
+ int nc2 = (bits2+2)/3;
+ m_pc_to_string = [nc1, nc2, sm1, sh2](offs_t pc) -> std::string {
+ return util::string_format("%0*o:%0*o",
+ nc2, pc >> sh2,
+ nc1, pc & sm1);
+ };
+ } else {
+ int nc1 = (bits1+3)/4;
+ int nc2 = (bits2+3)/4;
+ m_pc_to_string = [nc1, nc2, sm1, sh2](offs_t pc) -> std::string {
+ return util::string_format("%0*x:%0*x",
+ nc2, pc >> sh2,
+ nc1, pc & sm1);
+ };
+ }
+
+ } else {
+ int bits1 = aw;
+
+ if(is_octal) {
+ int nc1 = (bits1+2)/3;
+ m_pc_to_string = [nc1](offs_t pc) -> std::string {
+ return util::string_format("%0*o",
+ nc1, pc);
+ };
+ } else {
+ int nc1 = (bits1+3)/4;
+ m_pc_to_string = [nc1](offs_t pc) -> std::string {
+ return util::string_format("%0*x",
+ nc1, pc);
+ };
+ }
+ }
+}
+
+void debug_disasm_buffer::disassemble(offs_t pc, std::string &instruction, offs_t &next_pc, offs_t &size, u32 &info) const
+{
+ std::ostringstream out;
+ u32 result = m_dintf->disassemble(out, pc, m_buf_opcodes, m_buf_params.active() ? m_buf_params : m_buf_opcodes);
+ instruction = out.str();
+ size = result & util::disasm_interface::LENGTHMASK;
+ next_pc = m_next_pc(pc, size);
+ info = result;
+}
+
+
+u32 debug_disasm_buffer::disassemble_info(offs_t pc) const
+{
+ std::ostringstream out;
+ return m_dintf->disassemble(out, pc, m_buf_opcodes, m_buf_params.active() ? m_buf_params : m_buf_opcodes);
+}
+
+std::string debug_disasm_buffer::pc_to_string(offs_t pc) const
+{
+ return m_pc_to_string(pc);
+}
+
+std::string debug_disasm_buffer::data_to_string(offs_t pc, offs_t size, bool opcode) const
+{
+ if(!opcode && !m_buf_params.active())
+ return std::string();
+ return (opcode ? m_buf_opcodes : m_buf_params).data_to_string(pc, size);
+}
+
+void debug_disasm_buffer::data_get(offs_t pc, offs_t size, bool opcode, std::vector<u8> &data) const
+{
+ data.clear();
+ if(!opcode && !m_buf_params.active())
+ return;
+ (opcode ? m_buf_opcodes : m_buf_params).data_get(pc, size, data);
+}
+
+offs_t debug_disasm_buffer::next_pc(offs_t pc, offs_t step) const
+{
+ return m_next_pc(pc, step);
+}
+
+offs_t debug_disasm_buffer::next_pc_wrap(offs_t pc, offs_t step) const
+{
+ return m_next_pc_wrap(pc, step);
+}