summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/addrmap.cpp19
-rw-r--r--src/emu/addrmap.h4
-rw-r--r--src/emu/debug/debugbuf.cpp1379
-rw-r--r--src/emu/debug/debugbuf.h93
-rw-r--r--src/emu/debug/debugcmd.cpp366
-rw-r--r--src/emu/debug/debugcon.cpp8
-rw-r--r--src/emu/debug/debugcon.h2
-rw-r--r--src/emu/debug/debugcpu.cpp145
-rw-r--r--src/emu/debug/debugcpu.h1
-rw-r--r--src/emu/debug/dvdisasm.cpp514
-rw-r--r--src/emu/debug/dvdisasm.h59
-rw-r--r--src/emu/debug/dvmemory.cpp7
-rw-r--r--src/emu/devcpu.h12
-rw-r--r--src/emu/device.cpp31
-rw-r--r--src/emu/device.h2
-rw-r--r--src/emu/didisasm.cpp113
-rw-r--r--src/emu/didisasm.h83
-rw-r--r--src/emu/diexec.cpp42
-rw-r--r--src/emu/diexec.h6
-rw-r--r--src/emu/dipalette.cpp6
-rw-r--r--src/emu/dipalette.h2
-rw-r--r--src/emu/dirom.cpp2
-rw-r--r--src/emu/dirom.h2
-rw-r--r--src/emu/diserial.cpp4
-rw-r--r--src/emu/distate.cpp155
-rw-r--r--src/emu/distate.h128
-rw-r--r--src/emu/divideo.cpp7
-rw-r--r--src/emu/drawgfx.cpp12
-rw-r--r--src/emu/drawgfx.h4
-rw-r--r--src/emu/drawgfxm.h15
-rw-r--r--src/emu/driver.cpp57
-rw-r--r--src/emu/driver.h13
-rw-r--r--src/emu/drivers/xtal.h40
-rw-r--r--src/emu/emucore.h23
-rw-r--r--src/emu/emufwd.h2
-rw-r--r--src/emu/emumem.cpp869
-rw-r--r--src/emu/emumem.h272
-rw-r--r--src/emu/inpttype.h22
-rw-r--r--src/emu/input.h10
-rw-r--r--src/emu/ioport.cpp105
-rw-r--r--src/emu/ioport.h10
-rw-r--r--src/emu/layout/README.md4
-rw-r--r--src/emu/machine.cpp4
-rw-r--r--src/emu/natkeyboard.cpp64
-rw-r--r--src/emu/screen.cpp61
-rw-r--r--src/emu/screen.h2
-rw-r--r--src/emu/validity.cpp47
-rw-r--r--src/emu/video/rgbgen.cpp20
-rw-r--r--src/emu/video/rgbgen.h19
-rw-r--r--src/emu/video/rgbsse.h107
-rw-r--r--src/emu/video/rgbutil.h1
-rw-r--r--src/emu/video/rgbvmx.h32
52 files changed, 3482 insertions, 1525 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp
index 0d8d7bc4eef..9eee69f986f 100644
--- a/src/emu/addrmap.cpp
+++ b/src/emu/addrmap.cpp
@@ -41,11 +41,7 @@ address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t
m_region(nullptr),
m_rgnoffs(0),
m_submap_bits(0),
- m_memory(nullptr),
- m_bytestart(0),
- m_byteend(0),
- m_bytemirror(0),
- m_bytemask(0)
+ m_memory(nullptr)
{
}
@@ -404,7 +400,7 @@ address_map::address_map(const address_space &space, offs_t start, offs_t end, i
m_device(&device),
m_databits(space.data_width()),
m_unmapval(space.unmap()),
- m_globalmask(space.bytemask())
+ m_globalmask(space.addrmask())
{
range(start, end).set_submap(DEVICE_SELF, submap_delegate, bits, unitmask);
}
@@ -610,7 +606,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
// it's safe to assume here that the device has a memory interface and a config for this space
const address_space_config &spaceconfig = *m_device->memory().space_config(spacenum);
int datawidth = spaceconfig.m_databus_width;
- int alignunit = datawidth / 8;
+ int alignunit = spaceconfig.alignment();
bool detected_overlap = DETECT_OVERLAPPING_MEMORY ? false : true;
@@ -631,9 +627,6 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
// loop over entries and look for errors
for (address_map_entry &entry : m_entrylist)
{
- u32 bytestart = spaceconfig.addr2byte(entry.m_addrstart);
- u32 byteend = spaceconfig.addr2byte_end(entry.m_addrend);
-
// look for overlapping entries
if (!detected_overlap)
{
@@ -653,7 +646,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
}
// look for inverted start/end pairs
- if (byteend < bytestart)
+ if (entry.m_addrend < entry.m_addrstart)
osd_printf_error("Wrong %s memory read handler start = %08x > end = %08x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend);
// look for ranges outside the global mask
@@ -663,7 +656,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
osd_printf_error("In %s memory range %x-%x, end address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask);
// look for misaligned entries
- if ((bytestart & (alignunit - 1)) != 0 || (byteend & (alignunit - 1)) != (alignunit - 1))
+ if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1))
osd_printf_error("Wrong %s memory read handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit);
// verify mask/mirror/select
@@ -715,7 +708,7 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons
{
// verify the address range is within the region's bounds
offs_t const length = region.get_length();
- if (entry.m_rgnoffs + (byteend - bytestart + 1) > length)
+ if (entry.m_rgnoffs + spaceconfig.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > length)
osd_printf_error("%s space memory map entry %X-%X extends beyond region '%s' size (%X)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, length);
found = true;
}
diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h
index c56c9257d47..587f9a16e33 100644
--- a/src/emu/addrmap.h
+++ b/src/emu/addrmap.h
@@ -154,10 +154,6 @@ public:
// information used during processing
void * m_memory; // pointer to memory backing this entry
- offs_t m_bytestart; // byte-adjusted start address
- offs_t m_byteend; // byte-adjusted end address
- offs_t m_bytemirror; // byte-adjusted mirror bits
- offs_t m_bytemask; // byte-adjusted mask bits
// handler setters for 8-bit functions
address_map_entry &set_handler(read8_delegate func, u64 mask = 0);
diff --git a/src/emu/debug/debugbuf.cpp b/src/emu/debug/debugbuf.cpp
new file mode 100644
index 00000000000..779b91f84ac
--- /dev/null
+++ b/src/emu/debug/debugbuf.cpp
@@ -0,0 +1,1379 @@
+// 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 & m_pc_mask);
+}
+
+u16 debug_disasm_buffer::debug_data_buffer::r16(offs_t pc) const
+{
+ return m_do_r16(pc & m_pc_mask);
+}
+
+u32 debug_disasm_buffer::debug_data_buffer::r32(offs_t pc) const
+{
+ return m_do_r32(pc & m_pc_mask);
+}
+
+u64 debug_disasm_buffer::debug_data_buffer::r64(offs_t pc) const
+{
+ return m_do_r64(pc & m_pc_mask);
+}
+
+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_lstart == m_lend)
+ return;
+ if(m_wrapped) {
+ if(lstart >= m_lstart && (lend > m_lstart || lend <= m_lend))
+ return;
+ if(lstart < m_lend && lend <= m_lend)
+ return;
+ } else {
+ if(lstart < lend && lstart >= m_lstart && lend <= 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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) | u32(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) | u32(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);
+}
diff --git a/src/emu/debug/debugbuf.h b/src/emu/debug/debugbuf.h
new file mode 100644
index 00000000000..46ec8286417
--- /dev/null
+++ b/src/emu/debug/debugbuf.h
@@ -0,0 +1,93 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Buffering interface for the disassembly windows
+
+#ifndef MAME_EMU_DEBUG_DEBUGBUF_H
+#define MAME_EMU_DEBUG_DEBUGBUF_H
+
+#pragma once
+
+class debug_disasm_buffer
+{
+public:
+ debug_disasm_buffer(device_t &device);
+
+ void disassemble(offs_t pc, std::string &instruction, offs_t &next_pc, offs_t &size, u32 &info) const;
+ u32 disassemble_info(offs_t pc) const;
+ std::string pc_to_string(offs_t pc) const;
+ std::string data_to_string(offs_t pc, offs_t size, bool opcode) const;
+ void data_get(offs_t pc, offs_t size, bool opcode, std::vector<u8> &data) const;
+
+ offs_t next_pc(offs_t pc, offs_t step) const;
+ offs_t next_pc_wrap(offs_t pc, offs_t step) const;
+
+private:
+ class debug_data_buffer : public util::disasm_interface::data_buffer
+ {
+ public:
+ debug_data_buffer(util::disasm_interface *intf);
+ ~debug_data_buffer() = default;
+
+ virtual u8 r8 (offs_t pc) const override;
+ virtual u16 r16(offs_t pc) const override;
+ virtual u32 r32(offs_t pc) const override;
+ virtual u64 r64(offs_t pc) const override;
+
+ void set_source(address_space &space);
+ void set_source(debug_data_buffer &back, bool opcode);
+
+ bool active() const;
+
+ address_space *get_underlying_space() const;
+ std::string data_to_string(offs_t pc, offs_t size) const;
+ void data_get(offs_t pc, offs_t size, std::vector<u8> &data) const;
+
+ private:
+ util::disasm_interface *m_intf;
+
+ std::function<offs_t (offs_t)> m_pc_delta_to_bytes;
+ std::function<void (offs_t, offs_t)> m_do_fill;
+ std::function<u8 (offs_t)> m_do_r8;
+ std::function<u16 (offs_t)> m_do_r16;
+ std::function<u32 (offs_t)> m_do_r32;
+ std::function<u64 (offs_t)> m_do_r64;
+ std::function<std::string (offs_t, offs_t)> m_data_to_string;
+ std::function<void (offs_t, offs_t, std::vector<u8> &)> m_data_get;
+ std::function<offs_t (offs_t, offs_t)> m_next_pc_wrap;
+
+ address_space *m_space;
+ debug_data_buffer *m_back;
+ bool m_opcode;
+ offs_t m_page_mask, m_pc_mask;
+ mutable offs_t m_lstart, m_lend;
+ mutable bool m_wrapped;
+ mutable std::vector<u8> m_buffer;
+
+ template<typename T> T *get_ptr(offs_t lpc) {
+ return reinterpret_cast<T *>(&m_buffer[0]) + ((lpc - m_lstart) & m_pc_mask);
+ }
+
+ template<typename T> T get(offs_t lpc) const {
+ return reinterpret_cast<const T *>(&m_buffer[0])[(lpc - m_lstart) & m_pc_mask];
+ }
+
+ void setup_methods();
+ void fill(offs_t lstart, offs_t size) const;
+
+ };
+
+ util::disasm_interface *m_dintf;
+ device_memory_interface *m_mintf;
+
+ std::function<offs_t (offs_t, offs_t)> m_next_pc;
+ std::function<offs_t (offs_t, offs_t)> m_next_pc_wrap;
+ std::function<std::string (offs_t)> m_pc_to_string;
+
+ debug_data_buffer m_buf_raw, m_buf_opcodes, m_buf_params;
+ u32 m_flags;
+ offs_t m_page_mask, m_pc_mask;
+};
+
+#endif
+
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index c1e96054164..0c7715b523b 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -14,6 +14,7 @@
#include "debugcmd.h"
#include "debugcon.h"
#include "debugcpu.h"
+#include "debugbuf.h"
#include "express.h"
#include "debughlp.h"
#include "debugvw.h"
@@ -1644,7 +1645,6 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa
u64 offset, endoffset, length;
address_space *space;
FILE *f;
- u64 i;
/* validate parameters */
if (!validate_number_parameter(params[1], offset))
@@ -1655,8 +1655,9 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa
return;
/* determine the addresses to write */
- endoffset = space->address_to_byte(offset + length - 1) & space->bytemask();
- offset = space->address_to_byte(offset) & space->bytemask();
+ endoffset = (offset + length - 1) & space->addrmask();
+ offset = offset & space->addrmask();
+ endoffset ++;
/* open the file */
f = fopen(params[0].c_str(), "wb");
@@ -1667,10 +1668,46 @@ void debugger_commands::execute_save(int ref, const std::vector<std::string> &pa
}
/* now write the data out */
- for (i = offset; i <= endoffset; i++)
+ auto dis = space->machine().disable_side_effect();
+ switch (space->addrbus_shift())
{
- u8 byte = m_cpu.read_byte(*space, i, true);
- fwrite(&byte, 1, 1, f);
+ case -3:
+ for (offs_t i = offset; i != endoffset; i++)
+ {
+ u64 data = space->read_qword(i);
+ fwrite(&data, 8, 1, f);
+ }
+ break;
+ case -2:
+ for (offs_t i = offset; i != endoffset; i++)
+ {
+ u32 data = space->read_dword(i);
+ fwrite(&data, 4, 1, f);
+ }
+ break;
+ case -1:
+ for (offs_t i = offset; i != endoffset; i++)
+ {
+ u16 byte = space->read_word(i);
+ fwrite(&byte, 2, 1, f);
+ }
+ break;
+ case 0:
+ for (offs_t i = offset; i != endoffset; i++)
+ {
+ u8 byte = space->read_byte(i);
+ fwrite(&byte, 1, 1, f);
+ }
+ break;
+ case 3:
+ offset &= ~15;
+ endoffset &= ~15;
+ for (offs_t i = offset; i != endoffset; i+=16)
+ {
+ u16 byte = space->read_word(i >> 4);
+ fwrite(&byte, 2, 1, f);
+ }
+ break;
}
/* close the file */
@@ -1687,7 +1724,6 @@ void debugger_commands::execute_load(int ref, const std::vector<std::string> &pa
{
u64 offset, endoffset, length = 0;
address_space *space;
- u64 i;
// validate parameters
if (!validate_number_parameter(params[1], offset))
@@ -1712,19 +1748,66 @@ void debugger_commands::execute_load(int ref, const std::vector<std::string> &pa
f.seekg(0, std::ios::end);
length = f.tellg();
f.seekg(0);
+ if (space->addrbus_shift() < 0)
+ length >>= -space->addrbus_shift();
+ else if (space->addrbus_shift() > 0)
+ length <<= space->addrbus_shift();
}
// determine the addresses to read
- endoffset = space->address_to_byte(offset + length - 1) & space->bytemask();
- offset = space->address_to_byte(offset) & space->bytemask();
-
+ endoffset = (offset + length - 1) & space->addrmask();
+ offset = offset & space->addrmask();
+ offs_t i = 0;
// now read the data in, ignore endoffset and load entire file if length has been set to zero (offset-1)
- for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++)
+ switch (space->addrbus_shift())
{
- char byte;
- f.read(&byte, 1);
- if (f)
- m_cpu.write_byte(*space, i, byte, true);
+ case -3:
+ for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++)
+ {
+ u64 data;
+ f.read((char *)&data, 8);
+ if (f)
+ space->write_qword(i, data);
+ }
+ break;
+ case -2:
+ for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++)
+ {
+ u32 data;
+ f.read((char *)&data, 4);
+ if (f)
+ space->write_dword(i, data);
+ }
+ break;
+ case -1:
+ for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++)
+ {
+ u16 data;
+ f.read((char *)&data, 2);
+ if (f)
+ space->write_word(i, data);
+ }
+ break;
+ case 0:
+ for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 1); i++)
+ {
+ u8 data;
+ f.read((char *)&data, 1);
+ if (f)
+ space->write_byte(i, data);
+ }
+ break;
+ case 3:
+ offset &= ~15;
+ endoffset &= ~15;
+ for (i = offset; f.good() && (i <= endoffset || endoffset == offset - 16); i+=16)
+ {
+ u16 data;
+ f.read((char *)&data, 2);
+ if (f)
+ space->write_word(i >> 4, data);
+ }
+ break;
}
if (!f.good())
@@ -1767,6 +1850,9 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa
if (!validate_cpu_space_parameter((params.size() > 6) ? params[6].c_str() : nullptr, ref, space))
return;
+ int shift = space->addrbus_shift();
+ u64 granularity = shift > 0 ? 2 : 1 << -shift;
+
/* further validation */
if (width == 0)
width = space->data_width() / 8;
@@ -1777,14 +1863,19 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa
m_console.printf("Invalid width! (must be 1,2,4 or 8)\n");
return;
}
+ if (width < granularity)
+ {
+ m_console.printf("Invalid width! (must be at least %d)\n", granularity);
+ return;
+ }
if (rowsize == 0 || (rowsize % width) != 0)
{
m_console.printf("Invalid row size! (must be a positive multiple of %d)\n", width);
return;
}
- u64 endoffset = space->address_to_byte(offset + length - 1) & space->bytemask();
- offset = space->address_to_byte(offset) & space->bytemask();
+ u64 endoffset = (offset + length - 1) & space->addrmask();
+ offset = offset & space->addrmask();
/* open the file */
FILE* f = fopen(params[0].c_str(), "w");
@@ -1797,13 +1888,22 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa
/* now write the data out */
util::ovectorstream output;
output.reserve(200);
- for (u64 i = offset; i <= endoffset; i += rowsize)
+
+ if (shift > 0)
+ width <<= shift;
+ else if(shift < 0)
+ width >>= -shift;
+
+ auto dis = space->machine().disable_side_effect();
+ bool be = space->endianness() == ENDIANNESS_BIG;
+
+ for (offs_t i = offset; i <= endoffset; i += rowsize)
{
output.clear();
output.rdbuf()->clear();
/* print the address */
- util::stream_format(output, "%0*X: ", space->logaddrchars(), u32(space->byte_to_address(i)));
+ util::stream_format(output, "%0*X: ", space->logaddrchars(), i);
/* print the bytes */
for (u64 j = 0; j < rowsize; j += width)
@@ -1813,8 +1913,21 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa
offs_t curaddr = i + j;
if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
{
- u64 value = m_cpu.read_memory(*space, i + j, width, true);
- util::stream_format(output, " %0*X", width * 2, value);
+ switch (width)
+ {
+ case 8:
+ util::stream_format(output, " %016X", space->read_qword(i+j));
+ break;
+ case 4:
+ util::stream_format(output, " %08X", space->read_dword(i+j));
+ break;
+ case 2:
+ util::stream_format(output, " %04X", space->read_word(i+j));
+ break;
+ case 1:
+ util::stream_format(output, " %02X", space->read_byte(i+j));
+ break;
+ }
}
else
{
@@ -1834,8 +1947,26 @@ void debugger_commands::execute_dump(int ref, const std::vector<std::string> &pa
offs_t curaddr = i + j;
if (space->device().memory().translate(space->spacenum(), TRANSLATE_READ_DEBUG, curaddr))
{
- u8 byte = m_cpu.read_byte(*space, i + j, true);
- util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.');
+ u64 data = 0;
+ switch (width)
+ {
+ case 8:
+ data = space->read_qword(i+j);
+ break;
+ case 4:
+ data = space->read_dword(i+j);
+ break;
+ case 2:
+ data = space->read_word(i+j);
+ break;
+ case 1:
+ data = space->read_byte(i+j);
+ break;
+ }
+ for (unsigned int b = 0; b != width; b++) {
+ u8 byte = data >> (8 * (be ? (width-i-b) : b));
+ util::stream_format(output, "%c", (byte >= 32 && byte < 127) ? byte : '.');
+ }
}
else
{
@@ -1920,8 +2051,8 @@ void debugger_commands::execute_cheatinit(int ref, const std::vector<std::string
{
for (address_map_entry &entry : space->map()->m_entrylist)
{
- cheat_region[region_count].offset = space->address_to_byte(entry.m_addrstart) & space->bytemask();
- cheat_region[region_count].endoffset = space->address_to_byte(entry.m_addrend) & space->bytemask();
+ cheat_region[region_count].offset = entry.m_addrstart & space->addrmask();
+ cheat_region[region_count].endoffset = entry.m_addrend & space->addrmask();
cheat_region[region_count].share = entry.m_share;
cheat_region[region_count].disabled = (entry.m_write.m_type == AMH_RAM) ? false : true;
@@ -1944,8 +2075,8 @@ void debugger_commands::execute_cheatinit(int ref, const std::vector<std::string
return;
/* force region to the specified range */
- cheat_region[region_count].offset = space->address_to_byte(offset) & space->bytemask();
- cheat_region[region_count].endoffset = space->address_to_byte(offset + length - 1) & space->bytemask();
+ cheat_region[region_count].offset = offset & space->addrmask();
+ cheat_region[region_count].endoffset = (offset + length - 1) & space->addrmask();
cheat_region[region_count].share = nullptr;
cheat_region[region_count].disabled = false;
region_count++;
@@ -2320,9 +2451,9 @@ void debugger_commands::execute_find(int ref, const std::vector<std::string> &pa
return;
/* further validation */
- endoffset = space->address_to_byte(offset + length - 1) & space->bytemask();
- offset = space->address_to_byte(offset) & space->bytemask();
- cur_data_size = space->address_to_byte(1);
+ endoffset = (offset + length - 1) & space->addrmask();
+ offset = offset & space->addrmask();
+ cur_data_size = space->addrbus_shift() > 0 ? 2 : 1 << -space->addrbus_shift();
if (cur_data_size == 0)
cur_data_size = 1;
@@ -2403,10 +2534,7 @@ void debugger_commands::execute_find(int ref, const std::vector<std::string> &pa
void debugger_commands::execute_dasm(int ref, const std::vector<std::string> &params)
{
u64 offset, length, bytes = 1;
- int minbytes, maxbytes, byteswidth;
- address_space *space, *decrypted_space;
- FILE *f;
- int j;
+ address_space *space;
/* validate parameters */
if (!validate_number_parameter(params[1], offset))
@@ -2417,10 +2545,6 @@ void debugger_commands::execute_dasm(int ref, const std::vector<std::string> &pa
return;
if (!validate_cpu_space_parameter(params.size() > 4 ? params[4].c_str() : nullptr, AS_PROGRAM, space))
return;
- if (space->device().memory().has_space(AS_OPCODES))
- decrypted_space = &space->device().memory().space(AS_OPCODES);
- else
- decrypted_space = space;
/* determine the width of the bytes */
device_disasm_interface *dasmintf;
@@ -2429,104 +2553,72 @@ void debugger_commands::execute_dasm(int ref, const std::vector<std::string> &pa
m_console.printf("No disassembler available for %s\n", space->device().name());
return;
}
- minbytes = dasmintf->min_opcode_bytes();
- maxbytes = dasmintf->max_opcode_bytes();
- byteswidth = 0;
- if (bytes)
- {
- byteswidth = (maxbytes + (minbytes - 1)) / minbytes;
- byteswidth *= (2 * minbytes) + 1;
- }
- /* open the file */
- f = fopen(params[0].c_str(), "w");
- if (!f)
- {
- m_console.printf("Error opening file '%s'\n", params[0].c_str());
- return;
- }
+ /* build the data, check the maximum size of the opcodes and disasm */
+ std::vector<offs_t> pcs;
+ std::vector<std::string> instructions;
+ std::vector<std::string> tpc;
+ std::vector<std::string> topcodes;
+ int max_opcodes_size = 0;
+ int max_disasm_size = 0;
+
+ debug_disasm_buffer buffer(space->device());
- /* now write the data out */
- util::ovectorstream output;
- util::ovectorstream disasm;
- output.reserve(512);
for (u64 i = 0; i < length; )
{
- int pcbyte = space->address_to_byte(offset + i) & space->bytemask();
- const char *comment;
- offs_t tempaddr;
- int numbytes = 0;
- output.clear();
- output.rdbuf()->clear();
- disasm.clear();
- disasm.seekp(0);
+ std::string instruction;
+ offs_t next_offset;
+ offs_t size;
+ u32 info;
+ buffer.disassemble(offset, instruction, next_offset, size, info);
+ pcs.push_back(offset);
+ instructions.emplace_back(instruction);
+ tpc.emplace_back(buffer.pc_to_string(offset));
+ topcodes.emplace_back(buffer.data_to_string(offset, size, true));
- /* print the address */
- stream_format(output, "%0*X: ", space->logaddrchars(), u32(space->byte_to_address(pcbyte)));
+ int osize = topcodes.back().size();
+ if(osize > max_opcodes_size)
+ max_opcodes_size = osize;
- /* make sure we can translate the address */
- tempaddr = pcbyte;
- if (space->device().memory().translate(space->spacenum(), TRANSLATE_FETCH_DEBUG, tempaddr))
- {
- {
- u8 opbuf[64], argbuf[64];
+ int dsize = instructions.back().size();
+ if(dsize > max_disasm_size)
+ max_disasm_size = dsize;
- /* fetch the bytes up to the maximum */
- for (numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = m_cpu.read_opcode(*decrypted_space, pcbyte + numbytes, 1);
- argbuf[numbytes] = m_cpu.read_opcode(*space, pcbyte + numbytes, 1);
- }
+ i += size;
+ offset = next_offset;
+ }
- /* disassemble the result */
- i += numbytes = dasmintf->disassemble(disasm, offset + i, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
- }
+ /* write the data */
+ std::ofstream f(params[0]);
+ if (!f.good())
+ {
+ m_console.printf("Error opening file '%s'\n", params[0]);
+ return;
+ }
- /* print the bytes */
- if (bytes)
- {
- auto const startdex = output.tellp();
- numbytes = space->address_to_byte(numbytes);
- for (j = 0; j < numbytes; j += minbytes)
- stream_format(output, "%0*X ", minbytes * 2, m_cpu.read_opcode(*decrypted_space, pcbyte + j, minbytes));
- if ((output.tellp() - startdex) < byteswidth)
- stream_format(output, "%*s", byteswidth - (output.tellp() - startdex), "");
- stream_format(output, " ");
- }
- }
- else
+ if (bytes)
+ {
+ for(unsigned int i=0; i != pcs.size(); i++)
{
- disasm << "<unmapped>";
- i += minbytes;
+ const char *comment = space->device().debug()->comment_text(pcs[i]);
+ if (comment)
+ util::stream_format(f, "%s: %-*s %-*s // %s\n", tpc[i], max_opcodes_size, topcodes[i], max_disasm_size, instructions[i], comment);
+ else
+ util::stream_format(f, "%s: %-*s %s\n", tpc[i], max_opcodes_size, topcodes[i], instructions[i]);
}
-
- /* add the disassembly */
- disasm.put('\0');
- stream_format(output, "%s", &disasm.vec()[0]);
-
- /* attempt to add the comment */
- comment = space->device().debug()->comment_text(tempaddr);
- if (comment != nullptr)
+ }
+ else
+ {
+ for(unsigned int i=0; i != pcs.size(); i++)
{
- /* somewhat arbitrary guess as to how long most disassembly lines will be [column 60] */
- if (output.tellp() < 60)
- {
- /* pad the comment space out to 60 characters and null-terminate */
- while (output.tellp() < 60) output.put(' ');
-
- stream_format(output, "// %s", comment);
- }
+ const char *comment = space->device().debug()->comment_text(pcs[i]);
+ if (comment)
+ util::stream_format(f, "%s: %-*s // %s\n", tpc[i], max_disasm_size, instructions[i], comment);
else
- stream_format(output, "\t// %s", comment);
+ util::stream_format(f, "%s: %s\n", tpc[i], instructions[i]);
}
-
- /* output the result */
- auto const &text(output.vec());
- fprintf(f, "%.*s\n", int(unsigned(text.size())), &text[0]);
}
- /* close the file */
- fclose(f);
m_console.printf("Data dumped successfully\n");
}
@@ -2640,13 +2732,9 @@ void debugger_commands::execute_traceflush(int ref, const std::vector<std::strin
void debugger_commands::execute_history(int ref, const std::vector<std::string> &params)
{
/* validate parameters */
- address_space *space, *decrypted_space;
+ address_space *space;
if (!validate_cpu_space_parameter(!params.empty() ? params[0].c_str() : nullptr, AS_PROGRAM, space))
return;
- if (space->device().memory().has_space(AS_OPCODES))
- decrypted_space = &space->device().memory().space(AS_OPCODES);
- else
- decrypted_space = space;
u64 count = device_debug::HISTORY_SIZE;
if (params.size() > 1 && !validate_number_parameter(params[1], count))
@@ -2665,25 +2753,19 @@ void debugger_commands::execute_history(int ref, const std::vector<std::string>
m_console.printf("No disassembler available for %s\n", space->device().name());
return;
}
- int maxbytes = dasmintf->max_opcode_bytes();
+
+ debug_disasm_buffer buffer(space->device());
+
for (int index = 0; index < (int) count; index++)
{
offs_t pc = debug->history_pc(-index);
+ std::string instruction;
+ offs_t next_offset;
+ offs_t size;
+ u32 info;
+ buffer.disassemble(pc, instruction, next_offset, size, info);
- /* fetch the bytes up to the maximum */
- offs_t pcbyte = space->address_to_byte(pc) & space->bytemask();
- u8 opbuf[64], argbuf[64];
- for (int numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = m_cpu.read_opcode(*decrypted_space, pcbyte + numbytes, 1);
- argbuf[numbytes] = m_cpu.read_opcode(*space, pcbyte + numbytes, 1);
- }
-
- util::ovectorstream buffer;
- dasmintf->disassemble(buffer, pc, opbuf, argbuf);
- buffer.put('\0');
-
- m_console.printf("%0*X: %s\n", space->logaddrchars(), pc, &buffer.vec()[0]);
+ m_console.printf("%s: %s\n", buffer.pc_to_string(pc), instruction);
}
}
@@ -2882,7 +2964,7 @@ void debugger_commands::execute_map(int ref, const std::vector<std::string> &par
for (intention = TRANSLATE_READ_DEBUG; intention <= TRANSLATE_FETCH_DEBUG; intention++)
{
static const char *const intnames[] = { "Read", "Write", "Fetch" };
- taddress = space->address_to_byte(address) & space->bytemask();
+ taddress = address & space->addrmask();
if (space->device().memory().translate(space->spacenum(), intention, taddress))
{
const char *mapname = space->get_handler_string((intention == TRANSLATE_WRITE_DEBUG) ? read_or_write::WRITE : read_or_write::READ, taddress);
@@ -2890,7 +2972,7 @@ void debugger_commands::execute_map(int ref, const std::vector<std::string> &par
"%7s: %0*X logical == %0*X physical -> %s\n",
intnames[intention & 3],
space->logaddrchars(), address,
- space->addrchars(), space->byte_to_address(taddress),
+ space->addrchars(), taddress,
mapname);
}
else
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index 8b0cd786bff..3b0f2e98b6b 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -344,7 +344,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo)
if (!echo)
printf(">%s\n", command.c_str());
printf(" %*s^\n", CMDERR_ERROR_OFFSET(result), "");
- printf("%s\n", cmderr_to_string(result));
+ printf("%s\n", cmderr_to_string(result).c_str());
}
/* update all views */
@@ -404,8 +404,9 @@ void debugger_console::register_command(const char *command, u32 flags, int ref,
for a given command error
-------------------------------------------------*/
-const char *debugger_console::cmderr_to_string(CMDERR error)
+std::string debugger_console::cmderr_to_string(CMDERR error)
{
+ int offset = CMDERR_ERROR_OFFSET(error);
switch (CMDERR_ERROR_CLASS(error))
{
case CMDERR_UNKNOWN_COMMAND: return "unknown command";
@@ -414,7 +415,8 @@ const char *debugger_console::cmderr_to_string(CMDERR error)
case CMDERR_UNBALANCED_QUOTES: return "unbalanced quotes";
case CMDERR_NOT_ENOUGH_PARAMS: return "not enough parameters for command";
case CMDERR_TOO_MANY_PARAMS: return "too many parameters for command";
- case CMDERR_EXPRESSION_ERROR: return "error in assignment expression";
+ case CMDERR_EXPRESSION_ERROR: return string_format("error in assignment expression: %s",
+ expression_error(static_cast<expression_error::error_code>(offset)).code_string());
default: return "unknown error";
}
}
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 54bc3bf6772..7cc1231d4c9 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -104,7 +104,7 @@ public:
vprintf_wrap(wrapcol, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
- static const char * cmderr_to_string(CMDERR error);
+ static std::string cmderr_to_string(CMDERR error);
private:
void exit();
diff --git a/src/emu/debug/debugcpu.cpp b/src/emu/debug/debugcpu.cpp
index 46ad9e04683..c5f5a532599 100644
--- a/src/emu/debug/debugcpu.cpp
+++ b/src/emu/debug/debugcpu.cpp
@@ -10,6 +10,7 @@
#include "emu.h"
#include "debugcpu.h"
+#include "debugbuf.h"
#include "express.h"
#include "debugcon.h"
@@ -363,7 +364,7 @@ u8 debugger_cpu::read_byte(address_space &space, offs_t address, bool apply_tran
device_memory_interface &memory = space.device().memory();
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* translate if necessary; if not mapped, return 0xff */
u8 result;
@@ -388,7 +389,7 @@ 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)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
u16 result;
if (!WORD_ALIGNED(address))
@@ -429,7 +430,7 @@ 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)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
u32 result;
if (!DWORD_ALIGNED(address))
@@ -469,7 +470,7 @@ 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)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
u64 result;
if (!QWORD_ALIGNED(address))
@@ -531,7 +532,7 @@ void debugger_cpu::write_byte(address_space &space, offs_t address, u8 data, boo
device_memory_interface &memory = space.device().memory();
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* translate if necessary; if not mapped, we're done */
if (apply_translation && !memory.translate(space.spacenum(), TRANSLATE_WRITE_DEBUG, address))
@@ -553,7 +554,7 @@ void debugger_cpu::write_byte(address_space &space, offs_t address, u8 data, boo
void debugger_cpu::write_word(address_space &space, offs_t address, u16 data, bool apply_translation)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* if this is a misaligned write, or if there are no word writers, just read two bytes */
if (!WORD_ALIGNED(address))
@@ -596,7 +597,7 @@ void debugger_cpu::write_word(address_space &space, offs_t address, u16 data, bo
void debugger_cpu::write_dword(address_space &space, offs_t address, u32 data, bool apply_translation)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* if this is a misaligned write, or if there are no dword writers, just read two words */
if (!DWORD_ALIGNED(address))
@@ -639,7 +640,7 @@ void debugger_cpu::write_dword(address_space &space, offs_t address, u32 data, b
void debugger_cpu::write_qword(address_space &space, offs_t address, u64 data, bool apply_translation)
{
/* mask against the logical byte mask */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* if this is a misaligned write, or if there are no qword writers, just read two dwords */
if (!QWORD_ALIGNED(address))
@@ -703,7 +704,7 @@ u64 debugger_cpu::read_opcode(address_space &space, offs_t address, int size)
u64 result = ~u64(0) & (~u64(0) >> (64 - 8*size));
/* keep in logical range */
- address &= space.logbytemask();
+ address &= space.logaddrmask();
/* if we're bigger than the address bus, break into smaller pieces */
if (size > space.data_width() / 8)
@@ -723,7 +724,7 @@ u64 debugger_cpu::read_opcode(address_space &space, offs_t address, int size)
return result;
/* keep in physical range */
- address &= space.bytemask();
+ address &= space.addrmask();
/* switch off the size and handle unaligned accesses */
switch (size)
@@ -1559,8 +1560,12 @@ device_debug::device_debug(device_t &device)
std::string tempstr;
for (const auto &entry : m_state->state_entries())
{
- strmakelower(tempstr.assign(entry->symbol()));
- m_symtable.add(tempstr.c_str(), (void *)(uintptr_t)entry->index(), get_state, set_state, entry->format_string());
+ // TODO: floating point registers
+ if (!entry->is_float())
+ {
+ strmakelower(tempstr.assign(entry->symbol()));
+ m_symtable.add(tempstr.c_str(), (void *)(uintptr_t)entry->index(), get_state, entry->writeable() ? set_state : nullptr, entry->format_string());
+ }
}
}
@@ -2483,33 +2488,15 @@ bool device_debug::comment_import(util::xml::data_node const &cpunode, bool is_i
u32 device_debug::compute_opcode_crc32(offs_t pc) const
{
- // Basically the same thing as dasm_wrapped, but with some tiny savings
- assert(m_memory != nullptr);
-
- // determine the adjusted PC
- address_space &decrypted_space = m_memory->has_space(AS_OPCODES) ? m_memory->space(AS_OPCODES) : m_memory->space(AS_PROGRAM);
- address_space &space = m_memory->space(AS_PROGRAM);
- offs_t pcbyte = space.address_to_byte(pc) & space.bytemask();
-
- // fetch the bytes up to the maximum
- u8 opbuf[64], argbuf[64];
- int maxbytes = (m_disasm != nullptr) ? m_disasm->max_opcode_bytes() : 1;
- for (int numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(decrypted_space, pcbyte + numbytes, 1);
- argbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(space, pcbyte + numbytes, 1);
- }
+ std::vector<u8> opbuf;
+ debug_disasm_buffer buffer(device());
- u32 numbytes = maxbytes;
- if (m_disasm != nullptr)
- {
- // disassemble to our buffer
- std::ostringstream diasmbuf;
- numbytes = m_disasm->disassemble(diasmbuf, pc, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
- }
+ // disassemble the current instruction and get the flags
+ u32 dasmresult = buffer.disassemble_info(pc);
+ buffer.data_get(pc, dasmresult & util::disasm_interface::LENGTHMASK, true, opbuf);
// return a CRC of the exact count of opcode bytes
- return core_crc32(0, opbuf, numbytes);
+ return core_crc32(0, &opbuf[0], opbuf.size());
}
@@ -2589,26 +2576,29 @@ void device_debug::compute_debug_flags()
void device_debug::prepare_for_step_overout(offs_t pc)
{
+ debug_disasm_buffer buffer(device());
+
// disassemble the current instruction and get the flags
- std::string dasmbuffer;
- offs_t dasmresult = dasm_wrapped(dasmbuffer, pc);
+ u32 dasmresult = buffer.disassemble_info(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)
+ if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
{
- int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT;
- pc += dasmresult & DASMFLAG_LENGTHMASK;
+ int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT;
+ pc = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK);
// if we need to skip additional instructions, advance as requested
- while (extraskip-- > 0)
- pc += dasm_wrapped(dasmbuffer, pc) & DASMFLAG_LENGTHMASK;
+ while (extraskip-- > 0) {
+ u32 result = buffer.disassemble_info(pc);
+ pc += buffer.next_pc_wrap(pc, result & util::disasm_interface::LENGTHMASK);
+ }
m_stepaddr = pc;
}
// if we're stepping out and this isn't a step out instruction, reset the steps until stop to a high number
if ((m_flags & DEBUG_FLAG_STEPPING_OUT) != 0)
{
- if ((dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OUT) == 0)
+ if ((dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OUT) == 0)
m_stepsleft = 100;
else
m_stepsleft = 1;
@@ -2881,38 +2871,6 @@ void device_debug::hotspot_check(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
-//-------------------------------------------------
-
-u32 device_debug::dasm_wrapped(std::string &buffer, offs_t pc)
-{
- assert(m_memory != nullptr && m_disasm != nullptr);
-
- // determine the adjusted PC
- address_space &decrypted_space = m_memory->has_space(AS_OPCODES) ? m_memory->space(AS_OPCODES) : m_memory->space(AS_PROGRAM);
- address_space &space = m_memory->space(AS_PROGRAM);
- offs_t pcbyte = space.address_to_byte(pc) & space.bytemask();
-
- // fetch the bytes up to the maximum
- u8 opbuf[64], argbuf[64];
- int maxbytes = m_disasm->max_opcode_bytes();
- for (int numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(decrypted_space, pcbyte + numbytes, 1);
- argbuf[numbytes] = m_device.machine().debugger().cpu().read_opcode(space, pcbyte + numbytes, 1);
- }
-
- // disassemble to our buffer
- std::ostringstream stream;
- uint32_t result = m_disasm->disassemble(stream, pc, opbuf, argbuf);
- buffer = stream.str();
- return result;
-}
-
-
-//-------------------------------------------------
// get_current_pc - getter callback for a device's
// current instruction pointer
//-------------------------------------------------
@@ -3090,8 +3048,8 @@ device_debug::watchpoint::watchpoint(device_debug* debugInterface,
m_index(index),
m_enabled(true),
m_type(type),
- m_address(space.address_to_byte(address) & space.bytemask()),
- m_length(space.address_to_byte(length)),
+ m_address(address & space.addrmask()),
+ m_length(length),
m_condition(&symbols, (condition != nullptr) ? condition : "1"),
m_action((action != nullptr) ? action : "")
{
@@ -3253,35 +3211,24 @@ void device_debug::tracer::update(offs_t pc)
if (!m_action.empty())
m_debug.m_device.machine().debugger().console().execute_command(m_action, false);
- // print the address
- std::string buffer;
- int logaddrchars = m_debug.logaddrchars();
- if (m_debug.is_octal())
- {
- buffer = string_format("%0*o: ", logaddrchars*3/2, pc);
- }
- else
- {
- buffer = string_format("%0*X: ", logaddrchars, pc);
- }
-
- // print the disassembly
- std::string dasm;
- offs_t dasmresult = m_debug.dasm_wrapped(dasm, pc);
- buffer.append(dasm);
+ debug_disasm_buffer buffer(m_debug.device());
+ std::string instruction;
+ offs_t next_pc, size;
+ u32 dasmresult;
+ buffer.disassemble(pc, instruction, next_pc, size, dasmresult);
// output the result
- fprintf(&m_file, "%s\n", buffer.c_str());
+ fprintf(&m_file, "%s: %s\n", buffer.pc_to_string(pc).c_str(), instruction.c_str());
// do we need to step the trace over this instruction?
- if (m_trace_over && (dasmresult & DASMFLAG_SUPPORTED) != 0 && (dasmresult & DASMFLAG_STEP_OVER) != 0)
+ if (m_trace_over && (dasmresult & util::disasm_interface::SUPPORTED) != 0 && (dasmresult & util::disasm_interface::STEP_OVER) != 0)
{
- int extraskip = (dasmresult & DASMFLAG_OVERINSTMASK) >> DASMFLAG_OVERINSTSHIFT;
- offs_t trace_over_target = pc + (dasmresult & DASMFLAG_LENGTHMASK);
+ int extraskip = (dasmresult & util::disasm_interface::OVERINSTMASK) >> util::disasm_interface::OVERINSTSHIFT;
+ offs_t trace_over_target = buffer.next_pc_wrap(pc, dasmresult & util::disasm_interface::LENGTHMASK);
// if we need to skip additional instructions, advance as requested
while (extraskip-- > 0)
- trace_over_target += m_debug.dasm_wrapped(dasm, trace_over_target) & DASMFLAG_LENGTHMASK;
+ trace_over_target = buffer.next_pc_wrap(trace_over_target, buffer.disassemble_info(trace_over_target) & util::disasm_interface::LENGTHMASK);
m_trace_over_target = trace_over_target;
}
diff --git a/src/emu/debug/debugcpu.h b/src/emu/debug/debugcpu.h
index 2ea78c3fe20..e00ac9576cc 100644
--- a/src/emu/debug/debugcpu.h
+++ b/src/emu/debug/debugcpu.h
@@ -278,7 +278,6 @@ private:
// internal helpers
void prepare_for_step_overout(offs_t pc);
- u32 dasm_wrapped(std::string &buffer, offs_t pc);
void errorlog_write_line(const char *line);
// breakpoint and watchpoint helpers
diff --git a/src/emu/debug/dvdisasm.cpp b/src/emu/debug/dvdisasm.cpp
index 1051365c561..9ad6cb968c2 100644
--- a/src/emu/debug/dvdisasm.cpp
+++ b/src/emu/debug/dvdisasm.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Olivier Galibert
/*********************************************************************
dvdisasm.c
@@ -14,7 +14,6 @@
#include "debugcpu.h"
#include "debugger.h"
-
//**************************************************************************
// DEBUG VIEW DISASM SOURCE
//**************************************************************************
@@ -25,7 +24,6 @@
debug_view_disasm_source::debug_view_disasm_source(const char *name, device_t &device)
: debug_view_source(name, &device),
- m_disasmintf(dynamic_cast<device_disasm_interface *>(&device)),
m_space(device.memory().space(AS_PROGRAM)),
m_decrypted_space(device.memory().has_space(AS_OPCODES) ? device.memory().space(AS_OPCODES) : device.memory().space(AS_PROGRAM))
{
@@ -49,23 +47,17 @@ debug_view_disasm::debug_view_disasm(running_machine &machine, debug_view_osd_up
m_right_column(DASM_RIGHTCOL_RAW),
m_backwards_steps(3),
m_dasm_width(DEFAULT_DASM_WIDTH),
- m_last_direct_raw(nullptr),
- m_last_direct_decrypted(nullptr),
- m_last_change_count(0),
- m_last_pcbyte(0),
- m_divider1(0),
- m_divider2(0),
- m_divider3(0),
+ m_previous_pc(1),
m_expression(machine)
{
// fail if no available sources
enumerate_sources();
- if (m_source_list.count() == 0)
+ if(m_source_list.count() == 0)
throw std::bad_alloc();
// count the number of comments
int total_comments = 0;
- for (const debug_view_source &source : m_source_list)
+ for(const debug_view_source &source : m_source_list)
{
const debug_view_disasm_source &dasmsource = downcast<const debug_view_disasm_source &>(source);
total_comments += dasmsource.device()->debug()->comment_count();
@@ -98,10 +90,10 @@ void debug_view_disasm::enumerate_sources()
// iterate over devices with disassembly interfaces
std::string name;
- for (device_disasm_interface &dasm : disasm_interface_iterator(machine().root_device()))
+ for(device_disasm_interface &dasm : disasm_interface_iterator(machine().root_device()))
{
name = string_format("%s '%s'", dasm.device().name(), dasm.device().tag());
- if (dasm.device().memory().space_config(AS_PROGRAM)!=nullptr)
+ if(dasm.device().memory().space_config(AS_PROGRAM)!=nullptr)
m_source_list.append(*global_alloc(debug_view_disasm_source(name.c_str(), dasm.device())));
}
@@ -117,10 +109,10 @@ void debug_view_disasm::enumerate_sources()
void debug_view_disasm::view_notify(debug_view_notification type)
{
- if (type == VIEW_NOTIFY_CURSOR_CHANGED)
+ if(type == VIEW_NOTIFY_CURSOR_CHANGED)
adjust_visible_y_for_cursor();
- else if (type == VIEW_NOTIFY_SOURCE_CHANGED)
+ else if(type == VIEW_NOTIFY_SOURCE_CHANGED)
m_expression.set_context(&downcast<const debug_view_disasm_source *>(m_source)->device()->debug()->symtable());
}
@@ -136,29 +128,29 @@ void debug_view_disasm::view_char(int chval)
u8 end_buffer = 3;
s32 temp;
- switch (chval)
+ switch(chval)
{
case DCH_UP:
- if (m_cursor.y > 0)
+ if(m_cursor.y > 0)
m_cursor.y--;
break;
case DCH_DOWN:
- if (m_cursor.y < m_total.y - 1)
+ if(m_cursor.y < m_total.y - 1)
m_cursor.y++;
break;
case DCH_PUP:
- temp = m_cursor.y - (m_visible.y - end_buffer);
- if (temp < 0)
+ temp = m_cursor.y -(m_visible.y - end_buffer);
+ if(temp < 0)
m_cursor.y = 0;
else
m_cursor.y = temp;
break;
case DCH_PDOWN:
- temp = m_cursor.y + (m_visible.y - end_buffer);
- if (temp > m_total.y - 1)
+ temp = m_cursor.y +(m_visible.y - end_buffer);
+ if(temp > m_total.y - 1)
m_cursor.y = m_total.y - 1;
else
m_cursor.y = temp;
@@ -167,11 +159,11 @@ void debug_view_disasm::view_char(int chval)
case DCH_HOME: // set the active column to the PC
{
const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
- offs_t pc = source.m_space.address_to_byte(source.device()->safe_pcbase()) & source.m_space.logbytemask();
+ offs_t pc = source.device()->safe_pcbase() & source.m_space.logaddrmask();
// figure out which row the pc is on
- for (unsigned int curline = 0; curline < m_dasm.size(); curline++)
- if (m_dasm[curline].m_byteaddress == pc)
+ for(unsigned int curline = 0; curline < m_dasm.size(); curline++)
+ if(m_dasm[curline].m_address == pc)
m_cursor.y = curline;
break;
}
@@ -186,7 +178,7 @@ void debug_view_disasm::view_char(int chval)
}
/* send a cursor changed notification */
- if (m_cursor.y != origcursor.y)
+ if(m_cursor.y != origcursor.y)
{
begin_update();
view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
@@ -208,7 +200,7 @@ void debug_view_disasm::view_click(const int button, const debug_view_xy& pos)
/* cursor popup|toggle */
bool cursorVisible = true;
- if (m_cursor.y == origcursor.y)
+ if(m_cursor.y == origcursor.y)
{
cursorVisible = !m_cursor_visible;
}
@@ -221,218 +213,174 @@ void debug_view_disasm::view_click(const int button, const debug_view_xy& pos)
end_update();
}
+void debug_view_disasm::generate_from_address(debug_disasm_buffer &buffer, offs_t address)
+{
+ m_dasm.clear();
+ for(int i=0; i != m_total.y; i++) {
+ std::string dasm;
+ offs_t size;
+ offs_t next_address;
+ u32 info;
+ buffer.disassemble(address, dasm, next_address, size, info);
+ m_dasm.emplace_back(address, size, dasm);
+ address = next_address;
+ }
+}
-//-------------------------------------------------
-// find_pc_backwards - back up the specified
-// number of instructions from the given PC
-//-------------------------------------------------
-
-offs_t debug_view_disasm::find_pc_backwards(offs_t targetpc, int numinstrs)
+bool debug_view_disasm::generate_with_pc(debug_disasm_buffer &buffer, offs_t pc)
{
- auto dis = machine().disable_side_effect();
+ // Consider that instructions are 64 bytes max
const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+ int shift = source.m_space.addrbus_shift();
- // compute the increment
- int minlen = source.m_space.byte_to_address(source.m_disasmintf->min_opcode_bytes());
- if (minlen == 0) minlen = 1;
- int maxlen = source.m_space.byte_to_address(source.m_disasmintf->max_opcode_bytes());
- if (maxlen == 0) maxlen = 1;
-
- // start off numinstrs back
- offs_t curpc = targetpc - minlen * numinstrs;
- if (curpc > targetpc)
- curpc = 0;
-
- /* loop until we find what we are looking for */
- offs_t targetpcbyte = source.m_space.address_to_byte(targetpc) & source.m_space.logbytemask();
- offs_t fillpcbyte = targetpcbyte;
- offs_t lastgoodpc = targetpc;
- while (1)
- {
- // fill the buffer up to the target
- offs_t curpcbyte = source.m_space.address_to_byte(curpc) & source.m_space.logbytemask();
- u8 opbuf[1024], argbuf[1024];
- while (curpcbyte < fillpcbyte)
- {
- fillpcbyte--;
- opbuf[1000 + fillpcbyte - targetpcbyte] = machine().debugger().cpu().read_opcode(source.m_decrypted_space, fillpcbyte, 1);
- argbuf[1000 + fillpcbyte - targetpcbyte] = machine().debugger().cpu().read_opcode(source.m_space, fillpcbyte, 1);
+ offs_t backwards_offset;
+ if(shift < 0)
+ backwards_offset = 64 >> -shift;
+ else if(shift == 0)
+ backwards_offset = 64;
+ else
+ backwards_offset = 64 << shift;
+
+ m_dasm.clear();
+ offs_t address = (pc - m_backwards_steps*backwards_offset) & source.m_space.logaddrmask();
+ // Handle wrap at 0
+ if(address > pc)
+ address = 0;
+
+ util::disasm_interface *intf = dynamic_cast<device_disasm_interface &>(*source.device()).get_disassembler();
+ if(intf->interface_flags() & util::disasm_interface::NONLINEAR_PC) {
+ offs_t lpc = intf->pc_real_to_linear(pc);
+ while(intf->pc_real_to_linear(address) < lpc) {
+ std::string dasm;
+ offs_t size;
+ offs_t next_address;
+ u32 info;
+ buffer.disassemble(address, dasm, next_address, size, info);
+ m_dasm.emplace_back(address, size, dasm);
+ if(intf->pc_real_to_linear(address) > intf->pc_real_to_linear(next_address))
+ return false;
+ address = next_address;
}
- // loop until we get past the target instruction
- int instcount = 0;
- int instlen;
- offs_t scanpc;
- for (scanpc = curpc; scanpc < targetpc; scanpc += instlen)
- {
- offs_t scanpcbyte = source.m_space.address_to_byte(scanpc) & source.m_space.logbytemask();
- offs_t physpcbyte = scanpcbyte;
-
- // get the disassembly, but only if mapped
- instlen = 1;
- if (source.m_space.device().memory().translate(source.m_space.spacenum(), TRANSLATE_FETCH, physpcbyte))
- {
- std::ostringstream dasmbuffer;
- instlen = source.m_disasmintf->disassemble(dasmbuffer, scanpc, &opbuf[1000 + scanpcbyte - targetpcbyte], &argbuf[1000 + scanpcbyte - targetpcbyte]) & DASMFLAG_LENGTHMASK;
- }
-
- // count this one
- instcount++;
+ } else {
+ while(address < pc) {
+ std::string dasm;
+ offs_t size;
+ offs_t next_address;
+ u32 info;
+ buffer.disassemble(address, dasm, next_address, size, info);
+ m_dasm.emplace_back(address, size, dasm);
+ if(address > next_address)
+ return false;
+ address = next_address;
}
+ }
- // if we ended up right on targetpc, this is a good candidate
- if (scanpc == targetpc && instcount <= numinstrs)
- lastgoodpc = curpc;
-
- // we're also done if we go back too far
- if (targetpc - curpc >= numinstrs * maxlen)
- break;
+ if(address != pc)
+ return false;
- // and if we hit 0, we're done
- if (curpc == 0)
- break;
+ if(m_dasm.size() > m_backwards_steps)
+ m_dasm.erase(m_dasm.begin(), m_dasm.begin() + (m_dasm.size() - m_backwards_steps));
- // back up one more and try again
- curpc -= minlen;
- if (curpc > targetpc)
- curpc = 0;
+ while(m_dasm.size() < m_total.y) {
+ std::string dasm;
+ offs_t size;
+ offs_t next_address;
+ u32 info;
+ buffer.disassemble(address, dasm, next_address, size, info);
+ m_dasm.emplace_back(address, size, dasm);
+ address = next_address;
}
-
- return lastgoodpc;
+ return true;
}
-
-//-------------------------------------------------
-// generate_bytes - generate the opcode byte
-// values
-//-------------------------------------------------
-
-std::string debug_view_disasm::generate_bytes(offs_t pcbyte, int numbytes, int granularity, bool encrypted)
+int debug_view_disasm::address_position(offs_t pc) const
{
- const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
- const int char_num = source.m_space.is_octal() ? 3 : 2;
- std::ostringstream ostr;
-
- for (int byte = 0; byte < numbytes; byte += granularity) {
- if (byte)
- ostr << ' ';
- util::stream_format(ostr, source.m_space.is_octal() ? "%0*o" : "%0*X", granularity * char_num, machine().debugger().cpu().read_opcode(encrypted ? source.m_space : source.m_decrypted_space, pcbyte + byte, granularity));
- }
-
- return ostr.str();
+ for(int i=0; i != int(m_dasm.size()); i++)
+ if(m_dasm[i].m_address == pc)
+ return i;
+ return -1;
}
-
-//-------------------------------------------------
-// recompute - recompute selected info for the
-// disassembly view
-//-------------------------------------------------
-
-bool debug_view_disasm::recompute(offs_t pc, int startline, int lines)
+void debug_view_disasm::generate_dasm(debug_disasm_buffer &buffer, offs_t pc)
{
- auto dis = machine().disable_side_effect();
-
- bool changed = false;
- const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
- const int char_num = source.m_space.is_octal() ? 3 : 2;
-
- // determine how many characters we need for an address and set the divider
- m_divider1 = 1 + (source.m_space.logaddrchars()/2*char_num) + 1;
+ bool pc_changed = pc != m_previous_pc;
+ m_previous_pc = pc;
+ if(strcmp(m_expression.string(), "curpc")) {
+ if(m_expression.dirty()) {
+ m_topleft.x = 0;
+ m_topleft.y = 0;
+ }
+ generate_from_address(buffer, m_expression.value());
+ return;
+ }
- // assume a fixed number of characters for the disassembly
- m_divider2 = m_divider1 + 1 + m_dasm_width + 1;
+ if(address_position(pc) != -1) {
+ generate_from_address(buffer, m_dasm[0].m_address);
+ int pos = address_position(pc);
+ if(pos != -1) {
+ if(!pc_changed)
+ return;
+ if(pos >= m_topleft.y && pos < m_topleft.y + m_visible.y)
+ return;
+ if(pos < m_total.y - m_visible.y) {
+ m_topleft.x = 0;
+ m_topleft.y = pos - m_backwards_steps;
+ return;
+ }
+ }
+ }
- // determine how many bytes we might need to display
- const int minbytes = source.m_disasmintf->min_opcode_bytes();
- const int maxbytes = source.m_disasmintf->max_opcode_bytes();
+ m_topleft.x = 0;
+ m_topleft.y = 0;
- // ensure that the PC is aligned to the minimum opcode size
- pc &= ~source.m_space.byte_to_address_end(minbytes - 1);
+ if(generate_with_pc(buffer, pc))
+ return;
- // set the width of the third column according to display mode
- if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED)
- {
- int const maxbytes_clamped = (std::min)(maxbytes, DASM_MAX_BYTES);
- m_total.x = m_divider2 + 1 + char_num * maxbytes_clamped + (maxbytes_clamped / minbytes - 1) + 1;
- }
- else if (m_right_column == DASM_RIGHTCOL_COMMENTS)
- m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH
- else
- m_total.x = m_divider2 + 1;
+ generate_from_address(buffer, pc);
+}
- // allocate dasm array
- m_dasm.resize(m_total.y);
+void debug_view_disasm::complete_information(const debug_view_disasm_source &source, debug_disasm_buffer &buffer, offs_t pc)
+{
+ for(auto &dasm : m_dasm) {
+ offs_t adr = dasm.m_address;
- // comparison buffer to detect whether data changed when doing only one line
- dasm_line comparison_buffer;
+ dasm.m_tadr = buffer.pc_to_string(adr);
+ dasm.m_topcodes = buffer.data_to_string(adr, dasm.m_size, true);
+ dasm.m_tparams = buffer.data_to_string(adr, dasm.m_size, false);
- // iterate over lines
- for (int line = 0; line < lines; line++)
- {
- // convert PC to a byte offset
- const offs_t pcbyte = source.m_space.address_to_byte(pc) & source.m_space.logbytemask();
-
- // save a copy of the previous line as a backup if we're only doing one line
- const auto instr = startline + line;
- if (lines == 1)
- comparison_buffer = m_dasm[instr];
-
- // convert back and set the address of this instruction
- std::ostringstream oadr;
- m_dasm[instr].m_byteaddress = pcbyte;
- util::stream_format(oadr,
- source.m_space.is_octal() ? " %0*o " : " %0*X ",
- source.m_space.logaddrchars()/2*char_num, source.m_space.byte_to_address(pcbyte));
- m_dasm[instr].m_adr = oadr.str();
-
- // make sure we can translate the address, and then disassemble the result
- std::ostringstream dasm;
- int numbytes = 0;
- offs_t physpcbyte = pcbyte;
- if (source.m_space.device().memory().translate(source.m_space.spacenum(), TRANSLATE_FETCH_DEBUG, physpcbyte))
- {
- u8 opbuf[64], argbuf[64];
+ dasm.m_is_pc = adr == pc;
- // fetch the bytes up to the maximum
- for (numbytes = 0; numbytes < maxbytes; numbytes++)
- {
- opbuf[numbytes] = machine().debugger().cpu().read_opcode(source.m_decrypted_space, pcbyte + numbytes, 1);
- argbuf[numbytes] = machine().debugger().cpu().read_opcode(source.m_space, pcbyte + numbytes, 1);
+ dasm.m_is_bp = false;
+ for(device_debug::breakpoint *bp = source.device()->debug()->breakpoint_first(); bp != nullptr; bp = bp->next())
+ if(adr ==(bp->address() & source.m_space.logaddrmask())) {
+ dasm.m_is_bp = true;
+ break;
}
- // disassemble the result
- pc += numbytes = source.m_disasmintf->disassemble(dasm, pc & source.m_space.logaddrmask(), opbuf, argbuf) & DASMFLAG_LENGTHMASK;
- }
- else
- dasm << "<unmapped>";
-
- m_dasm[instr].m_dasm = dasm.str();
+ dasm.m_is_visited = source.device()->debug()->track_pc_visited(adr);
- // generate the byte views
- std::ostringstream bytes_raw;
- numbytes = source.m_space.address_to_byte(numbytes) & source.m_space.logbytemask();
- m_dasm[instr].m_rawdata = generate_bytes(pcbyte, numbytes, minbytes, false);
- m_dasm[instr].m_encdata = generate_bytes(pcbyte, numbytes, minbytes, true);
+ const char *comment = source.device()->debug()->comment_text(adr);
+ if(comment)
+ dasm.m_comment = comment;
+ }
+}
- // get and add the comment, if present
- const offs_t comment_address = source.m_space.byte_to_address(m_dasm[instr].m_byteaddress);
- const char *const text = source.device()->debug()->comment_text(comment_address);
- if (text != nullptr)
- m_dasm[instr].m_comment = text;
+//-------------------------------------------------
+// view_update - update the contents of the
+// disassembly view
+//-------------------------------------------------
- // see if the line changed at all
- if (lines == 1 && m_dasm[instr] != comparison_buffer)
- changed = true;
- }
+void debug_view_disasm::view_update()
+{
+ const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
+ debug_disasm_buffer buffer(*source.device());
+ offs_t pc = source.device()->safe_pcbase() & source.m_space.logaddrmask();
- // update opcode base information
- m_last_direct_decrypted = source.m_decrypted_space.direct().ptr();
- m_last_direct_raw = source.m_space.direct().ptr();
- m_last_change_count = source.device()->debug()->comment_change_count();
+ generate_dasm(buffer, pc);
- // no longer need to recompute
- m_recompute = false;
- return changed;
+ complete_information(source, buffer, pc);
+ redraw();
}
@@ -443,11 +391,11 @@ bool debug_view_disasm::recompute(offs_t pc, int startline, int lines)
void debug_view_disasm::print(int row, std::string text, int start, int end, u8 attrib)
{
int view_end = end - m_topleft.x;
- if (view_end < 0)
+ if(view_end < 0)
return;
int string_0 = start - m_topleft.x;
- if (string_0 >= m_visible.x)
+ if(string_0 >= m_visible.x)
return;
int view_start = string_0 > 0 ? string_0 : 0;
@@ -458,152 +406,63 @@ void debug_view_disasm::print(int row, std::string text, int start, int end, u8
for(int pos = view_start; pos < view_end; pos++) {
int spos = pos - string_0;
- if (spos >= int(text.size()))
+ if(spos >= int(text.size()))
*dest++ = { ' ', attrib };
else
*dest++ = { u8(text[spos]), attrib };
- }
+ }
}
+
//-------------------------------------------------
-// view_update - update the contents of the
-// disassembly view
+// redraw - update the view from the data
//-------------------------------------------------
-void debug_view_disasm::view_update()
+void debug_view_disasm::redraw()
{
- const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
-
- offs_t pc = source.device()->safe_pcbase();
- offs_t pcbyte = source.m_space.address_to_byte(pc) & source.m_space.logbytemask();
-
- // update our context; if the expression is dirty, recompute
- if (m_expression.dirty())
- m_recompute = true;
-
- // if we're tracking a value, make sure it is visible
- u64 previous = m_expression.last_value();
- u64 result = m_expression.value();
- if (result != previous)
- {
- offs_t resultbyte = source.m_space.address_to_byte(result) & source.m_space.logbytemask();
-
- // see if the new result is an address we already have
- u32 row;
- for (row = 0; row < m_dasm.size(); row++)
- if (m_dasm[row].m_byteaddress == resultbyte)
- break;
-
- // if we didn't find it, or if it's really close to the bottom, recompute
- if (row == m_dasm.size() || row >= m_total.y - m_visible.y)
- m_recompute = true;
-
- // otherwise, if it's not visible, adjust the view so it is
- else if (row < m_topleft.y || row >= m_topleft.y + m_visible.y - 2)
- m_topleft.y = (row > 3) ? row - 3 : 0;
- }
-
- // if the opcode base has changed, rework things
- if (source.m_decrypted_space.direct().ptr() != m_last_direct_decrypted || source.m_space.direct().ptr() != m_last_direct_raw)
- m_recompute = true;
-
- // if the comments have changed, redo it
- if (m_last_change_count != source.device()->debug()->comment_change_count())
- m_recompute = true;
-
- // if we need to recompute, do it
- bool recomputed_this_time = false;
-recompute:
- if (m_recompute)
- {
- // recompute the view
- if (!m_dasm.empty() && m_last_change_count != source.device()->debug()->comment_change_count())
- {
- // smoosh us against the left column, but not the top row
- m_topleft.x = 0;
-
- // recompute from where we last recomputed!
- recompute(source.m_space.byte_to_address(m_dasm[0].m_byteaddress), 0, m_total.y);
- }
- else
- {
- // determine the addresses of what we will display
- offs_t backpc = find_pc_backwards(u32(m_expression.value()), m_backwards_steps);
-
- // put ourselves back in the top left
- m_topleft.y = 0;
- m_topleft.x = 0;
-
- recompute(backpc, 0, m_total.y);
- }
- recomputed_this_time = true;
- }
+ // determine how many characters we need for an address and set the divider
+ int m_divider1 = 1 + m_dasm[0].m_tadr.size() + 1;
- // figure out the row where the PC is and recompute the disassembly
- if (pcbyte != m_last_pcbyte)
- {
- // find the row with the PC on it
- for (u32 row = 0; row < m_visible.y; row++)
- {
- u32 effrow = m_topleft.y + row;
- if (effrow >= m_dasm.size())
- break;
- if (pcbyte == m_dasm[effrow].m_byteaddress)
- {
- // see if we changed
- bool changed = recompute(pc, effrow, 1);
- if (changed && !recomputed_this_time)
- {
- m_recompute = true;
- goto recompute;
- }
+ // assume a fixed number of characters for the disassembly
+ int m_divider2 = m_divider1 + 1 + m_dasm_width + 1;
- // set the effective row and PC
- m_cursor.y = effrow;
- view_notify(VIEW_NOTIFY_CURSOR_CHANGED);
- }
- }
- m_last_pcbyte = pcbyte;
- }
+ // set the width of the third column to max comment length
+ m_total.x = m_divider2 + 1 + 50; // DEBUG_COMMENT_MAX_LINE_LENGTH
// loop over visible rows
- for (u32 row = 0; row < m_visible.y; row++)
+ for(u32 row = 0; row < m_visible.y; row++)
{
u32 effrow = m_topleft.y + row;
// if this visible row is valid, add it to the buffer
u8 attrib = DCA_NORMAL;
- if (effrow < m_dasm.size())
+ if(effrow < m_dasm.size())
{
- // if we're on the line with the PC, recompute and hilight it
- if (pcbyte == m_dasm[effrow].m_byteaddress)
+ // if we're on the line with the PC, hilight it
+ if(m_dasm[effrow].m_is_pc)
attrib = DCA_CURRENT;
// if we're on a line with a breakpoint, tag it changed
- else
- {
- for (device_debug::breakpoint *bp = source.device()->debug()->breakpoint_first(); bp != nullptr; bp = bp->next())
- if (m_dasm[effrow].m_byteaddress == (source.m_space.address_to_byte(bp->address()) & source.m_space.logbytemask()))
- attrib = DCA_CHANGED;
- }
+ else if(m_dasm[effrow].m_is_bp)
+ attrib = DCA_CHANGED;
// if we're on the active column and everything is couth, highlight it
- if (m_cursor_visible && effrow == m_cursor.y)
+ if(m_cursor_visible && effrow == m_cursor.y)
attrib |= DCA_SELECTED;
// if we've visited this pc, mark it as such
- if (source.device()->debug()->track_pc_visited(m_dasm[effrow].m_byteaddress))
+ if(m_dasm[effrow].m_is_visited)
attrib |= DCA_VISITED;
- print(row, m_dasm[effrow].m_adr, 0, m_divider1, attrib | DCA_ANCILLARY);
+ print(row, ' ' + m_dasm[effrow].m_tadr, 0, m_divider1, attrib | DCA_ANCILLARY);
print(row, ' ' + m_dasm[effrow].m_dasm, m_divider1, m_divider2, attrib);
- if (m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) {
- std::string text = ' ' + (m_right_column == DASM_RIGHTCOL_RAW ? m_dasm[effrow].m_rawdata : m_dasm[effrow].m_encdata);
+ if(m_right_column == DASM_RIGHTCOL_RAW || m_right_column == DASM_RIGHTCOL_ENCRYPTED) {
+ std::string text = ' ' +(m_right_column == DASM_RIGHTCOL_RAW ? m_dasm[effrow].m_topcodes : m_dasm[effrow].m_tparams);
print(row, text, m_divider2, m_visible.x, attrib | DCA_ANCILLARY);
if(int(text.size()) > m_visible.x - m_divider2) {
int base = m_total.x - 3;
- if (base < m_divider2)
+ if(base < m_divider2)
base = m_divider2;
print(row, "...", base, m_visible.x, attrib | DCA_ANCILLARY);
}
@@ -624,7 +483,7 @@ recompute:
offs_t debug_view_disasm::selected_address()
{
flush_updates();
- return downcast<const debug_view_disasm_source &>(*m_source).m_space.byte_to_address(m_dasm[m_cursor.y].m_byteaddress);
+ return m_dasm[m_cursor.y].m_address;
}
@@ -679,7 +538,7 @@ void debug_view_disasm::set_disasm_width(u32 width)
{
begin_update();
m_dasm_width = width;
- m_recompute = m_update_pending = true;
+ m_update_pending = true;
end_update();
}
@@ -692,10 +551,9 @@ void debug_view_disasm::set_disasm_width(u32 width)
void debug_view_disasm::set_selected_address(offs_t address)
{
const debug_view_disasm_source &source = downcast<const debug_view_disasm_source &>(*m_source);
- offs_t byteaddress = source.m_space.address_to_byte(address) & source.m_space.logbytemask();
- for (int line = 0; line < m_total.y; line++)
- if (m_dasm[line].m_byteaddress == byteaddress)
- {
+ address = address & source.m_space.logaddrmask();
+ for(int line = 0; line < m_total.y; line++)
+ if(m_dasm[line].m_address == address) {
m_cursor.y = line;
set_cursor_position(m_cursor);
break;
diff --git a/src/emu/debug/dvdisasm.h b/src/emu/debug/dvdisasm.h
index 85ebd7cfef2..dcf756117b8 100644
--- a/src/emu/debug/dvdisasm.h
+++ b/src/emu/debug/dvdisasm.h
@@ -14,6 +14,7 @@
#pragma once
#include "debugvw.h"
+#include "debugbuf.h"
#include "vecstream.h"
@@ -51,7 +52,6 @@ public:
private:
// internal state
- device_disasm_interface *m_disasmintf; // disassembly interface
address_space & m_space; // address space to display
address_space & m_decrypted_space; // address space to display for decrypted opcodes
};
@@ -90,49 +90,42 @@ protected:
private:
// The information of one disassembly line. May become the actual
- // external interface at one point
+ // external interface at one point.
struct dasm_line {
- offs_t m_byteaddress; // address of the first byte of the instruction
- std::string m_adr; // instruction address as a string
+ offs_t m_address; // address of the instruction
+ offs_t m_size; // size of the instruction
+
+ std::string m_tadr; // instruction address as a string
std::string m_dasm; // disassembly
- std::string m_rawdata; // textual representation of the instruction values
- std::string m_encdata; // textual representation of encrypted instruction values
+ std::string m_topcodes; // textual representation of opcode/default values
+ std::string m_tparams; // textual representation of parameter values
std::string m_comment; // comment, when present
- bool operator == (const dasm_line &right) const {
- return
- m_byteaddress == right.m_byteaddress &&
- m_adr == right.m_adr &&
- m_dasm == right.m_dasm &&
- m_rawdata == right.m_rawdata &&
- m_encdata == right.m_encdata &&
- m_comment == right.m_comment;
- }
-
- bool operator != (const dasm_line &right) const {
- return !(*this == right);
- }
+ bool m_is_pc; // this line's address is PC
+ bool m_is_bp; // this line's address is a breakpoint
+ bool m_is_visited; // this line has been visited
+
+ dasm_line(offs_t address, offs_t size, std::string dasm) : m_address(address), m_size(size), m_dasm(dasm), m_is_pc(false), m_is_bp(false), m_is_visited(false) {}
};
// internal helpers
+ void generate_from_address(debug_disasm_buffer &buffer, offs_t address);
+ bool generate_with_pc(debug_disasm_buffer &buffer, offs_t pc);
+ int address_position(offs_t pc) const;
+ void generate_dasm(debug_disasm_buffer &buffer, offs_t pc);
+ void complete_information(const debug_view_disasm_source &source, debug_disasm_buffer &buffer, offs_t pc);
+
void enumerate_sources();
- offs_t find_pc_backwards(offs_t targetpc, int numinstrs);
- std::string generate_bytes(offs_t pcbyte, int numbytes, int granularity, bool encrypted);
- bool recompute(offs_t pc, int startline, int lines);
void print(int row, std::string text, int start, int end, u8 attrib);
+ void redraw();
// internal state
- disasm_right_column m_right_column; // right column contents
- u32 m_backwards_steps; // number of backwards steps
- u32 m_dasm_width; // width of the disassembly area
- u8 * m_last_direct_raw; // last direct raw value
- u8 * m_last_direct_decrypted;// last direct decrypted value
- u32 m_last_change_count; // last comment change count
- offs_t m_last_pcbyte; // last PC byte value
- int m_divider1, m_divider2; // left and right divider columns
- int m_divider3; // comment divider column
- debug_view_expression m_expression; // expression-related information
- std::vector<dasm_line> m_dasm; // disassembled instructions
+ disasm_right_column m_right_column; // right column contents
+ u32 m_backwards_steps; // number of backwards steps
+ u32 m_dasm_width; // width of the disassembly area
+ offs_t m_previous_pc; // previous pc, to detect whether it changed
+ debug_view_expression m_expression; // expression-related information
+ std::vector<dasm_line> m_dasm; // disassembled instructions
// constants
static constexpr int DEFAULT_DASM_LINES = 1000;
diff --git a/src/emu/debug/dvmemory.cpp b/src/emu/debug/dvmemory.cpp
index a5de89adb30..e32d576fa65 100644
--- a/src/emu/debug/dvmemory.cpp
+++ b/src/emu/debug/dvmemory.cpp
@@ -531,7 +531,7 @@ void debug_view_memory::recompute()
int addrchars;
if (source.m_space != nullptr)
{
- m_maxaddr = m_no_translation ? source.m_space->bytemask() : source.m_space->logbytemask();
+ m_maxaddr = m_no_translation ? source.m_space->addrmask() : source.m_space->logaddrmask();
addrchars = m_no_translation ? source.m_space->addrchars() : source.m_space->logaddrchars();
}
else
@@ -547,6 +547,8 @@ void debug_view_memory::recompute()
m_addrformat = string_format("%%0%dX%*s", addrchars, 8 - addrchars, "");
// if we are viewing a space with a minimum chunk size, clamp the bytes per chunk
+ // BAD
+#if 0
if (source.m_space != nullptr && source.m_space->byte_to_address(1) > 1)
{
u32 min_bytes_per_chunk = source.m_space->byte_to_address(1);
@@ -557,6 +559,7 @@ void debug_view_memory::recompute()
}
m_chunks_per_row = std::max(1U, m_chunks_per_row);
}
+#endif
// recompute the byte offset based on the most recent expression result
m_bytes_per_row = m_bytes_per_chunk * m_chunks_per_row;
@@ -617,7 +620,7 @@ bool debug_view_memory::needs_recompute()
const debug_view_memory_source &source = downcast<const debug_view_memory_source &>(*m_source);
offs_t resultbyte;
if (source.m_space != nullptr)
- resultbyte = source.m_space->address_to_byte(m_expression.value()) & source.m_space->logbytemask();
+ resultbyte = m_expression.value() & source.m_space->logaddrmask();
else
resultbyte = m_expression.value();
diff --git a/src/emu/devcpu.h b/src/emu/devcpu.h
index 1c4bce13506..35c8c3b2a9e 100644
--- a/src/emu/devcpu.h
+++ b/src/emu/devcpu.h
@@ -50,15 +50,6 @@
//**************************************************************************
-// MACROS
-//**************************************************************************
-
-#define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
-#define CPU_DISASSEMBLE(name) offs_t CPU_DISASSEMBLE_NAME(name)(cpu_device *device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options)
-#define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(device, stream, pc, oprom, opram, options)
-
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@@ -86,7 +77,4 @@ private:
};
-typedef offs_t (*cpu_disassemble_func)(cpu_device *device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options);
-
-
#endif /* MAME_EMU_DEVCPU_H */
diff --git a/src/emu/device.cpp b/src/emu/device.cpp
index 5325e506568..e03e09e8dac 100644
--- a/src/emu/device.cpp
+++ b/src/emu/device.cpp
@@ -450,10 +450,11 @@ bool device_t::findit(bool isvalidation) const
}
//-------------------------------------------------
-// start - start a device
+// resolve_objects - find objects referenced in
+// configuration
//-------------------------------------------------
-void device_t::start()
+void device_t::resolve_objects()
{
// prepare the logerror buffer
if (m_machine->allow_logging())
@@ -463,6 +464,20 @@ void device_t::start()
if (!findit(false))
throw emu_fatalerror("Missing some required objects, unable to proceed");
+ // allow implementation to do additional setup
+ device_resolve_objects();
+}
+
+//-------------------------------------------------
+// start - start a device
+//-------------------------------------------------
+
+void device_t::start()
+{
+ // prepare the logerror buffer
+ if (m_machine->allow_logging())
+ m_string_buffer.reserve(1024);
+
// let the interfaces do their pre-work
for (device_interface &intf : interfaces())
intf.interface_pre_start();
@@ -681,6 +696,18 @@ void device_t::device_reset_after_children()
//-------------------------------------------------
+// device_resolve_objects - resolve objects that
+// may be needed for other devices to set
+// initial conditions at start time
+//-------------------------------------------------
+
+void device_t::device_resolve_objects()
+{
+ // do nothing by default
+}
+
+
+//-------------------------------------------------
// device_stop - clean up anything that needs to
// happen before the running_machine goes away
//-------------------------------------------------
diff --git a/src/emu/device.h b/src/emu/device.h
index 0a894d20e09..211da59cb38 100644
--- a/src/emu/device.h
+++ b/src/emu/device.h
@@ -541,6 +541,7 @@ public:
protected:
// miscellaneous helpers
void set_machine(running_machine &machine);
+ void resolve_objects();
void start();
void stop();
void debug_setup();
@@ -557,6 +558,7 @@ protected:
virtual ioport_constructor device_input_ports() const;
virtual void device_config_complete();
virtual void device_validity_check(validity_checker &valid) const ATTR_COLD;
+ virtual void device_resolve_objects() ATTR_COLD;
virtual void device_start() ATTR_COLD = 0;
virtual void device_stop() ATTR_COLD;
virtual void device_reset() ATTR_COLD;
diff --git a/src/emu/didisasm.cpp b/src/emu/didisasm.cpp
index 95353889a65..51a96915a04 100644
--- a/src/emu/didisasm.cpp
+++ b/src/emu/didisasm.cpp
@@ -11,82 +11,93 @@
#include "emu.h"
-//**************************************************************************
-// DEVICE DISASM INTERFACE
-//**************************************************************************
-
-//-------------------------------------------------
-// device_disasm_interface - constructor
-//-------------------------------------------------
-
device_disasm_interface::device_disasm_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "disasm")
{
}
+util::disasm_interface *device_disasm_interface::get_disassembler()
+{
+ if(!m_disasm) {
+ if(m_dasm_override.isnull())
+ m_disasm.reset(create_disassembler());
+ else
+ m_disasm = std::make_unique<device_disasm_indirect>(create_disassembler(), m_dasm_override);
+ }
+ return m_disasm.get();
+}
-//-------------------------------------------------
-// ~device_disasm_interface - destructor
-//-------------------------------------------------
+void device_disasm_interface::interface_pre_start()
+{
+ m_dasm_override.bind_relative_to(*device().owner());
+}
-device_disasm_interface::~device_disasm_interface()
+void device_disasm_interface::set_dasm_override(dasm_override_delegate dasm_override)
{
+ m_dasm_override = dasm_override;
}
+device_disasm_indirect::device_disasm_indirect(util::disasm_interface *upper, dasm_override_delegate &dasm_override) : m_dasm_override(dasm_override)
+{
+ m_disasm.reset(upper);
+}
-//-------------------------------------------------
-// interface_pre_start - work to be done prior to
-// actually starting a device
-//-------------------------------------------------
+u32 device_disasm_indirect::interface_flags() const
+{
+ return m_disasm->interface_flags();
+}
-void device_disasm_interface::interface_pre_start()
+u32 device_disasm_indirect::page_address_bits() const
{
- // bind delegate
- m_dasm_override.bind_relative_to(*device().owner());
+ return m_disasm->page_address_bits();
}
+u32 device_disasm_indirect::page2_address_bits() const
+{
+ return m_disasm->page2_address_bits();
+}
-//-------------------------------------------------
-// static_set_dasm_override - configuration
-// helper to override disassemble function
-//-------------------------------------------------
+offs_t device_disasm_indirect::pc_linear_to_real(offs_t pc) const
+{
+ return m_disasm->pc_linear_to_real(pc);
+}
-void device_disasm_interface::static_set_dasm_override(device_t &device, dasm_override_delegate dasm_override)
+offs_t device_disasm_indirect::pc_real_to_linear(offs_t pc) const
{
- device_disasm_interface *dasm;
- if (!device.interface(dasm))
- throw emu_fatalerror("MCFG_DEVICE_DISASSEMBLE_OVERRIDE called on device '%s' with no disasm interface", device.tag());
- dasm->m_dasm_override = dasm_override;
+ return m_disasm->pc_real_to_linear(pc);
}
+u8 device_disasm_indirect::decrypt8 (u8 value, offs_t pc, bool opcode) const
+{
+ return m_disasm->decrypt8(value, pc, opcode);
+}
-//-------------------------------------------------
-// disassemble - interface for disassembly
-//-------------------------------------------------
+u16 device_disasm_indirect::decrypt16(u16 value, offs_t pc, bool opcode) const
+{
+ return m_disasm->decrypt16(value, pc, opcode);
+}
-offs_t device_disasm_interface::disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options)
+u32 device_disasm_indirect::decrypt32(u32 value, offs_t pc, bool opcode) const
{
- offs_t result = 0;
+ return m_disasm->decrypt32(value, pc, opcode);
+}
- // check for disassembler override
- if (!m_dasm_override.isnull())
- result = m_dasm_override(device(), stream, pc, oprom, opram, options);
- if (result == 0)
- result = disasm_disassemble(stream, pc, oprom, opram, options);
+u64 device_disasm_indirect::decrypt64(u64 value, offs_t pc, bool opcode) const
+{
+ return m_disasm->decrypt64(value, pc, opcode);
+}
- // make sure we get good results
- assert((result & DASMFLAG_LENGTHMASK) != 0);
-#ifdef MAME_DEBUG
- device_memory_interface *memory;
- if (device().interface(memory))
- {
- address_space &space = memory->space(AS_PROGRAM);
- int bytes = space.address_to_byte(result & DASMFLAG_LENGTHMASK);
- assert(bytes >= min_opcode_bytes());
- assert(bytes <= max_opcode_bytes());
- (void) bytes; // appease compiler
- }
-#endif
+u32 device_disasm_indirect::opcode_alignment() const
+{
+ return m_disasm->opcode_alignment();
+}
+offs_t device_disasm_indirect::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ offs_t result = m_dasm_override(stream, pc, opcodes, params);
+ if(!result)
+ result = m_disasm->disassemble(stream, pc, opcodes, params);
return result;
}
+
+
diff --git a/src/emu/didisasm.h b/src/emu/didisasm.h
index edd56b3352f..9636b67a6db 100644
--- a/src/emu/didisasm.h
+++ b/src/emu/didisasm.h
@@ -17,79 +17,70 @@
#ifndef MAME_EMU_DIDISASM_H
#define MAME_EMU_DIDISASM_H
-
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-// Disassembler constants
-constexpr u32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
-constexpr u32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
-constexpr u32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
-constexpr u32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
-constexpr u32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
-constexpr u32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
-
-
-
-//**************************************************************************
-// MACROS
-//**************************************************************************
-
-#define DASMFLAG_STEP_OVER_EXTRA(x) ((x) << DASMFLAG_OVERINSTSHIFT)
-
-
-
-//**************************************************************************
-// INTERFACE CONFIGURATION MACROS
-//**************************************************************************
+#include "disasmintf.h"
#define MCFG_DEVICE_DISASSEMBLE_OVERRIDE(_class, _func) \
- device_disasm_interface::static_set_dasm_override(*device, dasm_override_delegate(&_class::_func, #_class "::" #_func, nullptr, (_class *)nullptr));
-
-
+ dynamic_cast<device_disasm_interface *>(device)->set_dasm_override(dasm_override_delegate(&_class::_func, #_class "::" #_func, nullptr, (_class *)nullptr));
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-typedef device_delegate<offs_t (device_t &device, std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, int options)> dasm_override_delegate;
+typedef device_delegate<offs_t (std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer &params)> dasm_override_delegate;
// ======================> device_disasm_interface
-
+
// class representing interface-specific live disasm
class device_disasm_interface : public device_interface
{
public:
// construction/destruction
device_disasm_interface(const machine_config &mconfig, device_t &device);
- virtual ~device_disasm_interface();
+ virtual ~device_disasm_interface() = default;
- // configuration access
- u32 min_opcode_bytes() const { return disasm_min_opcode_bytes(); }
- u32 max_opcode_bytes() const { return disasm_max_opcode_bytes(); }
+ // Override
+ void set_dasm_override(dasm_override_delegate dasm_override);
- // static inline configuration helpers
- static void static_set_dasm_override(device_t &device, dasm_override_delegate dasm_override);
-
- // interface for disassembly
- offs_t disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options = 0);
+ // disassembler request
+ util::disasm_interface *get_disassembler();
protected:
- // required operation overrides
- virtual u32 disasm_min_opcode_bytes() const = 0;
- virtual u32 disasm_max_opcode_bytes() const = 0;
- virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) = 0;
+ // disassembler creation
+ virtual util::disasm_interface *create_disassembler() = 0;
- // interface-level overrides
+ // delegate resolving
virtual void interface_pre_start() override;
private:
- dasm_override_delegate m_dasm_override; // provided override function
+ std::unique_ptr<util::disasm_interface> m_disasm;
+ dasm_override_delegate m_dasm_override;
};
// iterator
typedef device_interface_iterator<device_disasm_interface> disasm_interface_iterator;
+class device_disasm_indirect : public util::disasm_interface
+{
+public:
+ device_disasm_indirect(util::disasm_interface *upper, dasm_override_delegate &dasm_override);
+ virtual ~device_disasm_indirect() = default;
+
+ virtual u32 interface_flags() const override;
+ virtual u32 page_address_bits() const override;
+ virtual u32 page2_address_bits() const override;
+ virtual offs_t pc_linear_to_real(offs_t pc) const override;
+ virtual offs_t pc_real_to_linear(offs_t pc) const override;
+ virtual u8 decrypt8 (u8 value, offs_t pc, bool opcode) const override;
+ virtual u16 decrypt16(u16 value, offs_t pc, bool opcode) const override;
+ virtual u32 decrypt32(u32 value, offs_t pc, bool opcode) const override;
+ virtual u64 decrypt64(u64 value, offs_t pc, bool opcode) const override;
+
+ virtual u32 opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+private:
+ std::unique_ptr<util::disasm_interface> m_disasm;
+ dasm_override_delegate &m_dasm_override;
+};
#endif /* MAME_EMU_DIDISASM_H */
diff --git a/src/emu/diexec.cpp b/src/emu/diexec.cpp
index e43613b0302..0958108fe42 100644
--- a/src/emu/diexec.cpp
+++ b/src/emu/diexec.cpp
@@ -695,6 +695,48 @@ TIMER_CALLBACK_MEMBER(device_execute_interface::trigger_periodic_interrupt)
}
+//-------------------------------------------------
+// irq_pulse_clear - clear a "pulsed" input line
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(device_execute_interface::irq_pulse_clear)
+{
+ int irqline = param;
+ set_input_line(irqline, CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// pulse_input_line - "pulse" an input line by
+// asserting it and then clearing it later
+//-------------------------------------------------
+
+void device_execute_interface::pulse_input_line(int irqline, const attotime &duration)
+{
+ assert(duration > attotime::zero);
+ set_input_line(irqline, ASSERT_LINE);
+
+ attotime target_time = local_time() + duration;
+ m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline);
+}
+
+
+//-------------------------------------------------
+// pulse_input_line_and_vector - "pulse" an
+// input line by asserting it and then clearing it
+// later, specifying a vector
+//-------------------------------------------------
+
+void device_execute_interface::pulse_input_line_and_vector(int irqline, int vector, const attotime &duration)
+{
+ assert(duration > attotime::zero);
+ set_input_line_and_vector(irqline, ASSERT_LINE, vector);
+
+ attotime target_time = local_time() + duration;
+ m_scheduler->timer_set(target_time - m_scheduler->time(), timer_expired_delegate(FUNC(device_execute_interface::irq_pulse_clear), this), irqline);
+}
+
+
//**************************************************************************
// DEVICE INPUT
diff --git a/src/emu/diexec.h b/src/emu/diexec.h
index 8e4c4ce9cc5..c307400dd69 100644
--- a/src/emu/diexec.h
+++ b/src/emu/diexec.h
@@ -162,6 +162,8 @@ public:
void set_input_line_vector(int linenum, int vector) { m_input[linenum].set_vector(vector); }
void set_input_line_and_vector(int linenum, int state, int vector) { m_input[linenum].set_state_synced(state, vector); }
int input_state(int linenum) const { return m_input[linenum].m_curstate; }
+ void pulse_input_line(int irqline, const attotime &duration);
+ void pulse_input_line_and_vector(int irqline, int vector, const attotime &duration);
// suspend/resume
void suspend(u32 reason, bool eatcycles);
@@ -292,9 +294,13 @@ private:
void on_vblank(screen_device &screen, bool vblank_state);
TIMER_CALLBACK_MEMBER(trigger_periodic_interrupt);
+ TIMER_CALLBACK_MEMBER(irq_pulse_clear);
void suspend_resume_changed();
attoseconds_t minimum_quantum() const;
+
+public:
+ attotime minimum_quantum_time() const { return attotime(0, minimum_quantum()); }
};
// iterator
diff --git a/src/emu/dipalette.cpp b/src/emu/dipalette.cpp
index d996ccafe4d..f7d4a6974d4 100644
--- a/src/emu/dipalette.cpp
+++ b/src/emu/dipalette.cpp
@@ -26,7 +26,7 @@ device_palette_interface::device_palette_interface(const machine_config &mconfig
: device_interface(device, "palette"),
m_palette(nullptr),
m_pens(nullptr),
- m_format(),
+ m_format(BITMAP_FORMAT_RGB32),
m_shadow_table(nullptr),
m_shadow_group(0),
m_hilight_group(0),
@@ -57,10 +57,6 @@ void device_palette_interface::interface_validity_check(validity_checker &valid)
void device_palette_interface::interface_pre_start()
{
- // reset all our data
- screen_device *screen = device().machine().first_screen();
- m_format = (screen != nullptr) ? screen->format() : BITMAP_FORMAT_INVALID;
-
// allocate the palette
u32 numentries = palette_entries();
allocate_palette(numentries);
diff --git a/src/emu/dipalette.h b/src/emu/dipalette.h
index eb2979f6118..358d5071b58 100644
--- a/src/emu/dipalette.h
+++ b/src/emu/dipalette.h
@@ -37,6 +37,8 @@ typedef u16 indirect_pen_t;
class device_palette_interface : public device_interface
{
+ friend class screen_device;
+
static constexpr int MAX_SHADOW_PRESETS = 4;
public:
diff --git a/src/emu/dirom.cpp b/src/emu/dirom.cpp
index 161b7770c75..3a0ed23692f 100644
--- a/src/emu/dirom.cpp
+++ b/src/emu/dirom.cpp
@@ -85,7 +85,7 @@ void device_rom_interface::set_rom(const void *base, u32 size)
void device_rom_interface::interface_pre_start()
{
- m_rom_direct = &space().direct();
+ m_rom_direct = space().direct<0>();
m_bank = nullptr;
m_cur_bank = -1;
device().save_item(NAME(m_cur_bank));
diff --git a/src/emu/dirom.h b/src/emu/dirom.h
index 1e9efcca037..2ea7edca810 100644
--- a/src/emu/dirom.h
+++ b/src/emu/dirom.h
@@ -42,7 +42,7 @@ protected:
private:
const char *m_rom_tag;
const address_space_config m_rom_config;
- direct_read_data *m_rom_direct;
+ direct_read_data<0> *m_rom_direct;
memory_bank *m_bank;
int m_cur_bank, m_bank_count;
diff --git a/src/emu/diserial.cpp b/src/emu/diserial.cpp
index b0a8e40ab6a..db8f726d8c7 100644
--- a/src/emu/diserial.cpp
+++ b/src/emu/diserial.cpp
@@ -213,6 +213,7 @@ WRITE_LINE_MEMBER(device_serial_interface::rx_w)
receive_register_update_bit(state);
if(m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
{
+ //device().logerror("Receiver is synchronized\n");
if(m_rcv_clock && !(m_rcv_rate.is_never()))
// make start delay just a bit longer to make sure we are called after the sender
m_rcv_clock->adjust(((m_rcv_rate*3)/2), 0, m_rcv_rate);
@@ -266,6 +267,7 @@ void device_serial_interface::receive_register_update_bit(int bit)
else
if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
{
+ //device().logerror("Received bit %d\n", m_rcv_bit_count_received);
m_rcv_bit_count_received++;
if (!bit && (m_rcv_bit_count_received > (m_rcv_bit_count - m_df_stop_bit_count)))
@@ -279,7 +281,7 @@ void device_serial_interface::receive_register_update_bit(int bit)
m_rcv_bit_count_received = 0;
m_rcv_flags &=~RECEIVE_REGISTER_SYNCHRONISED;
m_rcv_flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT;
- //logerror("receive register full\n");
+ //device().logerror("Receive register full\n");
m_rcv_flags |= RECEIVE_REGISTER_FULL;
}
}
diff --git a/src/emu/distate.cpp b/src/emu/distate.cpp
index 2a1ed9b9ea9..71462ce3275 100644
--- a/src/emu/distate.cpp
+++ b/src/emu/distate.cpp
@@ -49,30 +49,18 @@ const u64 device_state_entry::k_decimal_divisor[] =
// device_state_entry - constructor
//-------------------------------------------------
-device_state_entry::device_state_entry(int index, const char *symbol, void *dataptr, u8 size, device_state_interface *dev)
+device_state_entry::device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev)
: m_device_state(dev),
m_index(index),
- m_dataptr(dataptr),
- m_datamask(0),
+ m_datamask(sizemask),
m_datasize(size),
- m_flags(0),
+ m_flags(flags),
m_symbol(symbol),
m_default_format(true),
- m_sizemask(0)
+ m_sizemask(sizemask)
{
- // convert the size to a mask
- assert(size == 1 || size == 2 || size == 4 || size == 8);
- if (size == 1)
- m_sizemask = 0xff;
- else if (size == 2)
- m_sizemask = 0xffff;
- else if (size == 4)
- m_sizemask = 0xffffffff;
- else
- m_sizemask = ~u64(0);
-
- // default the data mask to the same
- m_datamask = m_sizemask;
+ assert(size == 1 || size == 2 || size == 4 || size == 8 || (flags & DSF_FLOATING_POINT) != 0);
+
format_from_mask();
// override well-known symbols
@@ -87,10 +75,9 @@ device_state_entry::device_state_entry(int index, const char *symbol, void *data
device_state_entry::device_state_entry(int index, device_state_interface *dev)
: m_device_state(dev),
m_index(index),
- m_dataptr(nullptr),
m_datamask(0),
m_datasize(0),
- m_flags(DSF_DIVIDER),
+ m_flags(DSF_DIVIDER | DSF_READONLY),
m_symbol(),
m_default_format(true),
m_sizemask(0)
@@ -99,6 +86,15 @@ device_state_entry::device_state_entry(int index, device_state_interface *dev)
//-------------------------------------------------
+// device_state_entry - destructor
+//-------------------------------------------------
+
+device_state_entry::~device_state_entry()
+{
+}
+
+
+//-------------------------------------------------
// formatstr - specify a format string
//-------------------------------------------------
@@ -126,6 +122,12 @@ void device_state_entry::format_from_mask()
if (!m_default_format)
return;
+ if (is_float())
+ {
+ m_format = "%12s";
+ return;
+ }
+
// make up a format based on the mask
int width = 0;
for (u64 tempmask = m_datamask; tempmask != 0; tempmask >>= 4)
@@ -135,22 +137,34 @@ void device_state_entry::format_from_mask()
//-------------------------------------------------
-// value - return the current value as a u64
+// entry_baseptr - return a pointer to where the
+// data lives (if applicable)
//-------------------------------------------------
-u64 device_state_entry::value() const
+void *device_state_entry::entry_baseptr() const
{
- // pick up the value
- u64 result;
- switch (m_datasize)
- {
- default:
- case 1: result = *static_cast<u8 *>(m_dataptr); break;
- case 2: result = *static_cast<u16 *>(m_dataptr); break;
- case 4: result = *static_cast<u32 *>(m_dataptr); break;
- case 8: result = *static_cast<u64 *>(m_dataptr); break;
- }
- return result & m_datamask;
+ return nullptr;
+}
+
+
+//-------------------------------------------------
+// entry_value - return the current value as a u64
+//-------------------------------------------------
+
+u64 device_state_entry::entry_value() const
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// entry_dvalue - return the current value as a
+// double
+//-------------------------------------------------
+
+double device_state_entry::entry_dvalue() const
+{
+ return 0.0;
}
@@ -349,6 +363,8 @@ std::string device_state_entry::format(const char *string, bool maxout) const
void device_state_entry::set_value(u64 value) const
{
+ assert((m_flags & DSF_READONLY) == 0);
+
// apply the mask
value &= m_datamask;
@@ -357,14 +373,39 @@ void device_state_entry::set_value(u64 value) const
value |= ~m_datamask;
// store the value
- switch (m_datasize)
- {
- default:
- case 1: *static_cast<u8 *>(m_dataptr) = value; break;
- case 2: *static_cast<u16 *>(m_dataptr) = value; break;
- case 4: *static_cast<u32 *>(m_dataptr) = value; break;
- case 8: *static_cast<u64 *>(m_dataptr) = value; break;
- }
+ entry_set_value(value);
+}
+
+
+//-------------------------------------------------
+// set_dvalue - set the value from a double
+//-------------------------------------------------
+
+void device_state_entry::set_dvalue(double value) const
+{
+ assert((m_flags & DSF_READONLY) == 0);
+
+ // store the value
+ entry_set_dvalue(value);
+}
+
+
+//-------------------------------------------------
+// entry_set_value - set the value from a u64
+//-------------------------------------------------
+
+void device_state_entry::entry_set_value(u64 value) const
+{
+}
+
+
+//-------------------------------------------------
+// entry_set_dvalue - set the value from a double
+//-------------------------------------------------
+
+void device_state_entry::entry_set_dvalue(double value) const
+{
+ set_value(u64(value));
}
@@ -443,6 +484,8 @@ std::string device_state_interface::state_string(int index) const
std::string custom;
if (entry->needs_custom_string())
state_string_export(*entry, custom);
+ else if (entry->is_float())
+ custom = string_format("%-12G", entry->dvalue());
// ask the entry to format itself
return entry->format(custom.c_str());
@@ -509,38 +552,22 @@ void device_state_interface::set_state_string(int index, const char *string)
//-------------------------------------------------
-// state_add - return the value of the given
-// pieces of indexed state as a u64
+// state_add - add a new piece of indexed state
//-------------------------------------------------
-device_state_entry &device_state_interface::state_add(int index, const char *symbol, void *data, u8 size)
+device_state_entry &device_state_interface::state_add(std::unique_ptr<device_state_entry> &&entry)
{
- // assert validity of incoming parameters
- assert(size == 1 || size == 2 || size == 4 || size == 8);
- assert(symbol != nullptr);
-
// append to the end of the list
- m_state_list.push_back(std::make_unique<device_state_entry>(index, symbol, data, size, this));
+ m_state_list.push_back(std::move(entry));
+ device_state_entry &new_entry = *m_state_list.back();
// set the fast entry if applicable
- if (index >= FAST_STATE_MIN && index <= FAST_STATE_MAX)
- m_fast_state[index - FAST_STATE_MIN] = m_state_list.back().get();
+ if (new_entry.index() >= FAST_STATE_MIN && new_entry.index() <= FAST_STATE_MAX && !new_entry.divider())
+ m_fast_state[new_entry.index() - FAST_STATE_MIN] = &new_entry;
- return *m_state_list.back().get();
+ return new_entry;
}
-//-------------------------------------------------
-// state_add_divider - add a simple divider
-// entry
-//-------------------------------------------------
-
-device_state_entry &device_state_interface::state_add_divider(int index)
-{
- // append to the end of the list
- m_state_list.push_back(std::make_unique<device_state_entry>(index, this));
-
- return *m_state_list.back().get();
-}
//-------------------------------------------------
// state_import - called after new state is
diff --git a/src/emu/distate.h b/src/emu/distate.h
index 22db6cc22af..a2cfcecb4c5 100644
--- a/src/emu/distate.h
+++ b/src/emu/distate.h
@@ -46,8 +46,9 @@ class device_state_entry
friend class device_state_interface;
public:
// construction/destruction
- device_state_entry(int index, const char *symbol, void *dataptr, u8 size, device_state_interface *dev);
+ device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev);
device_state_entry(int index, device_state_interface *dev);
+ virtual ~device_state_entry();
public:
// post-construction modifiers
@@ -57,13 +58,17 @@ public:
device_state_entry &callimport() { m_flags |= DSF_IMPORT; return *this; }
device_state_entry &callexport() { m_flags |= DSF_EXPORT; return *this; }
device_state_entry &noshow() { m_flags |= DSF_NOSHOW; return *this; }
+ device_state_entry &readonly() { m_flags |= DSF_READONLY; return *this; }
// query information
int index() const { return m_index; }
- void *dataptr() const { return m_dataptr; }
+ void *dataptr() const { return entry_baseptr(); }
+ u64 datamask() const { return m_datamask; }
const char *symbol() const { return m_symbol.c_str(); }
bool visible() const { return ((m_flags & DSF_NOSHOW) == 0); }
+ bool writeable() const { return ((m_flags & DSF_READONLY) == 0); }
bool divider() const { return m_flags & DSF_DIVIDER; }
+ bool is_float() const { return m_flags & DSF_FLOATING_POINT; }
device_state_interface *parent_state() const {return m_device_state;}
const std::string &format_string() const { return m_format; }
@@ -75,6 +80,8 @@ protected:
static constexpr u8 DSF_EXPORT = 0x08; // call the export function prior to fetching the data
static constexpr u8 DSF_CUSTOM_STRING = 0x10; // set if the format has a custom string
static constexpr u8 DSF_DIVIDER = 0x20; // set if this is a divider entry
+ static constexpr u8 DSF_READONLY = 0x40; // set if this entry does not permit writes
+ static constexpr u8 DSF_FLOATING_POINT = 0x80; // set if this entry represents a floating-point value
// helpers
bool needs_custom_string() const { return ((m_flags & DSF_CUSTOM_STRING) != 0); }
@@ -82,21 +89,29 @@ protected:
// return the current value -- only for our friends who handle export
bool needs_export() const { return ((m_flags & DSF_EXPORT) != 0); }
- u64 value() const;
+ u64 value() const { return entry_value() & m_datamask; }
+ double dvalue() const { return entry_dvalue(); }
std::string format(const char *string, bool maxout = false) const;
// set the current value -- only for our friends who handle import
bool needs_import() const { return ((m_flags & DSF_IMPORT) != 0); }
void set_value(u64 value) const;
+ void set_dvalue(double value) const;
void set_value(const char *string) const;
+ // overrides
+ virtual void *entry_baseptr() const;
+ virtual u64 entry_value() const;
+ virtual void entry_set_value(u64 value) const;
+ virtual double entry_dvalue() const;
+ virtual void entry_set_dvalue(double value) const;
+
// statics
static const u64 k_decimal_divisor[20]; // divisors for outputting decimal values
// public state description
device_state_interface *m_device_state; // link to parent device state
u32 m_index; // index by which this item is referred
- void * m_dataptr; // pointer to where the data lives
u64 m_datamask; // mask that applies to the data
u8 m_datasize; // size of the data
u8 m_flags; // flags for this data
@@ -107,6 +122,84 @@ protected:
};
+// ======================> device_state_register
+
+// class template representing a state register of a specific width
+template<class ItemType>
+class device_state_register : public device_state_entry
+{
+public:
+ // construction/destruction
+ device_state_register(int index, const char *symbol, ItemType &data, device_state_interface *dev)
+ : device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev),
+ m_data(data)
+ {
+ static_assert(std::is_integral<ItemType>().value, "Registration of non-integer types is not currently supported");
+ }
+
+protected:
+ // device_state_entry overrides
+ virtual void *entry_baseptr() const override { return &m_data; }
+ virtual u64 entry_value() const override { return m_data; }
+ virtual void entry_set_value(u64 value) const override { m_data = value; }
+
+private:
+ ItemType & m_data; // reference to where the data lives
+};
+
+// class template representing a floating-point state register
+template<>
+class device_state_register<double> : public device_state_entry
+{
+public:
+ // construction/destruction
+ device_state_register(int index, const char *symbol, double &data, device_state_interface *dev)
+ : device_state_entry(index, symbol, sizeof(double), ~u64(0), DSF_FLOATING_POINT, dev),
+ m_data(data)
+ {
+ }
+
+protected:
+ // device_state_entry overrides
+ virtual void *entry_baseptr() const override { return &m_data; }
+ virtual u64 entry_value() const override { return u64(m_data); }
+ virtual void entry_set_value(u64 value) const override { m_data = double(value); }
+ virtual double entry_dvalue() const override { return m_data; }
+ virtual void entry_set_dvalue(double value) const override { m_data = value; }
+
+private:
+ double & m_data; // reference to where the data lives
+};
+
+
+// ======================> device_state_register
+
+// class template representing a state register of a specific width
+template<class ItemType>
+class device_pseudo_state_register : public device_state_entry
+{
+public:
+ typedef typename std::function<ItemType ()> getter_func;
+ typedef typename std::function<void (ItemType)> setter_func;
+
+ // construction/destruction
+ device_pseudo_state_register(int index, const char *symbol, getter_func &&getter, setter_func &&setter, device_state_interface *dev)
+ : device_state_entry(index, symbol, sizeof(ItemType), std::numeric_limits<ItemType>::max(), 0, dev),
+ m_getter(std::move(getter)),
+ m_setter(std::move(setter))
+ {
+ }
+
+protected:
+ // device_state_entry overrides
+ virtual u64 entry_value() const override { return m_getter(); }
+ virtual void entry_set_value(u64 value) const override { m_setter(value); }
+
+private:
+ getter_func m_getter; // function to retrieve the data
+ setter_func m_setter; // function to store the data
+};
+
// ======================> device_state_interface
@@ -143,15 +236,32 @@ public:
public: // protected eventually
- // add a new state item
- template<class _ItemType> device_state_entry &state_add(int index, const char *symbol, _ItemType &data)
+ // add a new state register item
+ template<class ItemType> device_state_entry &state_add(int index, const char *symbol, ItemType &data)
+ {
+ assert(symbol != nullptr);
+ return state_add(std::make_unique<device_state_register<ItemType>>(index, symbol, data, this));
+ }
+
+ // add a new state pseudo-register item (template argument must be explicit)
+ template<class ItemType> device_state_entry &state_add(int index, const char *symbol,
+ typename device_pseudo_state_register<ItemType>::getter_func &&getter,
+ typename device_pseudo_state_register<ItemType>::setter_func &&setter)
{
- return state_add(index, symbol, &data, sizeof(data));
+ assert(symbol != nullptr);
+ return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), std::move(setter), this));
}
- device_state_entry &state_add(int index, const char *symbol, void *data, u8 size);
+ template<class ItemType> device_state_entry &state_add(int index, const char *symbol,
+ typename device_pseudo_state_register<ItemType>::getter_func &&getter)
+ {
+ assert(symbol != nullptr);
+ return state_add(std::make_unique<device_pseudo_state_register<ItemType>>(index, symbol, std::move(getter), [](ItemType){}, this)).readonly();
+ }
+
+ device_state_entry &state_add(std::unique_ptr<device_state_entry> &&entry);
// add a new divider entry
- device_state_entry &state_add_divider(int index);
+ device_state_entry &state_add_divider(int index) { return state_add(std::make_unique<device_state_entry>(index, this)); }
protected:
// derived class overrides
diff --git a/src/emu/divideo.cpp b/src/emu/divideo.cpp
index 4abe607dab3..7007487ef32 100644
--- a/src/emu/divideo.cpp
+++ b/src/emu/divideo.cpp
@@ -134,11 +134,8 @@ void device_video_interface::interface_pre_start()
throw device_missing_dependencies();
else
{
- // resolve the palette for the sake of register_screen_bitmap
- m_screen->resolve_palette();
-
- // no other palette may be specified (FIXME: breaks meritm.cpp)
- if (0 && m_screen->has_palette() && palintf != &m_screen->palette())
+ // no other palette may be specified
+ if (m_screen->has_palette() && palintf != &m_screen->palette())
throw emu_fatalerror("Device '%s' cannot control screen '%s' with palette '%s'", device().tag(), m_screen_tag, m_screen->palette().device().tag());
}
}
diff --git a/src/emu/drawgfx.cpp b/src/emu/drawgfx.cpp
index edbfa1ec306..eff4e46f2cf 100644
--- a/src/emu/drawgfx.cpp
+++ b/src/emu/drawgfx.cpp
@@ -1919,6 +1919,18 @@ void copybitmap_trans(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, in
}
+/*-------------------------------------------------
+ copybitmap_transalphpa - copy from one bitmap
+ to another, copying all unclipped pixels except
+ those with an alpha value of zero
+-------------------------------------------------*/
+
+void copybitmap_transalpha(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect)
+{
+ DECLARE_NO_PRIORITY;
+ COPYBITMAP_CORE(u32, PIXEL_OP_COPY_TRANSALPHA, NO_PRIORITY);
+}
+
/***************************************************************************
COPYSCROLLBITMAP IMPLEMENTATIONS
diff --git a/src/emu/drawgfx.h b/src/emu/drawgfx.h
index fe5cb7679df..e9833de4a30 100644
--- a/src/emu/drawgfx.h
+++ b/src/emu/drawgfx.h
@@ -352,6 +352,8 @@ void copybitmap(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flip
void copybitmap_trans(bitmap_ind16 &dest, const bitmap_ind16 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, u32 transpen);
void copybitmap_trans(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect, u32 transpen);
+void copybitmap_transalpha(bitmap_rgb32 &dest, const bitmap_rgb32 &src, int flipx, int flipy, s32 destx, s32 desty, const rectangle &cliprect);
+
/*
Copy a bitmap onto another with scroll and wraparound.
These functions support multiple independently scrolling rows/columns.
@@ -429,7 +431,7 @@ constexpr u32 alpha_blend_r16(u32 d, u32 s, u8 level)
//-------------------------------------------------
-// alpha_blend_r16 - alpha blend two 32-bit
+// alpha_blend_r32 - alpha blend two 32-bit
// 8-8-8 RGB pixels
//-------------------------------------------------
diff --git a/src/emu/drawgfxm.h b/src/emu/drawgfxm.h
index 325ce0e974c..1bef8e15237 100644
--- a/src/emu/drawgfxm.h
+++ b/src/emu/drawgfxm.h
@@ -95,6 +95,21 @@ do
while (0)
/*-------------------------------------------------
+ PIXEL_OP_COPY_TRANSALPHA - render all pixels
+ except those with an alpha of zero, copying
+ directly
+-------------------------------------------------*/
+
+#define PIXEL_OP_COPY_TRANSALPHA(DEST, PRIORITY, SOURCE) \
+do \
+{ \
+ u32 srcdata = (SOURCE); \
+ if ((srcdata & 0xff000000) != 0) \
+ (DEST) = SOURCE; \
+} \
+while (0)
+
+/*-------------------------------------------------
PIXEL_OP_REMAP_OPAQUE - render all pixels
regardless of pen, mapping the pen via the
'paldata' array
diff --git a/src/emu/driver.cpp b/src/emu/driver.cpp
index 76756b2bfb0..75e01880fe2 100644
--- a/src/emu/driver.cpp
+++ b/src/emu/driver.cpp
@@ -260,55 +260,6 @@ void driver_device::device_reset_after_children()
//**************************************************************************
-// INTERRUPT ENABLE AND VECTOR HELPERS
-//**************************************************************************
-
-//-------------------------------------------------
-// irq_pulse_clear - clear a "pulsed" IRQ line
-//-------------------------------------------------
-
-void driver_device::irq_pulse_clear(void *ptr, s32 param)
-{
- device_execute_interface *exec = reinterpret_cast<device_execute_interface *>(ptr);
- int irqline = param;
- exec->set_input_line(irqline, CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// generic_pulse_irq_line - "pulse" an IRQ line by
-// asserting it and then clearing it x cycle(s)
-// later
-//-------------------------------------------------
-
-void driver_device::generic_pulse_irq_line(device_execute_interface &exec, int irqline, int cycles)
-{
- assert(irqline != INPUT_LINE_NMI && irqline != INPUT_LINE_RESET && cycles > 0);
- exec.set_input_line(irqline, ASSERT_LINE);
-
- attotime target_time = exec.local_time() + exec.cycles_to_attotime(cycles * exec.min_cycles());
- machine().scheduler().timer_set(target_time - machine().time(), timer_expired_delegate(FUNC(driver_device::irq_pulse_clear), this), irqline, (void *)&exec);
-}
-
-
-//-------------------------------------------------
-// generic_pulse_irq_line_and_vector - "pulse" an
-// IRQ line by asserting it and then clearing it
-// x cycle(s) later, specifying a vector
-//-------------------------------------------------
-
-void driver_device::generic_pulse_irq_line_and_vector(device_execute_interface &exec, int irqline, int vector, int cycles)
-{
- assert(irqline != INPUT_LINE_NMI && irqline != INPUT_LINE_RESET && cycles > 0);
- exec.set_input_line_and_vector(irqline, ASSERT_LINE, vector);
-
- attotime target_time = exec.local_time() + exec.cycles_to_attotime(cycles * exec.min_cycles());
- machine().scheduler().timer_set(target_time - machine().time(), timer_expired_delegate(FUNC(driver_device::irq_pulse_clear), this), irqline, (void *)&exec);
-}
-
-
-
-//**************************************************************************
// INTERRUPT GENERATION CALLBACK HELPERS
//**************************************************************************
@@ -325,35 +276,27 @@ INTERRUPT_GEN_MEMBER( driver_device::nmi_line_assert ) { device.execute().set_i
//-------------------------------------------------
INTERRUPT_GEN_MEMBER( driver_device::irq0_line_hold ) { device.execute().set_input_line(0, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq0_line_pulse ) { generic_pulse_irq_line(device.execute(), 0, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq0_line_assert ) { device.execute().set_input_line(0, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq1_line_hold ) { device.execute().set_input_line(1, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq1_line_pulse ) { generic_pulse_irq_line(device.execute(), 1, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq1_line_assert ) { device.execute().set_input_line(1, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq2_line_hold ) { device.execute().set_input_line(2, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq2_line_pulse ) { generic_pulse_irq_line(device.execute(), 2, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq2_line_assert ) { device.execute().set_input_line(2, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq3_line_hold ) { device.execute().set_input_line(3, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq3_line_pulse ) { generic_pulse_irq_line(device.execute(), 3, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq3_line_assert ) { device.execute().set_input_line(3, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq4_line_hold ) { device.execute().set_input_line(4, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq4_line_pulse ) { generic_pulse_irq_line(device.execute(), 4, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq4_line_assert ) { device.execute().set_input_line(4, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq5_line_hold ) { device.execute().set_input_line(5, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq5_line_pulse ) { generic_pulse_irq_line(device.execute(), 5, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq5_line_assert ) { device.execute().set_input_line(5, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq6_line_hold ) { device.execute().set_input_line(6, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq6_line_pulse ) { generic_pulse_irq_line(device.execute(), 6, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq6_line_assert ) { device.execute().set_input_line(6, ASSERT_LINE); }
INTERRUPT_GEN_MEMBER( driver_device::irq7_line_hold ) { device.execute().set_input_line(7, HOLD_LINE); }
-INTERRUPT_GEN_MEMBER( driver_device::irq7_line_pulse ) { generic_pulse_irq_line(device.execute(), 7, 1); }
INTERRUPT_GEN_MEMBER( driver_device::irq7_line_assert ) { device.execute().set_input_line(7, ASSERT_LINE); }
diff --git a/src/emu/driver.h b/src/emu/driver.h
index 8ac375c218a..2b4d3088a1f 100644
--- a/src/emu/driver.h
+++ b/src/emu/driver.h
@@ -130,43 +130,31 @@ public:
// output heler
output_manager &output() const { return machine().output(); }
- // generic interrupt generators
- void generic_pulse_irq_line(device_execute_interface &exec, int irqline, int cycles);
- void generic_pulse_irq_line_and_vector(device_execute_interface &exec, int irqline, int vector, int cycles);
-
INTERRUPT_GEN_MEMBER( nmi_line_pulse );
INTERRUPT_GEN_MEMBER( nmi_line_assert );
INTERRUPT_GEN_MEMBER( irq0_line_hold );
- INTERRUPT_GEN_MEMBER( irq0_line_pulse );
INTERRUPT_GEN_MEMBER( irq0_line_assert );
INTERRUPT_GEN_MEMBER( irq1_line_hold );
- INTERRUPT_GEN_MEMBER( irq1_line_pulse );
INTERRUPT_GEN_MEMBER( irq1_line_assert );
INTERRUPT_GEN_MEMBER( irq2_line_hold );
- INTERRUPT_GEN_MEMBER( irq2_line_pulse );
INTERRUPT_GEN_MEMBER( irq2_line_assert );
INTERRUPT_GEN_MEMBER( irq3_line_hold );
- INTERRUPT_GEN_MEMBER( irq3_line_pulse );
INTERRUPT_GEN_MEMBER( irq3_line_assert );
INTERRUPT_GEN_MEMBER( irq4_line_hold );
- INTERRUPT_GEN_MEMBER( irq4_line_pulse );
INTERRUPT_GEN_MEMBER( irq4_line_assert );
INTERRUPT_GEN_MEMBER( irq5_line_hold );
- INTERRUPT_GEN_MEMBER( irq5_line_pulse );
INTERRUPT_GEN_MEMBER( irq5_line_assert );
INTERRUPT_GEN_MEMBER( irq6_line_hold );
- INTERRUPT_GEN_MEMBER( irq6_line_pulse );
INTERRUPT_GEN_MEMBER( irq6_line_assert );
INTERRUPT_GEN_MEMBER( irq7_line_hold );
- INTERRUPT_GEN_MEMBER( irq7_line_pulse );
INTERRUPT_GEN_MEMBER( irq7_line_assert );
@@ -204,7 +192,6 @@ protected:
private:
// helpers
- void irq_pulse_clear(void *ptr, s32 param);
void updateflip();
// internal state
diff --git a/src/emu/drivers/xtal.h b/src/emu/drivers/xtal.h
index dfab1af2ee6..8c9fb948510 100644
--- a/src/emu/drivers/xtal.h
+++ b/src/emu/drivers/xtal.h
@@ -35,6 +35,11 @@
XTAL_3_579545MHz should actually be 3579545.454545...Hz (39375000/11).
This is no problem though: see above note about tolerance.
+ In the "Examples" column, please don't add 1000 examples, this is just
+ for interest, so two or three examples is enough.
+ The actual reference where the xtals are used can be found in the
+ driver files by searching for the frequency (e.g. "XTAL_4_9152MHz")
+
(Thanks to Guru for starting this documentation.)
**************************************************************************/
@@ -53,6 +58,7 @@ enum
XTAL_1MHz = 1000000, /* Used to drive OKI M6295 chips */
XTAL_1_2944MHz = 1294400, /* BBN BitGraph PSG */
XTAL_1_75MHz = 1750000, /* RCA CDP1861 */
+ XTAL_1_7971MHz = 1797100, /* SWTPC 6800 (with MIKBUG) */
XTAL_1_8432MHz = 1843200, /* Bondwell 12/14 */
XTAL_1_9968MHz = 1996800, /* NEC PC-98xx */
XTAL_2MHz = 2000000,
@@ -66,6 +72,7 @@ enum
XTAL_3_12MHz = 3120000, /* SP0250 clock on Gottlieb games */
XTAL_3_5MHz = 3500000, /* Reported by Commodore 65 document, true xtal unchecked on PCB */
XTAL_3_52128MHz = 3521280, /* RCA COSMAC VIP */
+ XTAL_3_57MHz = 3570000, /* Telmac TMC-600 */
XTAL_3_57864MHz = 3578640, /* Atari Portfolio PCD3311T */
XTAL_3_579545MHz = 3579545, /* NTSC color subcarrier, extremely common, used on 100's of PCBs (Keytronic custom part #48-300-010 is equivalent) */
XTAL_3_6864MHz = 3686400, /* Baud rate clock for MC68681 and similar UARTs */
@@ -91,7 +98,7 @@ enum
XTAL_5_911MHz = 5911000, /* Philips Videopac Plus G7400 */
XTAL_5_9904MHz = 5990400, /* Luxor ABC 800 keyboard (Keytronic custom part #48-300-008 is equivalent) */
XTAL_6MHz = 6000000, /* American Poker II, Taito SJ System */
- XTAL_6_144MHz = 6144000, /* Used on Alpha Denshi early 80's games sound board, Casio FP-200 and Namco System 16 */
+ XTAL_6_144MHz = 6144000, /* Used on Alpha Denshi early 80's games sound board, Casio FP-200 and Namco Universal System 16 */
XTAL_6_5MHz = 6500000, /* Jupiter Ace */
XTAL_6_9MHz = 6900000, /* BBN BitGraph CPU */
XTAL_7MHz = 7000000, /* Jaleco Mega System PCBs */
@@ -123,6 +130,7 @@ enum
XTAL_10_733MHz = 10733000, /* The Fairyland Story */
XTAL_10_738635MHz = 10738635, /* TMS9918 family (3x NTSC subcarrier) */
XTAL_10_816MHz = 10816000, /* Universal 1979-1980 (Cosmic Alien, etc) */
+ XTAL_10_920MHz = 10920000, /* ADDS Viewpoint 60, Viewpoint A2 */
XTAL_11MHz = 11000000, /* Mario I8039 sound */
XTAL_11_0592MHz = 11059200, /* Used with MCS-51 to generate common baud rates */
XTAL_11_2MHz = 11200000, /* New York, New York */
@@ -132,6 +140,7 @@ enum
XTAL_11_8MHz = 11800000, /* IBM PC Music Feature Card */
XTAL_11_9808MHz = 11980800, /* Luxor ABC 80 */
XTAL_12MHz = 12000000, /* Extremely common, used on 100's of PCBs */
+ XTAL_12_0576MHz = 12057600, /* Poly 1 (38400 * 314) */
XTAL_12_096MHz = 12096000, /* Some early 80's Atari games */
XTAL_12_288MHz = 12288000, /* Sega Model 3 digital audio board */
XTAL_12_432MHz = 12432000, /* Kaneko Fly Boy/Fast Freddie Hardware */
@@ -149,32 +158,41 @@ enum
XTAL_13_5168MHz = 13516800, /* Kontron KDT6 */
XTAL_14MHz = 14000000,
XTAL_14_112MHz = 14112000, /* Timex/Sinclair TS2068 */
+ XTAL_14_192640MHz = 14192640, /* Reported by Central Data 2650 document, true xtal unchecked on PCB */
+ XTAL_14_218MHz = 14218000, /* Dragon */
XTAL_14_3MHz = 14300000, /* Agat-7 */
XTAL_14_314MHz = 14314000, /* Taito TTL Board */
XTAL_14_31818MHz = 14318181, /* Extremely common, used on 100's of PCBs (4x NTSC subcarrier) */
XTAL_14_705882MHz = 14705882, /* Aleck64 */
XTAL_14_7456MHz = 14745600, /* Namco System 12 & System Super 22/23 for JVS */
+ XTAL_14_916MHz = 14916000, /* ADDS Viewpoint 122 */
XTAL_15MHz = 15000000, /* Sinclair QL, Amusco Poker */
+ XTAL_15_30072MHz = 15300720, /* Microterm 420 */
XTAL_15_36MHz = 15360000, /* Visual 1050 */
XTAL_15_4MHz = 15400000, /* DVK KSM */
XTAL_15_468MHz = 15468480, /* Bank Panic h/w, Sega G80 */
XTAL_15_8976MHz = 15897600, /* IAI Swyft */
XTAL_15_92MHz = 15920000, /* HP Integral PC */
- XTAL_15_9744MHz = 15974400, /* Osborne 1 */
+ XTAL_15_9744MHz = 15974400, /* Osborne 1 (9600 * 52 * 32) */
XTAL_16MHz = 16000000, /* Extremely common, used on 100's of PCBs */
XTAL_16_384MHz = 16384000,
XTAL_16_4MHz = 16400000, /* MS 6102 */
XTAL_16_5888MHz = 16588800, /* SM 7238 */
+ XTAL_16_6698MHz = 16669800, /* Qume QVT-102 */
XTAL_16_67MHz = 16670000,
XTAL_16_777216MHz = 16777216, /* Nintendo Game Boy Advance */
XTAL_16_9344MHz = 16934400, /* Usually used to drive 90's Yamaha OPL/FM chips (44100 * 384) */
+ XTAL_17_064MHz = 17064000, /* Memorex 1377 */
XTAL_17_36MHz = 17360000, /* OMTI Series 10 SCSI controller */
XTAL_17_73447MHz = 17734470, /* (~4x PAL subcarrier) */
XTAL_17_734472MHz = 17734472, /* actually ~4x PAL subcarrier */
XTAL_17_9712MHz = 17971200,
XTAL_18MHz = 18000000, /* S.A.R, Ikari Warriors 3 */
XTAL_18_432MHz = 18432000, /* Extremely common, used on 100's of PCBs (48000 * 384) */
+ XTAL_18_575MHz = 18575000, /* Visual 102 */
XTAL_18_720MHz = 18720000, /* Nokia MikroMikko 1 */
+ XTAL_18_8696MHz = 18869600, /* Memorex 2178 */
+ XTAL_19_3396MHz = 19339600, /* TeleVideo TVI-955 80-column display clock */
XTAL_19_6MHz = 19600000, /* Universal Mr. Do - Model 8021 PCB */
XTAL_19_6608MHz = 19660800, /* Euro League (bootleg), labeled as "UKI 19.6608 20PF" */
XTAL_19_923MHz = 19923000, /* Cinematronics vectors */
@@ -187,9 +205,11 @@ enum
XTAL_21_3MHz = 21300000,
XTAL_21_4772MHz = 21477272, /* BMC bowling, some Data East 90's games, Vtech Socrates; (6x NTSC subcarrier) */
XTAL_22MHz = 22000000,
+ XTAL_22_096MHz = 22096000, /* ADDS Viewpoint 122 */
XTAL_22_1184MHz = 22118400, /* Amusco Poker */
XTAL_22_3210MHz = 22321000, /* Apple LaserWriter II NT */
XTAL_22_656MHz = 22656000, /* Super Pinball Action (~1440x NTSC line rate) */
+ XTAL_23_814MHz = 23814000, /* TeleVideo TVI-912C & 950 */
XTAL_23_9616MHz = 23961600, /* Osborne 4 (Vixen) */
XTAL_24MHz = 24000000, /* Mario, 80's Data East games, 80's Konami games */
XTAL_24_0734MHz = 24073400, /* DEC Rainbow 100 */
@@ -201,10 +221,14 @@ enum
XTAL_25_447MHz = 25447000, /* Namco EVA3A (Funcube2) */
XTAL_25_590906MHz = 25590906, /* Atari Jaguar NTSC */
XTAL_25_593900MHz = 25593900, /* Atari Jaguar PAL */
+ XTAL_25_7715MHz = 25771500, /* HP-2622A */
+ XTAL_25_92MHz = 25920000, /* ADDS Viewpoint 60 */
XTAL_26MHz = 26000000, /* Gaelco PCBs */
XTAL_26_601712MHz = 26601712, /* Astro Corp.'s Show Hand, PAL Vtech/Yeno Socrates (6x PAL subcarrier) */
+ XTAL_26_666MHz = 26666000, /* Imagetek I4100/I4220/I4300 */
XTAL_26_66666MHz = 26666666, /* Irem M92 but most use 27MHz */
XTAL_26_686MHz = 26686000, /* Typically used on 90's Taito PCBs to drive the custom chips */
+ XTAL_26_9892MHz = 26989200, /* TeleVideo 965 */
XTAL_27MHz = 27000000, /* Some Banpresto games macrossp, Irem M92 and 90's Toaplan games */
XTAL_27_164MHz = 27164000, /* Typically used on 90's Taito PCBs to drive the custom chips */
XTAL_27_2109MHz = 27210900, /* LA Girl */
@@ -216,9 +240,11 @@ enum
XTAL_28_64MHz = 28640000, /* Fukki FG-1c AI AM-2 PCB */
XTAL_28_7MHz = 28700000,
XTAL_29_4912MHz = 29491200, /* Xerox Alto-II system clock (tagged 29.4MHz in the schematics) */
+ XTAL_29_876MHz = 29876000, /* Qume QVT-103 */
XTAL_30MHz = 30000000, /* Impera Magic Card */
XTAL_30_4761MHz = 30476100, /* Taito JC */
XTAL_30_8MHz = 30800000, /* 15IE-00-013 */
+ XTAL_31_684MHz = 31684000, /* TeleVideo TVI-955 132-column display clock */
XTAL_32MHz = 32000000,
XTAL_32_22MHz = 32220000, /* Typically used on 90's Data East PCBs (close to 9x NTSC subcarrier which is 32.215905Mhz*/
XTAL_32_5304MHz = 32530400, /* Seta 2 */
@@ -234,12 +260,18 @@ enum
XTAL_40MHz = 40000000,
XTAL_42MHz = 42000000, /* BMC A-00211 - Popo Bear */
XTAL_42_9545MHz = 42954545, /* CPS3 (12x NTSC subcarrier)*/
+ XTAL_43_320MHz = 43320000, /* DEC VT420 */
XTAL_44_1MHz = 44100000, /* Subsino's Bishou Jan */
+ XTAL_44_4528MHz = 44452800, /* TeleVideo 965 */
XTAL_45MHz = 45000000, /* Eolith with Hyperstone CPUs */
XTAL_45_158MHz = 45158000, /* Sega Model 2A video board, Model 3 CPU board */
- XTAL_45_6192Mhz = 45619200, /* DEC VK100 */
+ XTAL_45_582MHz = 45582000, /* Zentec Zephyr */
+ XTAL_45_6192MHz = 45619200, /* DEC VK100 */
+ XTAL_45_8304MHz = 45830400, /* Microterm 5510 */
+ XTAL_47_736MHz = 47736000, /* Visual 100 */
XTAL_48MHz = 48000000, /* Williams/Midway Y/Z-unit system / SSV board */
XTAL_48_384MHz = 48384000, /* Namco NB-1 */
+ XTAL_48_654MHz = 48654000, /* Qume QVT-201 */
XTAL_48_66MHz = 48660000, /* Zaxxon */
XTAL_49_152MHz = 49152000, /* Used on some Namco PCBs, Baraduke h/w, System 21, Super System 22 */
XTAL_50MHz = 50000000, /* Williams/Midway T/W/V-unit system */
@@ -253,6 +285,7 @@ enum
XTAL_55MHz = 55000000, /* Eolith Vega */
XTAL_57_2727MHz = 57272727, /* Psikyo SH2 with /2 divider (16x NTSC subcarrier)*/
XTAL_58MHz = 58000000, /* Magic Reel (Play System) */
+ XTAL_59_2920MHz = 59292000, /* Data General D461 */
XTAL_60MHz = 60000000,
XTAL_61_44MHz = 61440000, /* dkong */
XTAL_64MHz = 64000000, /* BattleToads */
@@ -261,6 +294,7 @@ enum
XTAL_72MHz = 72000000, /* Aristocrat MKV */
XTAL_72_576MHz = 72576000, /* Centipede, Millipede, Missile Command, Let's Go Bowling "Multipede" */
XTAL_73_728MHz = 73728000, /* Ms. Pac-Man/Galaga 20th Anniversary */
+ XTAL_87_18336MHz = 87183360, /* AT&T 630 MTG */
XTAL_100MHz = 100000000, /* PSX-based Namco System 12, Vegas, Sony ZN1-2-based */
XTAL_101_4912MHz = 101491200, /* PSX-based Namco System 10 */
XTAL_200MHz = 200000000, /* Base SH4 CPU (Naomi, Hikaru etc.) */
diff --git a/src/emu/emucore.h b/src/emu/emucore.h
index 46a5427a4ec..04b67869546 100644
--- a/src/emu/emucore.h
+++ b/src/emu/emucore.h
@@ -384,19 +384,6 @@ enum_value(T value) noexcept
// INLINE FUNCTIONS
//**************************************************************************
-// population count
-#if !defined(__NetBSD__)
-inline int popcount(u32 val)
-{
- int count;
-
- for (count = 0; val != 0; count++)
- val &= val - 1;
- return count;
-}
-#endif
-
-
// convert a series of 32 bits into a float
inline float u2f(u32 v)
{
@@ -444,4 +431,14 @@ inline u64 d2u(double d)
return u.vv;
}
+
+// constexpr absolute value of an integer
+inline constexpr int iabs(int v)
+{
+ if(v < 0)
+ return -v;
+ else
+ return v;
+}
+
#endif /* MAME_EMU_EMUCORE_H */
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index cd7de9fecb9..0ab280adbf4 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -130,7 +130,7 @@ class driver_device;
// declared in emumem.h
class address_space;
-class direct_read_data;
+template<int addr_shift> class direct_read_data;
class memory_bank;
class memory_block;
class memory_manager;
diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp
index c6ad1349d23..48e43c4acf1 100644
--- a/src/emu/emumem.cpp
+++ b/src/emu/emumem.cpp
@@ -269,8 +269,9 @@ protected:
public:
// getters
bool populated() const { return m_populated; }
- offs_t bytestart() const { return m_bytestart; }
- offs_t byteend() const { return m_byteend; }
+ offs_t addrstart() const { return m_addrstart; }
+ offs_t addrend() const { return m_addrend; }
+ offs_t addrmask() const { return m_addrmask; }
offs_t bytemask() const { return m_bytemask; }
virtual const char *name() const = 0;
virtual const char *subunit_name(int entry) const = 0;
@@ -279,44 +280,45 @@ public:
virtual void copy(handler_entry *entry);
// return offset within the range referenced by this handler
- offs_t byteoffset(offs_t byteaddress) const { return (byteaddress - m_bytestart) & m_bytemask; }
+ offs_t offset(offs_t address) const { return (address - m_addrstart) & m_addrmask; }
// return a pointer to the backing RAM at the given offset
u8 *ramptr(offs_t offset = 0) const { return *m_rambaseptr + offset; }
// see if we are an exact match to the given parameters
- bool matches_exactly(offs_t bytestart, offs_t byteend, offs_t bytemask) const
+ bool matches_exactly(offs_t addrstart, offs_t addrend, offs_t addrmask) const
{
- return (m_populated && m_bytestart == bytestart && m_byteend == byteend && m_bytemask == bytemask);
+ return (m_populated && m_addrstart == addrstart && m_addrend == addrend && m_addrmask == addrmask);
}
// get the start/end address with the given mirror
- void mirrored_start_end(offs_t byteaddress, offs_t &start, offs_t &end) const
+ void mirrored_start_end(offs_t address, offs_t &start, offs_t &end) const
{
- offs_t mirrorbits = (byteaddress - m_bytestart) & ~m_bytemask;
- start = m_bytestart | mirrorbits;
- end = m_byteend | mirrorbits;
+ offs_t mirrorbits = (address - m_addrstart) & ~m_addrmask;
+ start = m_addrstart | mirrorbits;
+ end = m_addrend | mirrorbits;
}
// configure the handler addresses, and mark as populated
- void configure(offs_t bytestart, offs_t byteend, offs_t bytemask)
+ void configure(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t bytemask)
{
if (m_populated && m_subunits)
- reconfigure_subunits(bytestart);
+ reconfigure_subunits(addrstart);
m_populated = true;
- m_bytestart = bytestart;
- m_byteend = byteend;
+ m_addrstart = addrstart;
+ m_addrend = addrend;
+ m_addrmask = addrmask;
m_bytemask = bytemask;
}
- // Re-expand the bytemask after subunit fun
+ // Re-expand the addrmask after subunit fun
void expand_bytemask(offs_t previous_mask)
{
m_bytemask |= previous_mask;
}
// reconfigure the subunits on a base address change
- void reconfigure_subunits(offs_t bytestart);
+ void reconfigure_subunits(offs_t addrstart);
// depopulate an handler
void deconfigure()
@@ -326,7 +328,7 @@ public:
}
// apply a global mask
- void apply_mask(offs_t bytemask) { m_bytemask &= bytemask; }
+ void apply_mask(offs_t addrmask) { m_addrmask &= addrmask; }
void clear_conflicting_subunits(u64 handlermask);
bool overriden_by_mask(u64 handlermask);
@@ -335,7 +337,7 @@ protected:
// Subunit description information
struct subunit_info
{
- offs_t m_bytemask; // bytemask for this subunit
+ offs_t m_addrmask; // addrmask for this subunit
u32 m_mask; // mask (ff, ffff or ffffffff)
s32 m_offset; // offset to add to the address
u32 m_multiplier; // multiplier to the pre-split address
@@ -351,9 +353,10 @@ protected:
bool m_populated; // populated?
u8 m_datawidth;
endianness_t m_endianness;
- offs_t m_bytestart; // byte-adjusted start address for handler
- offs_t m_byteend; // byte-adjusted end address for handler
- offs_t m_bytemask; // byte-adjusted mask against the final address
+ offs_t m_addrstart; // start address for handler
+ offs_t m_addrend; // end address for handler
+ offs_t m_addrmask; // mask against the final address
+ offs_t m_bytemask; // mask against the final address, byte resolution
u8 ** m_rambaseptr; // pointer to the bank base
u8 m_subunits; // for width stubs, the number of subunits
subunit_info m_subunit_infos[8]; // for width stubs, the associated subunit info
@@ -568,33 +571,33 @@ public:
bool watchpoints_enabled() const { return (m_live_lookup == s_watchpoint_table); }
// address lookups
- u32 lookup_live(offs_t byteaddress) const { return m_large ? lookup_live_large(byteaddress) : lookup_live_small(byteaddress); }
- u32 lookup_live_small(offs_t byteaddress) const { return m_live_lookup[byteaddress]; }
+ u32 lookup_live(offs_t address) const { return m_large ? lookup_live_large(address) : lookup_live_small(address); }
+ u32 lookup_live_small(offs_t address) const { return m_live_lookup[address]; }
- u32 lookup_live_large(offs_t byteaddress) const
+ u32 lookup_live_large(offs_t address) const
{
- u32 entry = m_live_lookup[level1_index_large(byteaddress)];
+ u32 entry = m_live_lookup[level1_index_large(address)];
if (entry >= SUBTABLE_BASE)
- entry = m_live_lookup[level2_index_large(entry, byteaddress)];
+ entry = m_live_lookup[level2_index_large(entry, address)];
return entry;
}
- u32 lookup_live_nowp(offs_t byteaddress) const { return m_large ? lookup_live_large_nowp(byteaddress) : lookup_live_small_nowp(byteaddress); }
- u32 lookup_live_small_nowp(offs_t byteaddress) const { return m_table[byteaddress]; }
+ u32 lookup_live_nowp(offs_t address) const { return m_large ? lookup_live_large_nowp(address) : lookup_live_small_nowp(address); }
+ u32 lookup_live_small_nowp(offs_t address) const { return m_table[address]; }
- u32 lookup_live_large_nowp(offs_t byteaddress) const
+ u32 lookup_live_large_nowp(offs_t address) const
{
- u32 entry = m_table[level1_index_large(byteaddress)];
+ u32 entry = m_table[level1_index_large(address)];
if (entry >= SUBTABLE_BASE)
- entry = m_table[level2_index_large(entry, byteaddress)];
+ entry = m_table[level2_index_large(entry, address)];
return entry;
}
- u32 lookup(offs_t byteaddress) const
+ u32 lookup(offs_t address) const
{
- u32 entry = m_live_lookup[level1_index(byteaddress)];
+ u32 entry = m_live_lookup[level1_index(address)];
if (entry >= SUBTABLE_BASE)
- entry = m_live_lookup[level2_index(entry, byteaddress)];
+ entry = m_live_lookup[level2_index(entry, address)];
return entry;
}
@@ -602,9 +605,9 @@ public:
void enable_watchpoints(bool enable = true) { m_live_lookup = enable ? s_watchpoint_table : &m_table[0]; }
// table mapping helpers
- void map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u16 staticentry);
- void setup_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask, std::list<u32> &entries);
- u16 derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const;
+ void map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 staticentry);
+ void setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask, std::list<u32> &entries);
+ u16 derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const;
// misc helpers
void mask_all_handlers(offs_t mask);
@@ -618,8 +621,8 @@ protected:
u32 level2_index(u16 l1entry, offs_t address) const { return m_large ? level2_index_large(l1entry, address) : 0; }
// table population/depopulation
- void populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, u16 handler);
- void populate_range(offs_t bytestart, offs_t byteend, u16 handler);
+ void populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handler);
+ void populate_range(offs_t addrstart, offs_t addrend, u16 handler);
// subtable management
u16 subtable_alloc();
@@ -700,9 +703,9 @@ public:
handler_entry_read &handler_read(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
// range getter
- handler_entry_proxy<handler_entry_read> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) {
+ handler_entry_proxy<handler_entry_read> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) {
std::list<u32> entries;
- setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries);
+ setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries);
std::list<handler_entry_read *> handlers;
for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i)
handlers.push_back(&handler_read(*i));
@@ -771,9 +774,9 @@ public:
handler_entry_write &handler_write(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
// range getter
- handler_entry_proxy<handler_entry_write> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) {
+ handler_entry_proxy<handler_entry_write> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) {
std::list<u32> entries;
- setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries);
+ setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries);
std::list<handler_entry_write *> handlers;
for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i)
handlers.push_back(&handler_write(*i));
@@ -836,7 +839,7 @@ public:
// Watchpoints and unmap states do not make sense for setoffset
m_handlers[STATIC_NOP]->set_delegate(setoffset_delegate(FUNC(address_table_setoffset::nop_so), this));
- m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0);
}
~address_table_setoffset()
@@ -847,9 +850,9 @@ public:
handler_entry_setoffset &handler_setoffset(u32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
// range getter
- handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, u64 mask = 0) {
+ handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask = 0) {
std::list<u32> entries;
- setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries);
+ setup_range(addrstart, addrend, addrmask, addrmirror, mask, entries);
std::list<handler_entry_setoffset *> handlers;
for (std::list<u32>::const_iterator i = entries.begin(); i != entries.end(); ++i)
handlers.push_back(&handler_setoffset(*i));
@@ -875,20 +878,23 @@ private:
// ======================> address_space_specific
// this is a derived class of address_space with specific width, endianness, and table size
-template<typename _NativeType, endianness_t _Endian, bool _Large>
+template<typename _NativeType, endianness_t _Endian, int _Shift, bool _Large>
class address_space_specific : public address_space
{
- typedef address_space_specific<_NativeType, _Endian, _Large> this_type;
+ typedef address_space_specific<_NativeType, _Endian, _Shift, _Large> this_type;
// constants describing the native size
static const u32 NATIVE_BYTES = sizeof(_NativeType);
- static const u32 NATIVE_MASK = NATIVE_BYTES - 1;
+ static const u32 NATIVE_STEP = _Shift >= 0 ? NATIVE_BYTES << iabs(_Shift) : NATIVE_BYTES >> iabs(_Shift);
+ static const u32 NATIVE_MASK = NATIVE_STEP - 1;
static const u32 NATIVE_BITS = 8 * NATIVE_BYTES;
// helpers to simplify core code
- u32 read_lookup(offs_t byteaddress) const { return _Large ? m_read.lookup_live_large(byteaddress) : m_read.lookup_live_small(byteaddress); }
- u32 write_lookup(offs_t byteaddress) const { return _Large ? m_write.lookup_live_large(byteaddress) : m_write.lookup_live_small(byteaddress); }
- u32 setoffset_lookup(offs_t byteaddress) const { return _Large ? m_setoffset.lookup_live_large(byteaddress) : m_setoffset.lookup_live_small(byteaddress); }
+ u32 read_lookup(offs_t address) const { return _Large ? m_read.lookup_live_large(address) : m_read.lookup_live_small(address); }
+ u32 write_lookup(offs_t address) const { return _Large ? m_write.lookup_live_large(address) : m_write.lookup_live_small(address); }
+ u32 setoffset_lookup(offs_t address) const { return _Large ? m_setoffset.lookup_live_large(address) : m_setoffset.lookup_live_small(address); }
+
+ static inline offs_t offset_to_byte(offs_t offset) { return _Shift < 0 ? offset << iabs(_Shift) : offset >> iabs(_Shift); }
public:
// construction/destruction
@@ -1064,31 +1070,31 @@ public:
}
// return a pointer to the read bank, or nullptr if none
- virtual void *get_read_ptr(offs_t byteaddress) override
+ virtual void *get_read_ptr(offs_t address) override
{
// perform the lookup
- byteaddress &= m_bytemask;
- u32 entry = read_lookup(byteaddress);
+ address &= m_addrmask;
+ u32 entry = read_lookup(address);
const handler_entry_read &handler = m_read.handler_read(entry);
// 8-bit case: RAM/ROM
if (entry > STATIC_BANKMAX)
return nullptr;
- return handler.ramptr(handler.byteoffset(byteaddress));
+ return handler.ramptr(handler.offset(address));
}
// return a pointer to the write bank, or nullptr if none
- virtual void *get_write_ptr(offs_t byteaddress) override
+ virtual void *get_write_ptr(offs_t address) override
{
// perform the lookup
- byteaddress &= m_bytemask;
- u32 entry = write_lookup(byteaddress);
+ address &= m_addrmask;
+ u32 entry = write_lookup(address);
const handler_entry_write &handler = m_write.handler_write(entry);
// 8-bit case: RAM/ROM
if (entry > STATIC_BANKMAX)
return nullptr;
- return handler.ramptr(handler.byteoffset(byteaddress));
+ return handler.ramptr(handler.offset(address));
}
// native read
@@ -1099,12 +1105,12 @@ public:
if (TEST_HANDLER) printf("[r%X,%s]", offset, core_i64_hex_format(mask, sizeof(_NativeType) * 2));
// look up the handler
- offs_t byteaddress = offset & m_bytemask;
- u32 entry = read_lookup(byteaddress);
+ offs_t address = offset & m_addrmask;
+ u32 entry = read_lookup(address);
const handler_entry_read &handler = m_read.handler_read(entry);
// either read directly from RAM, or call the delegate
- offset = handler.byteoffset(byteaddress);
+ offset = offset_to_byte(handler.offset(address));
_NativeType result;
if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset));
else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, mask);
@@ -1124,12 +1130,12 @@ public:
if (TEST_HANDLER) printf("[r%X]", offset);
// look up the handler
- offs_t byteaddress = offset & m_bytemask;
- u32 entry = read_lookup(byteaddress);
+ offs_t address = offset & m_addrmask;
+ u32 entry = read_lookup(address);
const handler_entry_read &handler = m_read.handler_read(entry);
// either read directly from RAM, or call the delegate
- offset = handler.byteoffset(byteaddress);
+ offset = offset_to_byte(handler.offset(address));
_NativeType result;
if (entry <= STATIC_BANKMAX) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset));
else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, 0xff);
@@ -1147,12 +1153,12 @@ public:
g_profiler.start(PROFILER_MEMWRITE);
// look up the handler
- offs_t byteaddress = offset & m_bytemask;
- u32 entry = write_lookup(byteaddress);
+ offs_t address = offset & m_addrmask;
+ u32 entry = write_lookup(address);
const handler_entry_write &handler = m_write.handler_write(entry);
// either write directly to RAM, or call the delegate
- offset = handler.byteoffset(byteaddress);
+ offset = offset_to_byte(handler.offset(address));
if (entry <= STATIC_BANKMAX)
{
_NativeType *dest = reinterpret_cast<_NativeType *>(handler.ramptr(offset));
@@ -1172,12 +1178,12 @@ public:
g_profiler.start(PROFILER_MEMWRITE);
// look up the handler
- offs_t byteaddress = offset & m_bytemask;
- u32 entry = write_lookup(byteaddress);
+ offs_t address = offset & m_addrmask;
+ u32 entry = write_lookup(address);
const handler_entry_write &handler = m_write.handler_write(entry);
// either write directly to RAM, or call the delegate
- offset = handler.byteoffset(byteaddress);
+ offset = offset_to_byte(handler.offset(address));
if (entry <= STATIC_BANKMAX) *reinterpret_cast<_NativeType *>(handler.ramptr(offset)) = data;
else if (sizeof(_NativeType) == 1) handler.write8(*this, offset, data, 0xff);
else if (sizeof(_NativeType) == 2) handler.write16(*this, offset >> 1, data, 0xffff);
@@ -1201,7 +1207,7 @@ public:
// if native size is larger, see if we can do a single masked read (guaranteed if we're aligned)
if (NATIVE_BYTES > TARGET_BYTES)
{
- u32 offsbits = 8 * (address & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1)));
+ u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1)));
if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS))
{
if (_Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits;
@@ -1210,7 +1216,7 @@ public:
}
// determine our alignment against the native boundaries, and mask the address
- u32 offsbits = 8 * (address & (NATIVE_BYTES - 1));
+ u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - 1));
address &= ~NATIVE_MASK;
// if we're here, and native size is larger or equal to the target, we need exactly 2 reads
@@ -1227,7 +1233,7 @@ public:
// read upper bits from upper address
offsbits = NATIVE_BITS - offsbits;
curmask = mask >> offsbits;
- if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) << offsbits;
+ if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) << offsbits;
return result;
}
@@ -1246,7 +1252,7 @@ public:
// read lower bits from upper address
curmask = ljmask << offsbits;
- if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) >> offsbits;
+ if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) >> offsbits;
// return the un-justified result
return result >> LEFT_JUSTIFY_TARGET_TO_NATIVE_SHIFT;
@@ -1272,7 +1278,7 @@ public:
offsbits = NATIVE_BITS - offsbits;
for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
{
- address += NATIVE_BYTES;
+ address += NATIVE_STEP;
curmask = mask >> offsbits;
if (curmask != 0) result |= (_TargetType)read_native(address, curmask) << offsbits;
offsbits += NATIVE_BITS;
@@ -1282,7 +1288,7 @@ public:
if (!_Aligned && offsbits < TARGET_BITS)
{
curmask = mask >> offsbits;
- if (curmask != 0) result |= (_TargetType)read_native(address + NATIVE_BYTES, curmask) << offsbits;
+ if (curmask != 0) result |= (_TargetType)read_native(address + NATIVE_STEP, curmask) << offsbits;
}
}
@@ -1298,7 +1304,7 @@ public:
for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
{
offsbits -= NATIVE_BITS;
- address += NATIVE_BYTES;
+ address += NATIVE_STEP;
curmask = mask >> offsbits;
if (curmask != 0) result |= (_TargetType)read_native(address, curmask) << offsbits;
}
@@ -1308,7 +1314,7 @@ public:
{
offsbits = NATIVE_BITS - offsbits;
curmask = mask << offsbits;
- if (curmask != 0) result |= read_native(address + NATIVE_BYTES, curmask) >> offsbits;
+ if (curmask != 0) result |= read_native(address + NATIVE_STEP, curmask) >> offsbits;
}
}
return result;
@@ -1329,7 +1335,7 @@ public:
// if native size is larger, see if we can do a single masked write (guaranteed if we're aligned)
if (NATIVE_BYTES > TARGET_BYTES)
{
- u32 offsbits = 8 * (address & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1)));
+ u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - (_Aligned ? TARGET_BYTES : 1)));
if (_Aligned || (offsbits + TARGET_BITS <= NATIVE_BITS))
{
if (_Endian != ENDIANNESS_LITTLE) offsbits = NATIVE_BITS - TARGET_BITS - offsbits;
@@ -1338,7 +1344,7 @@ public:
}
// determine our alignment against the native boundaries, and mask the address
- u32 offsbits = 8 * (address & (NATIVE_BYTES - 1));
+ u32 offsbits = 8 * (offset_to_byte(address) & (NATIVE_BYTES - 1));
address &= ~NATIVE_MASK;
// if we're here, and native size is larger or equal to the target, we need exactly 2 writes
@@ -1354,7 +1360,7 @@ public:
// write upper bits to upper address
offsbits = NATIVE_BITS - offsbits;
curmask = mask >> offsbits;
- if (curmask != 0) write_native(address + NATIVE_BYTES, data >> offsbits, curmask);
+ if (curmask != 0) write_native(address + NATIVE_STEP, data >> offsbits, curmask);
}
// big-endian case
@@ -1372,7 +1378,7 @@ public:
// write lower bits to upper address
offsbits = NATIVE_BITS - offsbits;
curmask = ljmask << offsbits;
- if (curmask != 0) write_native(address + NATIVE_BYTES, ljdata << offsbits, curmask);
+ if (curmask != 0) write_native(address + NATIVE_STEP, ljdata << offsbits, curmask);
}
}
@@ -1394,7 +1400,7 @@ public:
offsbits = NATIVE_BITS - offsbits;
for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
{
- address += NATIVE_BYTES;
+ address += NATIVE_STEP;
curmask = mask >> offsbits;
if (curmask != 0) write_native(address, data >> offsbits, curmask);
offsbits += NATIVE_BITS;
@@ -1404,7 +1410,7 @@ public:
if (!_Aligned && offsbits < TARGET_BITS)
{
curmask = mask >> offsbits;
- if (curmask != 0) write_native(address + NATIVE_BYTES, data >> offsbits, curmask);
+ if (curmask != 0) write_native(address + NATIVE_STEP, data >> offsbits, curmask);
}
}
@@ -1420,7 +1426,7 @@ public:
for (u32 index = 0; index < MAX_SPLITS_MINUS_ONE; index++)
{
offsbits -= NATIVE_BITS;
- address += NATIVE_BYTES;
+ address += NATIVE_STEP;
curmask = mask >> offsbits;
if (curmask != 0) write_native(address, data >> offsbits, curmask);
}
@@ -1430,7 +1436,7 @@ public:
{
offsbits = NATIVE_BITS - offsbits;
curmask = mask << offsbits;
- if (curmask != 0) write_native(address + NATIVE_BYTES, data << offsbits, curmask);
+ if (curmask != 0) write_native(address + NATIVE_STEP, data << offsbits, curmask);
}
}
}
@@ -1441,11 +1447,11 @@ public:
// to some particular set_offset operation for an entry in the address map.
void set_address(offs_t address) override
{
- offs_t byteaddress = address & m_bytemask;
- u32 entry = setoffset_lookup(byteaddress);
+ address &= m_addrmask;
+ u32 entry = setoffset_lookup(address);
const handler_entry_setoffset &handler = m_setoffset.handler_setoffset(entry);
- offs_t offset = handler.byteoffset(byteaddress);
+ offs_t offset = handler.offset(address);
handler.setoffset(*this, offset / sizeof(_NativeType));
}
@@ -1499,23 +1505,52 @@ public:
address_table_setoffset m_setoffset; // memory setoffset lookup table
};
-typedef address_space_specific<u8, ENDIANNESS_LITTLE, false> address_space_8le_small;
-typedef address_space_specific<u8, ENDIANNESS_BIG, false> address_space_8be_small;
-typedef address_space_specific<u16, ENDIANNESS_LITTLE, false> address_space_16le_small;
-typedef address_space_specific<u16, ENDIANNESS_BIG, false> address_space_16be_small;
-typedef address_space_specific<u32, ENDIANNESS_LITTLE, false> address_space_32le_small;
-typedef address_space_specific<u32, ENDIANNESS_BIG, false> address_space_32be_small;
-typedef address_space_specific<u64, ENDIANNESS_LITTLE, false> address_space_64le_small;
-typedef address_space_specific<u64, ENDIANNESS_BIG, false> address_space_64be_small;
+typedef address_space_specific<u8, ENDIANNESS_LITTLE, 0, false> address_space_8_8le_small;
+typedef address_space_specific<u8, ENDIANNESS_BIG, 0, false> address_space_8_8be_small;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, 3, false> address_space_16_1le_small;
+typedef address_space_specific<u16, ENDIANNESS_BIG, 3, false> address_space_16_1be_small;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, 0, false> address_space_16_8le_small;
+typedef address_space_specific<u16, ENDIANNESS_BIG, 0, false> address_space_16_8be_small;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, -1, false> address_space_16_16le_small;
+typedef address_space_specific<u16, ENDIANNESS_BIG, -1, false> address_space_16_16be_small;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, 0, false> address_space_32_8le_small;
+typedef address_space_specific<u32, ENDIANNESS_BIG, 0, false> address_space_32_8be_small;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, -1, false> address_space_32_16le_small;
+typedef address_space_specific<u32, ENDIANNESS_BIG, -1, false> address_space_32_16be_small;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, -2, false> address_space_32_32le_small;
+typedef address_space_specific<u32, ENDIANNESS_BIG, -2, false> address_space_32_32be_small;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, 0, false> address_space_64_8le_small;
+typedef address_space_specific<u64, ENDIANNESS_BIG, 0, false> address_space_64_8be_small;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -1, false> address_space_64_16le_small;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -1, false> address_space_64_16be_small;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -2, false> address_space_64_32le_small;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -2, false> address_space_64_32be_small;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -3, false> address_space_64_64le_small;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -3, false> address_space_64_64be_small;
+
+typedef address_space_specific<u8, ENDIANNESS_LITTLE, 0, true> address_space_8_8le_large;
+typedef address_space_specific<u8, ENDIANNESS_BIG, 0, true> address_space_8_8be_large;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, 3, true> address_space_16_1le_large;
+typedef address_space_specific<u16, ENDIANNESS_BIG, 3, true> address_space_16_1be_large;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, 0, true> address_space_16_8le_large;
+typedef address_space_specific<u16, ENDIANNESS_BIG, 0, true> address_space_16_8be_large;
+typedef address_space_specific<u16, ENDIANNESS_LITTLE, -1, true> address_space_16_16le_large;
+typedef address_space_specific<u16, ENDIANNESS_BIG, -1, true> address_space_16_16be_large;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, 0, true> address_space_32_8le_large;
+typedef address_space_specific<u32, ENDIANNESS_BIG, 0, true> address_space_32_8be_large;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, -1, true> address_space_32_16le_large;
+typedef address_space_specific<u32, ENDIANNESS_BIG, -1, true> address_space_32_16be_large;
+typedef address_space_specific<u32, ENDIANNESS_LITTLE, -2, true> address_space_32_32le_large;
+typedef address_space_specific<u32, ENDIANNESS_BIG, -2, true> address_space_32_32be_large;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, 0, true> address_space_64_8le_large;
+typedef address_space_specific<u64, ENDIANNESS_BIG, 0, true> address_space_64_8be_large;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -1, true> address_space_64_16le_large;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -1, true> address_space_64_16be_large;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -2, true> address_space_64_32le_large;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -2, true> address_space_64_32be_large;
+typedef address_space_specific<u64, ENDIANNESS_LITTLE, -3, true> address_space_64_64le_large;
+typedef address_space_specific<u64, ENDIANNESS_BIG, -3, true> address_space_64_64be_large;
-typedef address_space_specific<u8, ENDIANNESS_LITTLE, true> address_space_8le_large;
-typedef address_space_specific<u8, ENDIANNESS_BIG, true> address_space_8be_large;
-typedef address_space_specific<u16, ENDIANNESS_LITTLE, true> address_space_16le_large;
-typedef address_space_specific<u16, ENDIANNESS_BIG, true> address_space_16be_large;
-typedef address_space_specific<u32, ENDIANNESS_LITTLE, true> address_space_32le_large;
-typedef address_space_specific<u32, ENDIANNESS_BIG, true> address_space_32be_large;
-typedef address_space_specific<u64, ENDIANNESS_LITTLE, true> address_space_64le_large;
-typedef address_space_specific<u64, ENDIANNESS_BIG, true> address_space_64be_large;
@@ -1574,72 +1609,206 @@ void memory_manager::allocate(device_memory_interface &memory)
if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
{
if (large)
- memory.allocate<address_space_8le_large>(*this, spacenum);
+ memory.allocate<address_space_8_8le_large>(*this, spacenum);
else
- memory.allocate<address_space_8le_small>(*this, spacenum);
+ memory.allocate<address_space_8_8le_small>(*this, spacenum);
}
else
{
if (large)
- memory.allocate<address_space_8be_large>(*this, spacenum);
+ memory.allocate<address_space_8_8be_large>(*this, spacenum);
else
- memory.allocate<address_space_8be_small>(*this, spacenum);
+ memory.allocate<address_space_8_8be_small>(*this, spacenum);
}
break;
-
+
case 16:
- if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ switch (spaceconfig->addrbus_shift())
{
- if (large)
- memory.allocate<address_space_16le_large>(*this, spacenum);
+ case 3:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_16_1le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_1le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_16le_small>(*this, spacenum);
- }
- else
- {
- if (large)
- memory.allocate<address_space_16be_large>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_16_1be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_1be_small>(*this, spacenum);
+ }
+ break;
+
+ case 0:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_16_8le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_8le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_16be_small>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_16_8be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_8be_small>(*this, spacenum);
+ }
+ break;
+
+ case -1:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_16_16le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_16le_small>(*this, spacenum);
+ }
+ else
+ {
+ if (large)
+ memory.allocate<address_space_16_16be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_16_16be_small>(*this, spacenum);
+ }
+ break;
}
break;
-
+
case 32:
- if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ switch (spaceconfig->addrbus_shift())
{
- if (large)
- memory.allocate<address_space_32le_large>(*this, spacenum);
+ case 0:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_32_8le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_8le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_32le_small>(*this, spacenum);
- }
- else
- {
- if (large)
- memory.allocate<address_space_32be_large>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_32_8be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_8be_small>(*this, spacenum);
+ }
+ break;
+
+ case -1:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_32_16le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_16le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_32be_small>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_32_16be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_16be_small>(*this, spacenum);
+ }
+ break;
+
+ case -2:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_32_32le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_32le_small>(*this, spacenum);
+ }
+ else
+ {
+ if (large)
+ memory.allocate<address_space_32_32be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_32_32be_small>(*this, spacenum);
+ }
+ break;
}
break;
-
+
case 64:
- if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ switch (spaceconfig->addrbus_shift())
{
- if (large)
- memory.allocate<address_space_64le_large>(*this, spacenum);
+ case 0:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_64_8le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_8le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_64le_small>(*this, spacenum);
- }
- else
- {
- if (large)
- memory.allocate<address_space_64be_large>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_64_8be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_8be_small>(*this, spacenum);
+ }
+ break;
+
+ case -1:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_64_16le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_16le_small>(*this, spacenum);
+ }
+ else
+ {
+ if (large)
+ memory.allocate<address_space_64_16be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_16be_small>(*this, spacenum);
+ }
+ break;
+
+ case -2:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_64_32le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_32le_small>(*this, spacenum);
+ }
+ else
+ {
+ if (large)
+ memory.allocate<address_space_64_32be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_32be_small>(*this, spacenum);
+ }
+ break;
+
+ case -3:
+ if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ memory.allocate<address_space_64_64le_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_64le_small>(*this, spacenum);
+ }
else
- memory.allocate<address_space_64be_small>(*this, spacenum);
+ {
+ if (large)
+ memory.allocate<address_space_64_64be_large>(*this, spacenum);
+ else
+ memory.allocate<address_space_64_64be_small>(*this, spacenum);
+ }
+ break;
}
break;
-
+
default:
- throw emu_fatalerror("Invalid width %d specified for memory_manager::allocate", spaceconfig->data_width());
+ throw emu_fatalerror("Invalid width %d specified for address_space::allocate", spaceconfig->data_width());
}
}
}
@@ -1786,19 +1955,24 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m
: m_config(*memory.space_config(spacenum)),
m_device(memory.device()),
m_addrmask(0xffffffffUL >> (32 - m_config.m_addrbus_width)),
- m_bytemask(address_to_byte_end(m_addrmask)),
m_logaddrmask(0xffffffffUL >> (32 - m_config.m_logaddr_width)),
- m_logbytemask(address_to_byte_end(m_logaddrmask)),
m_unmap(0),
m_spacenum(spacenum),
m_log_unmap(true),
- m_direct(std::make_unique<direct_read_data>(*this)),
m_name(memory.space_config(spacenum)->name()),
m_addrchars((m_config.m_addrbus_width + 3) / 4),
m_logaddrchars((m_config.m_logaddr_width + 3) / 4),
m_manager(manager),
m_machine(memory.device().machine())
{
+ switch(m_config.addrbus_shift()) {
+ case 3: m_direct = static_cast<void *>(new direct_read_data< 3>(*this)); break;
+ case 0: m_direct = static_cast<void *>(new direct_read_data< 0>(*this)); break;
+ case -1: m_direct = static_cast<void *>(new direct_read_data<-1>(*this)); break;
+ case -2: m_direct = static_cast<void *>(new direct_read_data<-2>(*this)); break;
+ case -3: m_direct = static_cast<void *>(new direct_read_data<-3>(*this)); break;
+ default: fatalerror("Unsupported address shift %d\n", m_config.addrbus_shift());
+ }
}
@@ -1808,6 +1982,13 @@ address_space::address_space(memory_manager &manager, device_memory_interface &m
address_space::~address_space()
{
+ switch(m_config.addrbus_shift()) {
+ case 3: delete static_cast<direct_read_data< 3> *>(m_direct); break;
+ case 0: delete static_cast<direct_read_data< 0> *>(m_direct); break;
+ case -1: delete static_cast<direct_read_data<-1> *>(m_direct); break;
+ case -2: delete static_cast<direct_read_data<-2> *>(m_direct); break;
+ case -3: delete static_cast<direct_read_data<-3> *>(m_direct); break;
+ }
}
@@ -1822,12 +2003,6 @@ inline void address_space::adjust_addresses(offs_t &start, offs_t &end, offs_t &
mask &= m_addrmask;
start &= ~mirror & m_addrmask;
end &= ~mirror & m_addrmask;
-
- // adjust to byte values
- start = address_to_byte(start);
- end = address_to_byte_end(end);
- mask = address_to_byte_end(mask);
- mirror = address_to_byte(mirror);
}
void address_space::check_optimize_all(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror)
@@ -1978,20 +2153,13 @@ void address_space::prepare_map()
// extract global parameters specified by the map
m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0;
if (m_map->m_globalmask != 0)
- {
m_addrmask = m_map->m_globalmask;
- m_bytemask = address_to_byte_end(m_addrmask);
- }
// make a pass over the address map, adjusting for the device and getting memory pointers
for (address_map_entry &entry : m_map->m_entrylist)
{
// computed adjusted addresses first
- entry.m_bytestart = entry.m_addrstart;
- entry.m_byteend = entry.m_addrend;
- entry.m_bytemirror = entry.m_addrmirror;
- entry.m_bytemask = entry.m_addrmask ? entry.m_addrmask : ~entry.m_addrmirror;
- adjust_addresses(entry.m_bytestart, entry.m_byteend, entry.m_bytemask, entry.m_bytemirror);
+ adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror);
// if we have a share entry, add it to our map
if (entry.m_share != nullptr)
@@ -2000,8 +2168,8 @@ void address_space::prepare_map()
std::string fulltag = entry.m_devbase.subtag(entry.m_share);
if (manager().m_sharelist.find(fulltag.c_str()) == manager().m_sharelist.end())
{
- VPRINTF(("Creating share '%s' of length 0x%X\n", fulltag.c_str(), entry.m_byteend + 1 - entry.m_bytestart));
- manager().m_sharelist.emplace(fulltag.c_str(), std::make_unique<memory_share>(m_map->m_databits, entry.m_byteend + 1 - entry.m_bytestart, endianness()));
+ VPRINTF(("Creating share '%s' of length 0x%X\n", fulltag.c_str(), entry.m_addrend + 1 - entry.m_addrstart));
+ manager().m_sharelist.emplace(fulltag.c_str(), std::make_unique<memory_share>(m_map->m_databits, entry.m_addrend + 1 - entry.m_addrstart, endianness()));
}
}
@@ -2009,10 +2177,10 @@ void address_space::prepare_map()
if (m_spacenum == 0 && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr)
{
// make sure it fits within the memory region before doing so, however
- if (entry.m_byteend < devregionsize)
+ if (entry.m_addrend < devregionsize)
{
entry.m_region = m_device.tag();
- entry.m_rgnoffs = entry.m_bytestart;
+ entry.m_rgnoffs = address_to_byte(entry.m_addrstart);
}
}
@@ -2028,7 +2196,7 @@ void address_space::prepare_map()
fatalerror("device '%s' %s space memory map entry %X-%X references non-existant region \"%s\"\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region);
// validate the region
- if (entry.m_rgnoffs + (entry.m_byteend - entry.m_bytestart + 1) > region->bytes())
+ if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes())
fatalerror("device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes());
}
@@ -2044,8 +2212,8 @@ void address_space::prepare_map()
}
// now loop over all the handlers and enforce the address mask
- read().mask_all_handlers(m_bytemask);
- write().mask_all_handlers(m_bytemask);
+ read().mask_all_handlers(m_addrmask);
+ write().mask_all_handlers(m_addrmask);
}
@@ -2176,13 +2344,13 @@ void address_space::allocate_memory()
int tail = blocklist.size();
for (address_map_entry &entry : m_map->m_entrylist)
if (entry.m_memory != nullptr)
- blocklist.push_back(std::make_unique<memory_block>(*this, entry.m_bytestart, entry.m_byteend, entry.m_memory));
+ blocklist.push_back(std::make_unique<memory_block>(*this, entry.m_addrstart, entry.m_addrend, entry.m_memory));
// loop over all blocks just allocated and assign pointers from them
address_map_entry *unassigned = nullptr;
for (auto memblock = blocklist.begin() + tail; memblock != blocklist.end(); ++memblock)
- unassigned = block_assign_intersecting(memblock->get()->bytestart(), memblock->get()->byteend(), memblock->get()->data());
+ unassigned = block_assign_intersecting(memblock->get()->addrstart(), memblock->get()->addrend(), memblock->get()->data());
// if we don't have an unassigned pointer yet, try to find one
if (unassigned == nullptr)
@@ -2192,8 +2360,8 @@ void address_space::allocate_memory()
while (unassigned != nullptr)
{
// work in MEMORY_BLOCK_CHUNK-sized chunks
- offs_t curblockstart = unassigned->m_bytestart / MEMORY_BLOCK_CHUNK;
- offs_t curblockend = unassigned->m_byteend / MEMORY_BLOCK_CHUNK;
+ offs_t curblockstart = unassigned->m_addrstart / MEMORY_BLOCK_CHUNK;
+ offs_t curblockend = unassigned->m_addrend / MEMORY_BLOCK_CHUNK;
// loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_CHUNK chunks
bool changed;
@@ -2206,8 +2374,8 @@ void address_space::allocate_memory()
if (entry.m_memory == nullptr && &entry != unassigned && needs_backing_store(entry))
{
// get block start/end blocks for this block
- offs_t blockstart = entry.m_bytestart / MEMORY_BLOCK_CHUNK;
- offs_t blockend = entry.m_byteend / MEMORY_BLOCK_CHUNK;
+ offs_t blockstart = entry.m_addrstart / MEMORY_BLOCK_CHUNK;
+ offs_t blockend = entry.m_addrend / MEMORY_BLOCK_CHUNK;
// if we intersect or are adjacent, adjust the start/end
if (blockstart <= curblockend + 1 && blockend >= curblockstart - 1)
@@ -2221,12 +2389,12 @@ void address_space::allocate_memory()
} while (changed);
// we now have a block to allocate; do it
- offs_t curbytestart = curblockstart * MEMORY_BLOCK_CHUNK;
- offs_t curbyteend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1);
- auto block = std::make_unique<memory_block>(*this, curbytestart, curbyteend);
+ offs_t curaddrstart = curblockstart * MEMORY_BLOCK_CHUNK;
+ offs_t curaddrend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1);
+ auto block = std::make_unique<memory_block>(*this, curaddrstart, curaddrend);
// assign memory that intersected the new block
- unassigned = block_assign_intersecting(curbytestart, curbyteend, block.get()->data());
+ unassigned = block_assign_intersecting(curaddrstart, curaddrend, block.get()->data());
blocklist.push_back(std::move(block));
}
}
@@ -2245,7 +2413,7 @@ void address_space::locate_memory()
{
// set the initial bank pointer
for (address_map_entry &entry : m_map->m_entrylist)
- if (entry.m_bytestart == bank.second->bytestart() && entry.m_memory != nullptr)
+ if (entry.m_addrstart == bank.second->addrstart() && entry.m_memory != nullptr)
{
bank.second->set_base(entry.m_memory);
VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank.second->tag(), entry.m_addrstart, entry.m_addrend, entry.m_memory));
@@ -2266,7 +2434,7 @@ void address_space::locate_memory()
// intersecting blocks and assign their pointers
//-------------------------------------------------
-address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, offs_t byteend, u8 *base)
+address_map_entry *address_space::block_assign_intersecting(offs_t addrstart, offs_t addrend, u8 *base)
{
address_map_entry *unassigned = nullptr;
@@ -2290,10 +2458,10 @@ address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, of
}
// otherwise, look for a match in this block
- if (entry.m_memory == nullptr && entry.m_bytestart >= bytestart && entry.m_byteend <= byteend)
+ if (entry.m_memory == nullptr && entry.m_addrstart >= addrstart && entry.m_addrend <= addrend)
{
- entry.m_memory = base + (entry.m_bytestart - bytestart);
- VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, bytestart, byteend, entry.m_memory));
+ entry.m_memory = base + m_config.addr2byte(entry.m_addrstart - addrstart);
+ VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, addrstart, addrend, entry.m_memory));
}
// if we're the first match on a shared pointer, assign it now
@@ -2322,12 +2490,12 @@ address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, of
// describing the handler at a particular offset
//-------------------------------------------------
-const char *address_space::get_handler_string(read_or_write readorwrite, offs_t byteaddress)
+const char *address_space::get_handler_string(read_or_write readorwrite, offs_t address)
{
if (readorwrite == read_or_write::READ)
- return read().handler_name(read().lookup(byteaddress));
+ return read().handler_name(read().lookup(address));
else
- return write().handler_name(write().lookup(byteaddress));
+ return write().handler_name(write().lookup(address));
}
@@ -2343,17 +2511,17 @@ void address_space::dump_map(FILE *file, read_or_write readorwrite)
// dump generic information
fprintf(file, " Address bits = %d\n", m_config.m_addrbus_width);
fprintf(file, " Data bits = %d\n", m_config.m_databus_width);
- fprintf(file, " Address mask = %X\n", m_bytemask);
+ fprintf(file, " Address mask = %X\n", m_addrmask);
fprintf(file, "\n");
// iterate over addresses
- offs_t bytestart, byteend;
- for (offs_t byteaddress = 0; byteaddress <= m_bytemask; byteaddress = byteend)
+ offs_t addrstart, addrend;
+ for (offs_t address = 0; address <= m_addrmask; address = addrend)
{
- u16 entry = table.derive_range(byteaddress, bytestart, byteend);
+ u16 entry = table.derive_range(address, addrstart, addrend);
fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
- bytestart, byteend, entry, table.handler_name(entry), table.handler(entry).bytestart());
- if (++byteend == 0)
+ addrstart, addrend, entry, table.handler_name(entry), table.handler(entry).addrstart());
+ if (++addrend == 0)
break;
}
}
@@ -2549,7 +2717,7 @@ void address_space::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t
{
if (machine().phase() >= machine_phase::RESET)
fatalerror("Attempted to call install_ram_generic() after initialization time without a baseptr!\n");
- auto block = std::make_unique<memory_block>(*this, address_to_byte(addrstart), address_to_byte_end(addrend));
+ auto block = std::make_unique<memory_block>(*this, addrstart, addrend);
bank.set_base(block.get()->data());
manager().m_blocklist.push_back(std::move(block));
}
@@ -2739,10 +2907,7 @@ void address_space::install_setoffset_handler(offs_t addrstart, offs_t addrend,
void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend)
{
- offs_t bytestart = address_to_byte(addrstart);
- offs_t byteend = address_to_byte_end(addrend);
-
- VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, bytestart, byteend));
+ VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, addrstart, addrend));
if (m_map == nullptr)
return nullptr;
@@ -2750,21 +2915,19 @@ void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend)
// look in the address map first
for (address_map_entry &entry : m_map->m_entrylist)
{
- offs_t maskstart = bytestart & entry.m_bytemask;
- offs_t maskend = byteend & entry.m_bytemask;
- if (entry.m_memory != nullptr && maskstart >= entry.m_bytestart && maskend <= entry.m_byteend)
+ if (entry.m_memory != nullptr && addrstart >= entry.m_addrstart && addrend <= entry.m_addrend)
{
- VPRINTF(("found in entry %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, (u8 *)entry.m_memory + (maskstart - entry.m_bytestart)));
- return (u8 *)entry.m_memory + (maskstart - entry.m_bytestart);
+ VPRINTF(("found in entry %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart)));
+ return (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart);
}
}
// if not found there, look in the allocated blocks
for (auto &block : manager().m_blocklist)
- if (block->contains(*this, bytestart, byteend))
+ if (block->contains(*this, addrstart, addrend))
{
- VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->bytestart(), block->byteend(), block->data() + (bytestart - block->bytestart())));
- return block->data() + bytestart - block->bytestart();
+ VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->addrstart(), block->addrend(), block->data() + address_to_byte(addrstart - block->addrstart())));
+ return block->data() + address_to_byte(addrstart - block->addrstart());
}
VPRINTF(("did not find\n"));
@@ -2818,11 +2981,8 @@ bool address_space::needs_backing_store(const address_map_entry &entry)
memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite)
{
// adjust the addresses, handling mirrors and such
- offs_t bytemirror = addrmirror;
- offs_t bytestart = addrstart;
- offs_t bytemask = ~addrmirror;
- offs_t byteend = addrend;
- adjust_addresses(bytestart, byteend, bytemask, bytemirror);
+ offs_t addrmask = ~addrmirror;
+ adjust_addresses(addrstart, addrend, addrmask, addrmirror);
// look up the bank by name, or else by byte range
memory_bank *membank = nullptr;
@@ -2832,7 +2992,7 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst
membank = bank->second.get();
}
else {
- membank = bank_find_anonymous(bytestart, byteend);
+ membank = bank_find_anonymous(addrstart, addrend);
}
// if we don't have a bank yet, find a free one
@@ -2845,11 +3005,11 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst
if (tag != nullptr)
throw emu_fatalerror("Unable to allocate new bank '%s'", tag);
else
- throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", bytestart, byteend);
+ throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", addrstart, addrend);
}
// if no tag, create a unique one
- auto bank = std::make_unique<memory_bank>(*this, banknum, bytestart, byteend, tag);
+ auto bank = std::make_unique<memory_bank>(*this, banknum, addrstart, addrend, tag);
std::string temptag;
if (tag == nullptr) {
temptag = string_format("anon_%p", bank.get());
@@ -2869,17 +3029,56 @@ memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrst
// bank_find_anonymous - try to find an anonymous
// bank matching the given byte range
//-------------------------------------------------
-memory_bank *address_space::bank_find_anonymous(offs_t bytestart, offs_t byteend) const
+memory_bank *address_space::bank_find_anonymous(offs_t addrstart, offs_t addrend) const
{
// try to find an exact match
for (auto &bank : manager().banks())
- if (bank.second->anonymous() && bank.second->references_space(*this, read_or_write::READWRITE) && bank.second->matches_exactly(bytestart, byteend))
+ if (bank.second->anonymous() && bank.second->references_space(*this, read_or_write::READWRITE) && bank.second->matches_exactly(addrstart, addrend))
return bank.second.get();
// not found
return nullptr;
}
+//-------------------------------------------------
+// address_space::invalidate_read_caches -- clear
+// the read cache (direct) for a specific entry
+// or all of them
+//-------------------------------------------------
+
+void address_space::invalidate_read_caches()
+{
+ switch(m_config.addrbus_shift()) {
+ case 3: static_cast<direct_read_data< 3> *>(m_direct)->force_update(); break;
+ case 0: static_cast<direct_read_data< 0> *>(m_direct)->force_update(); break;
+ case -1: static_cast<direct_read_data<-1> *>(m_direct)->force_update(); break;
+ case -2: static_cast<direct_read_data<-2> *>(m_direct)->force_update(); break;
+ case -3: static_cast<direct_read_data<-3> *>(m_direct)->force_update(); break;
+ }
+}
+
+void address_space::invalidate_read_caches(u16 entry)
+{
+ switch(m_config.addrbus_shift()) {
+ case 3: static_cast<direct_read_data< 3> *>(m_direct)->force_update(entry); break;
+ case 0: static_cast<direct_read_data< 0> *>(m_direct)->force_update(entry); break;
+ case -1: static_cast<direct_read_data<-1> *>(m_direct)->force_update(entry); break;
+ case -2: static_cast<direct_read_data<-2> *>(m_direct)->force_update(entry); break;
+ case -3: static_cast<direct_read_data<-3> *>(m_direct)->force_update(entry); break;
+ }
+}
+
+void address_space::invalidate_read_caches(offs_t start, offs_t end)
+{
+ switch(m_config.addrbus_shift()) {
+ case 3: static_cast<direct_read_data< 3> *>(m_direct)->remove_intersecting_ranges(start, end); break;
+ case 0: static_cast<direct_read_data< 0> *>(m_direct)->remove_intersecting_ranges(start, end); break;
+ case -1: static_cast<direct_read_data<-1> *>(m_direct)->remove_intersecting_ranges(start, end); break;
+ case -2: static_cast<direct_read_data<-2> *>(m_direct)->remove_intersecting_ranges(start, end); break;
+ case -3: static_cast<direct_read_data<-3> *>(m_direct)->remove_intersecting_ranges(start, end); break;
+ }
+}
+
//**************************************************************************
// TABLE MANAGEMENT
@@ -2935,27 +3134,23 @@ address_table::~address_table()
void address_table::map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 entry)
{
// convert addresses to bytes
- offs_t bytestart = addrstart;
- offs_t byteend = addrend;
- offs_t bytemask = addrmask;
- offs_t bytemirror = addrmirror;
- m_space.adjust_addresses(bytestart, byteend, bytemask, bytemirror);
+ m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror);
// validity checks
assert_always(addrstart <= addrend, "address_table::map_range called with start greater than end");
- assert_always((bytestart & (m_space.data_width() / 8 - 1)) == 0, "address_table::map_range called with misaligned start address");
- assert_always((byteend & (m_space.data_width() / 8 - 1)) == (m_space.data_width() / 8 - 1), "address_table::map_range called with misaligned end address");
+ assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::map_range called with misaligned start address");
+ assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::map_range called with misaligned end address");
// configure the entry to our parameters (but not for static non-banked cases)
handler_entry &curentry = handler(entry);
if (entry <= STATIC_BANKMAX || entry >= STATIC_COUNT)
- curentry.configure(bytestart, byteend, bytemask);
+ curentry.configure(addrstart, addrend, addrmask, m_space.address_to_byte_end(addrmask));
// populate it
- populate_range_mirrored(bytestart, byteend, bytemirror, entry);
+ populate_range_mirrored(addrstart, addrend, addrmirror, entry);
// recompute any direct access on this space if it is a read modification
- m_space.m_direct->force_update(entry);
+ m_space.invalidate_read_caches(entry);
// verify_reference_counts();
}
@@ -3022,16 +3217,14 @@ namespace {
void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 mask, std::list<u32> &entries)
{
// convert addresses to bytes
- offs_t bytestart = addrstart;
- offs_t byteend = addrend;
- offs_t bytemask = addrmask;
- offs_t bytemirror = addrmirror;
- m_space.adjust_addresses(bytestart, byteend, bytemask, bytemirror);
+ m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror);
// Validity checks
assert_always(addrstart <= addrend, "address_table::setup_range called with start greater than end");
- assert_always((bytestart & (m_space.data_width() / 8 - 1)) == 0, "address_table::setup_range called with misaligned start address");
- assert_always((byteend & (m_space.data_width() / 8 - 1)) == (m_space.data_width() / 8 - 1), "address_table::setup_range called with misaligned end address");
+ assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::setup_range called with misaligned start address");
+ assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::setup_range called with misaligned end address");
+
+ offs_t bytemask = m_space.address_to_byte_end(addrmask);
// Scan the memory to see what has to be done
std::list<subrange> range_override;
@@ -3040,8 +3233,8 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
offs_t base_mirror = 0;
do
{
- offs_t base_address = base_mirror | bytestart;
- offs_t end_address = base_mirror | byteend;
+ offs_t base_address = base_mirror | addrstart;
+ offs_t end_address = base_mirror | addrend;
do
{
@@ -3059,7 +3252,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
while (base_address != end_address + 1);
// Efficient method to go to the next range start given a mirroring mask
- base_mirror = (base_mirror + 1 + ~bytemirror) & bytemirror;
+ base_mirror = (base_mirror + 1 + ~addrmirror) & addrmirror;
}
while (base_mirror);
@@ -3071,7 +3264,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
// configure the entry to our parameters
handler_entry &curentry = handler(entry);
- curentry.configure(bytestart, byteend, bytemask);
+ curentry.configure(addrstart, addrend, addrmask, bytemask);
// Populate it wherever needed
for (std::list<subrange>::const_iterator i = range_override.begin(); i != range_override.end(); ++i)
@@ -3081,7 +3274,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
entries.push_back(entry);
// recompute any direct access on this space if it is a read modification
- m_space.m_direct->force_update(entry);
+ m_space.invalidate_read_caches(entry);
}
// Ranges in range_partial must be duplicated then partially changed
@@ -3111,7 +3304,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
curentry.clear_conflicting_subunits(mask);
// Reconfigure the base addresses
- curentry.configure(bytestart, byteend, bytemask);
+ curentry.configure(addrstart, addrend, addrmask, bytemask);
// Populate it wherever needed
for (const auto & elem : i->second)
@@ -3123,7 +3316,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t
entries.push_back(entry);
// recompute any direct access on this space if it is a read modification
- m_space.m_direct->force_update(entry);
+ m_space.invalidate_read_caches(entry);
}
}
@@ -3182,16 +3375,16 @@ void address_table::verify_reference_counts()
// range of addresses
//-------------------------------------------------
-void address_table::populate_range(offs_t bytestart, offs_t byteend, u16 handlerindex)
+void address_table::populate_range(offs_t addrstart, offs_t addrend, u16 handlerindex)
{
offs_t l2mask = (1 << level2_bits()) - 1;
- offs_t l1start = bytestart >> level2_bits();
- offs_t l2start = bytestart & l2mask;
- offs_t l1stop = byteend >> level2_bits();
- offs_t l2stop = byteend & l2mask;
+ offs_t l1start = addrstart >> level2_bits();
+ offs_t l2start = addrstart & l2mask;
+ offs_t l1stop = addrend >> level2_bits();
+ offs_t l2stop = addrend & l2mask;
// sanity check
- if (bytestart > byteend)
+ if (addrstart > addrend)
return;
// handle the starting edge if it's not on a block boundary
@@ -3267,19 +3460,19 @@ void address_table::populate_range(offs_t bytestart, offs_t byteend, u16 handler
// mirrors
//-------------------------------------------------
-void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, u16 handlerindex)
+void address_table::populate_range_mirrored(offs_t addrstart, offs_t addrend, offs_t addrmirror, u16 handlerindex)
{
// determine the mirror bits
offs_t lmirrorbits = 0;
offs_t lmirrorbit[32];
for (int bit = 0; bit < level2_bits(); bit++)
- if (bytemirror & (1 << bit))
+ if (addrmirror & (1 << bit))
lmirrorbit[lmirrorbits++] = 1 << bit;
offs_t hmirrorbits = 0;
offs_t hmirrorbit[32];
for (int bit = level2_bits(); bit < 32; bit++)
- if (bytemirror & (1 << bit))
+ if (addrmirror & (1 << bit))
hmirrorbit[hmirrorbits++] = 1 << bit;
// loop over mirrors in the level 2 table
@@ -3301,14 +3494,14 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
for (int bit = 0; bit < lmirrorbits; bit++)
if (lmirrorcount & (1 << bit))
lmirrorbase |= lmirrorbit[bit];
- m_space.m_direct->remove_intersecting_ranges(bytestart + lmirrorbase, byteend + lmirrorbase);
+ m_space.invalidate_read_caches(addrstart + lmirrorbase, addrend + lmirrorbase);
}
// if this is not our first time through, and the level 2 entry matches the previous
// level 2 entry, just do a quick map and get out; note that this only works for entries
// which don't span multiple level 1 table entries
- int cur_index = level1_index(bytestart + hmirrorbase);
- if (cur_index == level1_index(byteend + hmirrorbase))
+ int cur_index = level1_index(addrstart + hmirrorbase);
+ if (cur_index == level1_index(addrend + hmirrorbase))
{
if (hmirrorcount != 0 && prev_entry == m_table[cur_index])
{
@@ -3344,7 +3537,7 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
lmirrorbase |= lmirrorbit[bit];
// populate the tables
- populate_range(bytestart + lmirrorbase, byteend + lmirrorbase, handlerindex);
+ populate_range(addrstart + lmirrorbase, addrend + lmirrorbase, handlerindex);
}
}
}
@@ -3356,22 +3549,22 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
// range based on the lookup tables
//-------------------------------------------------
-u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const
+u16 address_table::derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const
{
// look up the initial address to get the entry we care about
u16 l1entry;
- u16 entry = l1entry = m_table[level1_index(byteaddress)];
+ u16 entry = l1entry = m_table[level1_index(address)];
if (l1entry >= SUBTABLE_BASE)
- entry = m_table[level2_index(l1entry, byteaddress)];
+ entry = m_table[level2_index(l1entry, address)];
- // use the bytemask of the entry to set minimum and maximum bounds
+ // use the addrmask of the entry to set minimum and maximum bounds
offs_t minscan, maxscan;
- handler(entry).mirrored_start_end(byteaddress, minscan, maxscan);
+ handler(entry).mirrored_start_end(address, minscan, maxscan);
// first scan backwards to find the start address
u16 curl1entry = l1entry;
u16 curentry = entry;
- bytestart = byteaddress;
+ addrstart = address;
while (1)
{
// if we need to scan the subtable, do it
@@ -3381,7 +3574,7 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b
u32 index;
// scan backwards from the current address, until the previous entry doesn't match
- for (index = level2_index(curl1entry, bytestart); index > minindex; index--, bytestart -= 1)
+ for (index = level2_index(curl1entry, addrstart); index > minindex; index--, addrstart -= 1)
if (m_table[index - 1] != entry)
break;
@@ -3391,25 +3584,25 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b
}
// move to the beginning of this L1 entry; stop at the minimum address
- bytestart &= ~((1 << level2_bits()) - 1);
- if (bytestart <= minscan)
+ addrstart &= ~((1 << level2_bits()) - 1);
+ if (addrstart <= minscan)
break;
// look up the entry of the byte at the end of the previous L1 entry; if it doesn't match, stop
- curentry = curl1entry = m_table[level1_index(bytestart - 1)];
+ curentry = curl1entry = m_table[level1_index(addrstart - 1)];
if (curl1entry >= SUBTABLE_BASE)
- curentry = m_table[level2_index(curl1entry, bytestart - 1)];
+ curentry = m_table[level2_index(curl1entry, addrstart - 1)];
if (curentry != entry)
break;
// move into the previous entry and resume searching
- bytestart -= 1;
+ addrstart -= 1;
}
// then scan forwards to find the end address
curl1entry = l1entry;
curentry = entry;
- byteend = byteaddress;
+ addrend = address;
while (1)
{
// if we need to scan the subtable, do it
@@ -3419,7 +3612,7 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b
u32 index;
// scan forwards from the current address, until the next entry doesn't match
- for (index = level2_index(curl1entry, byteend); index < maxindex; index++, byteend += 1)
+ for (index = level2_index(curl1entry, addrend); index < maxindex; index++, addrend += 1)
if (m_table[index + 1] != entry)
break;
@@ -3429,19 +3622,19 @@ u16 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &b
}
// move to the end of this L1 entry; stop at the maximum address
- byteend |= (1 << level2_bits()) - 1;
- if (byteend >= maxscan)
+ addrend |= (1 << level2_bits()) - 1;
+ if (addrend >= maxscan)
break;
// look up the entry of the byte at the start of the next L1 entry; if it doesn't match, stop
- curentry = curl1entry = m_table[level1_index(byteend + 1)];
+ curentry = curl1entry = m_table[level1_index(addrend + 1)];
if (curl1entry >= SUBTABLE_BASE)
- curentry = m_table[level2_index(curl1entry, byteend + 1)];
+ curentry = m_table[level2_index(curl1entry, addrend + 1)];
if (curentry != entry)
break;
// move into the next entry and resume searching
- byteend += 1;
+ addrend += 1;
}
return entry;
@@ -3746,9 +3939,9 @@ address_table_read::address_table_read(address_space &space, bool large)
}
// reset the byte masks on the special handlers to open up the full address space for proper reporting
- m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0);
- m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
- m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0);
+ m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0);
+ m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0);
}
@@ -3820,9 +4013,9 @@ address_table_write::address_table_write(address_space &space, bool large)
}
// reset the byte masks on the special handlers to open up the full address space for proper reporting
- m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0);
- m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
- m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_UNMAP]->configure(0, space.addrmask(), ~0, ~0);
+ m_handlers[STATIC_NOP]->configure(0, space.addrmask(), ~0, ~0);
+ m_handlers[STATIC_WATCHPOINT]->configure(0, space.addrmask(), ~0, ~0);
}
@@ -3856,12 +4049,12 @@ handler_entry &address_table_write::handler(u32 index) const
// direct_read_data - constructor
//-------------------------------------------------
-direct_read_data::direct_read_data(address_space &space)
+template<int addr_shift> direct_read_data<addr_shift>::direct_read_data(address_space &space)
: m_space(space),
m_ptr(nullptr),
- m_bytemask(space.bytemask()),
- m_bytestart(1),
- m_byteend(0),
+ m_addrmask(space.addrmask()),
+ m_addrstart(1),
+ m_addrend(0),
m_entry(STATIC_UNMAP)
{
}
@@ -3871,7 +4064,7 @@ direct_read_data::direct_read_data(address_space &space)
// ~direct_read_data - destructor
//-------------------------------------------------
-direct_read_data::~direct_read_data()
+template<int addr_shift> direct_read_data<addr_shift>::~direct_read_data()
{
}
@@ -3881,29 +4074,35 @@ direct_read_data::~direct_read_data()
// update the opcode base for the given address
//-------------------------------------------------
-bool direct_read_data::set_direct_region(offs_t byteaddress)
+template<int addr_shift> bool direct_read_data<addr_shift>::set_direct_region(offs_t address)
{
// find or allocate a matching range
- direct_range *range = find_range(byteaddress, m_entry);
+ direct_range *range = find_range(address, m_entry);
// if we don't map to a bank, return false
if (m_entry < STATIC_BANK1 || m_entry > STATIC_BANKMAX)
{
// ensure future updates to land here as well until we get back into a bank
- m_byteend = 0;
- m_bytestart = 1;
+ m_addrend = 0;
+ m_addrstart = 1;
return false;
}
u8 *base = *m_space.manager().bank_pointer_addr(m_entry);
// compute the adjusted base
- offs_t maskedbits = byteaddress & ~m_space.bytemask();
+ offs_t maskedbits = address & ~m_space.addrmask();
const handler_entry_read &handler = m_space.read().handler_read(m_entry);
- m_bytemask = handler.bytemask();
- m_ptr = base - (handler.bytestart() & m_bytemask);
- m_bytestart = maskedbits | range->m_bytestart;
- m_byteend = maskedbits | range->m_byteend;
+ m_addrmask = handler.addrmask();
+ u32 delta = handler.addrstart() & m_addrmask;
+ if(addr_shift < 0)
+ delta = delta << iabs(addr_shift);
+ else if(addr_shift > 0)
+ delta = delta >> iabs(addr_shift);
+
+ m_ptr = base - delta;
+ m_addrstart = maskedbits | range->m_addrstart;
+ m_addrend = maskedbits | range->m_addrend;
return true;
}
@@ -3912,20 +4111,20 @@ bool direct_read_data::set_direct_region(offs_t byteaddress)
// find_range - find a byte address in a range
//-------------------------------------------------
-direct_read_data::direct_range *direct_read_data::find_range(offs_t byteaddress, u16 &entry)
+template<int addr_shift> typename direct_read_data<addr_shift>::direct_range *direct_read_data<addr_shift>::find_range(offs_t address, u16 &entry)
{
// determine which entry
- byteaddress &= m_space.m_bytemask;
- entry = m_space.read().lookup_live_nowp(byteaddress);
+ address &= m_space.m_addrmask;
+ entry = m_space.read().lookup_live_nowp(address);
// scan our table
for (auto &range : m_rangelist[entry])
- if (byteaddress >= range.m_bytestart && byteaddress <= range.m_byteend)
+ if (address >= range.m_addrstart && address <= range.m_addrend)
return &range;
// didn't find out; create a new one
direct_range range;
- m_space.read().derive_range(byteaddress, range.m_bytestart, range.m_byteend);
+ m_space.read().derive_range(address, range.m_addrstart, range.m_addrend);
m_rangelist[entry].push_front(range);
return &m_rangelist[entry].front();
@@ -3937,7 +4136,7 @@ direct_read_data::direct_range *direct_read_data::find_range(offs_t byteaddress,
// ranges that intersect the given address range
//-------------------------------------------------
-void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t byteend)
+template<int addr_shift> void direct_read_data<addr_shift>::remove_intersecting_ranges(offs_t addrstart, offs_t addrend)
{
// loop over all entries
for (auto & elem : m_rangelist)
@@ -3946,7 +4145,7 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee
for (auto range = elem.begin(); range!=elem.end();)
{
// if we intersect, remove
- if (bytestart <= range->m_byteend && byteend >= range->m_bytestart)
+ if (addrstart <= range->m_addrend && addrend >= range->m_addrstart)
range = elem.erase(range);
else
range ++;
@@ -3954,6 +4153,12 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee
}
}
+template class direct_read_data<3>;
+template class direct_read_data<0>;
+template class direct_read_data<-1>;
+template class direct_read_data<-2>;
+template class direct_read_data<-3>;
+
//**************************************************************************
// MEMORY BLOCK
@@ -3963,15 +4168,15 @@ void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t bytee
// memory_block - constructor
//-------------------------------------------------
-memory_block::memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory)
+memory_block::memory_block(address_space &space, offs_t addrstart, offs_t addrend, void *memory)
: m_machine(space.machine()),
m_space(space),
- m_bytestart(bytestart),
- m_byteend(byteend),
+ m_addrstart(addrstart),
+ m_addrend(addrend),
m_data(reinterpret_cast<u8 *>(memory))
{
- offs_t const length = byteend + 1 - bytestart;
- VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), bytestart, byteend, memory));
+ offs_t const length = space.address_to_byte(addrend + 1 - addrstart);
+ VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), addrstart, addrend, memory));
// allocate a block if needed
if (m_data == nullptr)
@@ -3996,8 +4201,8 @@ memory_block::memory_block(address_space &space, offs_t bytestart, offs_t byteen
else
{
int bytes_per_element = space.data_width() / 8;
- std::string name = string_format("%08x-%08x", bytestart, byteend);
- space.machine().save().save_memory(nullptr, "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element);
+ std::string name = string_format("%08x-%08x", addrstart, addrend);
+ space.machine().save().save_memory(&space.device(), "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element);
}
}
@@ -4020,13 +4225,13 @@ memory_block::~memory_block()
// memory_bank - constructor
//-------------------------------------------------
-memory_bank::memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag)
+memory_bank::memory_bank(address_space &space, int index, offs_t addrstart, offs_t addrend, const char *tag)
: m_machine(space.machine()),
m_baseptr(space.manager().bank_pointer_addr(index)),
m_index(index),
m_anonymous(tag == nullptr),
- m_bytestart(bytestart),
- m_byteend(byteend),
+ m_addrstart(addrstart),
+ m_addrend(addrend),
m_curentry(BANK_ENTRY_UNSPECIFIED)
{
// generate an internal tag if we don't have one
@@ -4042,7 +4247,7 @@ memory_bank::memory_bank(address_space &space, int index, offs_t bytestart, offs
}
if (!m_anonymous && space.machine().save().registration_allowed())
- space.machine().save().save_item(nullptr, "memory", m_tag.c_str(), 0, NAME(m_curentry));
+ space.machine().save().save_item(&space.device(), "memory", m_tag.c_str(), 0, NAME(m_curentry));
}
@@ -4093,7 +4298,7 @@ void memory_bank::invalidate_references()
{
// invalidate all the direct references to any referenced address spaces
for (auto &ref : m_reflist)
- ref->space().direct().force_update();
+ ref->space().invalidate_read_caches();
}
@@ -4218,8 +4423,9 @@ handler_entry::handler_entry(u8 width, endianness_t endianness, u8 **rambaseptr)
: m_populated(false),
m_datawidth(width),
m_endianness(endianness),
- m_bytestart(0),
- m_byteend(0),
+ m_addrstart(0),
+ m_addrend(0),
+ m_addrmask(~0),
m_bytemask(~0),
m_rambaseptr(rambaseptr),
m_subunits(0),
@@ -4253,8 +4459,9 @@ void handler_entry::copy(handler_entry *entry)
m_populated = true;
m_datawidth = entry->m_datawidth;
m_endianness = entry->m_endianness;
- m_bytestart = entry->m_bytestart;
- m_byteend = entry->m_byteend;
+ m_addrstart = entry->m_addrstart;
+ m_addrend = entry->m_addrend;
+ m_addrmask = entry->m_addrmask;
m_bytemask = entry->m_bytemask;
m_rambaseptr = nullptr;
m_subunits = entry->m_subunits;
@@ -4267,9 +4474,9 @@ void handler_entry::copy(handler_entry *entry)
// reconfigure_subunits - reconfigure the subunits
// to handle a new base address
//-------------------------------------------------
-void handler_entry::reconfigure_subunits(offs_t bytestart)
+void handler_entry::reconfigure_subunits(offs_t addrstart)
{
- s32 delta = bytestart - m_bytestart;
+ s32 delta = addrstart - m_addrstart;
for (int i=0; i != m_subunits; i++)
m_subunit_infos[i].m_offset += delta / (m_subunit_infos[i].m_size / 8);
}
@@ -4319,7 +4526,7 @@ void handler_entry::configure_subunits(u64 handlermask, int handlerbits, int &st
u32 shift = (unitnum^shift_xor_mask) * handlerbits;
if (((handlermask >> shift) & unitmask) != 0)
{
- m_subunit_infos[m_subunits].m_bytemask = m_bytemask / (maxunits / multiplier);
+ m_subunit_infos[m_subunits].m_addrmask = m_bytemask / (maxunits / multiplier);
m_subunit_infos[m_subunits].m_mask = unitmask;
m_subunit_infos[m_subunits].m_offset = cur_offset++;
m_subunit_infos[m_subunits].m_size = handlerbits;
@@ -4413,7 +4620,7 @@ void handler_entry::description(char *buffer) const
m_subunit_infos[i].m_shift,
m_subunit_infos[i].m_offset,
m_subunit_infos[i].m_multiplier,
- m_subunit_infos[i].m_bytemask,
+ m_subunit_infos[i].m_addrmask,
subunit_name(i));
}
}
@@ -4660,7 +4867,7 @@ u16 handler_entry_read::read_stub_16(address_space &space, offs_t offset, u16 ma
{
offs_t aoffset = offset * si.m_multiplier + si.m_offset;
u8 val;
- val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask);
result |= val << si.m_shift;
}
}
@@ -4687,10 +4894,10 @@ u32 handler_entry_read::read_stub_32(address_space &space, offs_t offset, u32 ma
switch (si.m_size)
{
case 8:
- val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask);
break;
case 16:
- val = m_subread[index].r16(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r16(space, aoffset & si.m_addrmask, submask);
break;
}
result |= val << si.m_shift;
@@ -4719,13 +4926,13 @@ u64 handler_entry_read::read_stub_64(address_space &space, offs_t offset, u64 ma
switch (si.m_size)
{
case 8:
- val = m_subread[index].r8(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r8(space, aoffset & si.m_addrmask, submask);
break;
case 16:
- val = m_subread[index].r16(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r16(space, aoffset & si.m_addrmask, submask);
break;
case 32:
- val = m_subread[index].r32(space, aoffset & si.m_bytemask, submask);
+ val = m_subread[index].r32(space, aoffset & si.m_addrmask, submask);
break;
}
result |= u64(val) << si.m_shift;
@@ -4953,7 +5160,7 @@ void handler_entry_write::write_stub_16(address_space &space, offs_t offset, u16
{
offs_t aoffset = offset * si.m_multiplier + si.m_offset;
u8 adata = data >> si.m_shift;
- m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask);
}
}
}
@@ -4977,10 +5184,10 @@ void handler_entry_write::write_stub_32(address_space &space, offs_t offset, u32
switch (si.m_size)
{
case 8:
- m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask);
break;
case 16:
- m_subwrite[index].w16(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, submask);
break;
}
}
@@ -5006,13 +5213,13 @@ void handler_entry_write::write_stub_64(address_space &space, offs_t offset, u64
switch (si.m_size)
{
case 8:
- m_subwrite[index].w8(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w8(space, aoffset & si.m_addrmask, adata, submask);
break;
case 16:
- m_subwrite[index].w16(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w16(space, aoffset & si.m_addrmask, adata, submask);
break;
case 32:
- m_subwrite[index].w32(space, aoffset & si.m_bytemask, adata, submask);
+ m_subwrite[index].w32(space, aoffset & si.m_addrmask, adata, submask);
break;
}
}
diff --git a/src/emu/emumem.h b/src/emu/emumem.h
index 19edc918aaa..45e1a759138 100644
--- a/src/emu/emumem.h
+++ b/src/emu/emumem.h
@@ -17,6 +17,14 @@
#ifndef MAME_EMU_EMUMEM_H
#define MAME_EMU_EMUMEM_H
+using s8 = std::int8_t;
+using u8 = std::uint8_t;
+using s16 = std::int16_t;
+using u16 = std::uint16_t;
+using s32 = std::int32_t;
+using u32 = std::uint32_t;
+using s64 = std::int64_t;
+using u64 = std::uint64_t;
//**************************************************************************
@@ -63,21 +71,21 @@ typedef named_delegate<void (address_map &)> address_map_delegate;
// struct with function pointers for accessors; use is generally discouraged unless necessary
struct data_accessors
{
- u8 (*read_byte)(address_space &space, offs_t byteaddress);
- u16 (*read_word)(address_space &space, offs_t byteaddress);
- u16 (*read_word_masked)(address_space &space, offs_t byteaddress, u16 mask);
- u32 (*read_dword)(address_space &space, offs_t byteaddress);
- u32 (*read_dword_masked)(address_space &space, offs_t byteaddress, u32 mask);
- u64 (*read_qword)(address_space &space, offs_t byteaddress);
- u64 (*read_qword_masked)(address_space &space, offs_t byteaddress, u64 mask);
-
- void (*write_byte)(address_space &space, offs_t byteaddress, u8 data);
- void (*write_word)(address_space &space, offs_t byteaddress, u16 data);
- void (*write_word_masked)(address_space &space, offs_t byteaddress, u16 data, u16 mask);
- void (*write_dword)(address_space &space, offs_t byteaddress, u32 data);
- void (*write_dword_masked)(address_space &space, offs_t byteaddress, u32 data, u32 mask);
- void (*write_qword)(address_space &space, offs_t byteaddress, u64 data);
- void (*write_qword_masked)(address_space &space, offs_t byteaddress, u64 data, u64 mask);
+ u8 (*read_byte)(address_space &space, offs_t address);
+ u16 (*read_word)(address_space &space, offs_t address);
+ u16 (*read_word_masked)(address_space &space, offs_t address, u16 mask);
+ u32 (*read_dword)(address_space &space, offs_t address);
+ u32 (*read_dword_masked)(address_space &space, offs_t address, u32 mask);
+ u64 (*read_qword)(address_space &space, offs_t address);
+ u64 (*read_qword_masked)(address_space &space, offs_t address, u64 mask);
+
+ void (*write_byte)(address_space &space, offs_t address, u8 data);
+ void (*write_word)(address_space &space, offs_t address, u16 data);
+ void (*write_word_masked)(address_space &space, offs_t address, u16 data, u16 mask);
+ void (*write_dword)(address_space &space, offs_t address, u32 data);
+ void (*write_dword_masked)(address_space &space, offs_t address, u32 data, u32 mask);
+ void (*write_qword)(address_space &space, offs_t address, u64 data);
+ void (*write_qword_masked)(address_space &space, offs_t address, u64 data, u64 mask);
};
@@ -106,26 +114,28 @@ typedef device_delegate<void (address_space &, offs_t)> setoffset_delegate;
// ======================> direct_read_data
// direct_read_data contains state data for direct read access
-class direct_read_data
+template<int addr_shift> class direct_read_data
{
friend class address_table;
public:
+ using direct_update_delegate = delegate<offs_t (direct_read_data<addr_shift> &, offs_t)>;
+
// direct_range is an internal class that is part of a list of start/end ranges
class direct_range
{
public:
// construction
- direct_range(): m_bytestart(0),m_byteend(~0) { }
+ direct_range(): m_addrstart(0),m_addrend(~0) { }
inline bool operator==(direct_range val) noexcept
{ // return true if _Left and _Right identify the same thread
- return (m_bytestart == val.m_bytestart) && (m_byteend == val.m_byteend);
+ return (m_addrstart == val.m_addrstart) && (m_addrend == val.m_addrend);
}
// internal state
- offs_t m_bytestart; // starting byte offset of the range
- offs_t m_byteend; // ending byte offset of the range
+ offs_t m_addrstart; // starting offset of the range
+ offs_t m_addrend; // ending offset of the range
};
// construction/destruction
@@ -137,31 +147,32 @@ public:
u8 *ptr() const { return m_ptr; }
// see if an address is within bounds, or attempt to update it if not
- bool address_is_valid(offs_t byteaddress) { return EXPECTED(byteaddress >= m_bytestart && byteaddress <= m_byteend) || set_direct_region(byteaddress); }
+ bool address_is_valid(offs_t address) { return EXPECTED(address >= m_addrstart && address <= m_addrend) || set_direct_region(address); }
// force a recomputation on the next read
- void force_update() { m_byteend = 0; m_bytestart = 1; }
+ void force_update() { m_addrend = 0; m_addrstart = 1; }
void force_update(u16 if_match) { if (m_entry == if_match) force_update(); }
// accessor methods
- void *read_ptr(offs_t byteaddress, offs_t directxor = 0);
- u8 read_byte(offs_t byteaddress, offs_t directxor = 0);
- u16 read_word(offs_t byteaddress, offs_t directxor = 0);
- u32 read_dword(offs_t byteaddress, offs_t directxor = 0);
- u64 read_qword(offs_t byteaddress, offs_t directxor = 0);
+ void *read_ptr(offs_t address, offs_t directxor = 0);
+ u8 read_byte(offs_t address, offs_t directxor = 0);
+ u16 read_word(offs_t address, offs_t directxor = 0);
+ u32 read_dword(offs_t address, offs_t directxor = 0);
+ u64 read_qword(offs_t address, offs_t directxor = 0);
+
+ void remove_intersecting_ranges(offs_t start, offs_t end);
private:
// internal helpers
- bool set_direct_region(offs_t byteaddress);
- direct_range *find_range(offs_t byteaddress, u16 &entry);
- void remove_intersecting_ranges(offs_t bytestart, offs_t byteend);
+ bool set_direct_region(offs_t address);
+ direct_range *find_range(offs_t address, u16 &entry);
// internal state
address_space & m_space;
u8 * m_ptr; // direct access data pointer
- offs_t m_bytemask; // byte address mask
- offs_t m_bytestart; // minimum valid byte address
- offs_t m_byteend; // maximum valid byte address
+ offs_t m_addrmask; // address mask
+ offs_t m_addrstart; // minimum valid address
+ offs_t m_addrend; // maximum valid address
u16 m_entry; // live entry
std::list<direct_range> m_rangelist[TOTAL_MEMORY_BANKS]; // list of ranges for each entry
};
@@ -185,11 +196,17 @@ public:
endianness_t endianness() const { return m_endianness; }
int data_width() const { return m_databus_width; }
int addr_width() const { return m_addrbus_width; }
+ int addrbus_shift() const { return m_addrbus_shift; }
- // address-to-byte conversion helpers
+ // Actual alignment of the bus addresses
+ int alignment() const { int bytes = m_databus_width / 8; return m_addrbus_shift < 0 ? bytes >> -m_addrbus_shift : bytes << m_addrbus_shift; }
+
+ // Address delta to byte delta helpers
inline offs_t addr2byte(offs_t address) const { return (m_addrbus_shift < 0) ? (address << -m_addrbus_shift) : (address >> m_addrbus_shift); }
- inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); }
inline offs_t byte2addr(offs_t address) const { return (m_addrbus_shift > 0) ? (address << m_addrbus_shift) : (address >> -m_addrbus_shift); }
+
+ // address-to-byte conversion helpers
+ inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); }
inline offs_t byte2addr_end(offs_t address) const { return (m_addrbus_shift > 0) ? ((address << m_addrbus_shift) | ((1 << m_addrbus_shift) - 1)) : (address >> -m_addrbus_shift); }
// state
@@ -218,7 +235,11 @@ class address_space
friend class address_table_read;
friend class address_table_write;
friend class address_table_setoffset;
- friend class direct_read_data;
+ friend class direct_read_data<3>;
+ friend class direct_read_data<0>;
+ friend class direct_read_data<-1>;
+ friend class direct_read_data<-2>;
+ friend class direct_read_data<-3>;
protected:
// construction/destruction
@@ -235,19 +256,24 @@ public:
int spacenum() const { return m_spacenum; }
address_map *map() const { return m_map.get(); }
- direct_read_data &direct() const { return *m_direct; }
+ template<int addr_shift> direct_read_data<addr_shift> *direct() const {
+ static_assert(addr_shift == 3 || addr_shift == 0 || addr_shift == -1 || addr_shift == -2 || addr_shift == -3, "Unsupported addr_shift in direct()");
+ if(addr_shift != m_config.addrbus_shift())
+ fatalerror("Requesing direct() with address shift %d while the config says %d\n", addr_shift, m_config.addrbus_shift());
+ return static_cast<direct_read_data<addr_shift> *>(m_direct);
+ }
int data_width() const { return m_config.data_width(); }
int addr_width() const { return m_config.addr_width(); }
+ int alignment() const { return m_config.alignment(); }
endianness_t endianness() const { return m_config.endianness(); }
+ int addrbus_shift() const { return m_config.addrbus_shift(); }
u64 unmap() const { return m_unmap; }
bool is_octal() const { return m_config.m_is_octal; }
offs_t addrmask() const { return m_addrmask; }
- offs_t bytemask() const { return m_bytemask; }
u8 addrchars() const { return m_addrchars; }
offs_t logaddrmask() const { return m_logaddrmask; }
- offs_t logbytemask() const { return m_logbytemask; }
u8 logaddrchars() const { return m_logaddrchars; }
// debug helpers
@@ -262,41 +288,41 @@ public:
// general accessors
virtual void accessors(data_accessors &accessors) const = 0;
- virtual void *get_read_ptr(offs_t byteaddress) = 0;
- virtual void *get_write_ptr(offs_t byteaddress) = 0;
+ virtual void *get_read_ptr(offs_t address) = 0;
+ virtual void *get_write_ptr(offs_t address) = 0;
// read accessors
- virtual u8 read_byte(offs_t byteaddress) = 0;
- virtual u16 read_word(offs_t byteaddress) = 0;
- virtual u16 read_word(offs_t byteaddress, u16 mask) = 0;
- virtual u16 read_word_unaligned(offs_t byteaddress) = 0;
- virtual u16 read_word_unaligned(offs_t byteaddress, u16 mask) = 0;
- virtual u32 read_dword(offs_t byteaddress) = 0;
- virtual u32 read_dword(offs_t byteaddress, u32 mask) = 0;
- virtual u32 read_dword_unaligned(offs_t byteaddress) = 0;
- virtual u32 read_dword_unaligned(offs_t byteaddress, u32 mask) = 0;
- virtual u64 read_qword(offs_t byteaddress) = 0;
- virtual u64 read_qword(offs_t byteaddress, u64 mask) = 0;
- virtual u64 read_qword_unaligned(offs_t byteaddress) = 0;
- virtual u64 read_qword_unaligned(offs_t byteaddress, u64 mask) = 0;
+ virtual u8 read_byte(offs_t address) = 0;
+ virtual u16 read_word(offs_t address) = 0;
+ virtual u16 read_word(offs_t address, u16 mask) = 0;
+ virtual u16 read_word_unaligned(offs_t address) = 0;
+ virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0;
+ virtual u32 read_dword(offs_t address) = 0;
+ virtual u32 read_dword(offs_t address, u32 mask) = 0;
+ virtual u32 read_dword_unaligned(offs_t address) = 0;
+ virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0;
+ virtual u64 read_qword(offs_t address) = 0;
+ virtual u64 read_qword(offs_t address, u64 mask) = 0;
+ virtual u64 read_qword_unaligned(offs_t address) = 0;
+ virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0;
// write accessors
- virtual void write_byte(offs_t byteaddress, u8 data) = 0;
- virtual void write_word(offs_t byteaddress, u16 data) = 0;
- virtual void write_word(offs_t byteaddress, u16 data, u16 mask) = 0;
- virtual void write_word_unaligned(offs_t byteaddress, u16 data) = 0;
- virtual void write_word_unaligned(offs_t byteaddress, u16 data, u16 mask) = 0;
- virtual void write_dword(offs_t byteaddress, u32 data) = 0;
- virtual void write_dword(offs_t byteaddress, u32 data, u32 mask) = 0;
- virtual void write_dword_unaligned(offs_t byteaddress, u32 data) = 0;
- virtual void write_dword_unaligned(offs_t byteaddress, u32 data, u32 mask) = 0;
- virtual void write_qword(offs_t byteaddress, u64 data) = 0;
- virtual void write_qword(offs_t byteaddress, u64 data, u64 mask) = 0;
- virtual void write_qword_unaligned(offs_t byteaddress, u64 data) = 0;
- virtual void write_qword_unaligned(offs_t byteaddress, u64 data, u64 mask) = 0;
+ virtual void write_byte(offs_t address, u8 data) = 0;
+ virtual void write_word(offs_t address, u16 data) = 0;
+ virtual void write_word(offs_t address, u16 data, u16 mask) = 0;
+ virtual void write_word_unaligned(offs_t address, u16 data) = 0;
+ virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0;
+ virtual void write_dword(offs_t address, u32 data) = 0;
+ virtual void write_dword(offs_t address, u32 data, u32 mask) = 0;
+ virtual void write_dword_unaligned(offs_t address, u32 data) = 0;
+ virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0;
+ virtual void write_qword(offs_t address, u64 data) = 0;
+ virtual void write_qword(offs_t address, u64 data, u64 mask) = 0;
+ virtual void write_qword_unaligned(offs_t address, u64 data) = 0;
+ virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0;
// Set address. This will invoke setoffset handlers for the respective entries.
- virtual void set_address(offs_t byteaddress) = 0;
+ virtual void set_address(offs_t address) = 0;
// address-to-byte conversion helpers
offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); }
@@ -386,6 +412,10 @@ public:
void allocate_memory();
void locate_memory();
+ void invalidate_read_caches();
+ void invalidate_read_caches(u16 entry);
+ void invalidate_read_caches(offs_t start, offs_t end);
+
private:
// internal helpers
virtual address_table_read &read() = 0;
@@ -412,15 +442,13 @@ protected:
// private state
const address_space_config &m_config; // configuration of this space
device_t & m_device; // reference to the owning device
- std::unique_ptr<address_map> m_map; // original memory map
+ std::unique_ptr<address_map> m_map; // original memory map
offs_t m_addrmask; // physical address mask
- offs_t m_bytemask; // byte-converted physical address mask
offs_t m_logaddrmask; // logical address mask
- offs_t m_logbytemask; // byte-converted logical address mask
u64 m_unmap; // unmapped value
int m_spacenum; // address space index
bool m_log_unmap; // log unmapped accesses in this space?
- std::unique_ptr<direct_read_data> m_direct; // fast direct-access read info
+ void * m_direct; // fast direct-access read info
const char * m_name; // friendly name of the address space
u8 m_addrchars; // number of characters to use for physical addresses
u8 m_logaddrchars; // number of characters to use for logical addresses
@@ -440,26 +468,26 @@ class memory_block
public:
// construction/destruction
- memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory = nullptr);
+ memory_block(address_space &space, offs_t start, offs_t end, void *memory = nullptr);
~memory_block();
// getters
running_machine &machine() const { return m_machine; }
- offs_t bytestart() const { return m_bytestart; }
- offs_t byteend() const { return m_byteend; }
+ offs_t addrstart() const { return m_addrstart; }
+ offs_t addrend() const { return m_addrend; }
u8 *data() const { return m_data; }
// is the given range contained by this memory block?
- bool contains(address_space &space, offs_t bytestart, offs_t byteend) const
+ bool contains(address_space &space, offs_t addrstart, offs_t addrend) const
{
- return (&space == &m_space && m_bytestart <= bytestart && m_byteend >= byteend);
+ return (&space == &m_space && m_addrstart <= addrstart && m_addrend >= addrend);
}
private:
// internal state
running_machine & m_machine; // need the machine to free our memory
address_space & m_space; // which address space are we associated with?
- offs_t m_bytestart, m_byteend; // byte-normalized start/end for verifying a match
+ offs_t m_addrstart, m_addrend; // start/end for verifying a match
u8 * m_data; // pointer to the data for this block
std::vector<u8> m_allocated; // pointer to the actually allocated block
};
@@ -502,7 +530,7 @@ class memory_bank
public:
// construction/destruction
- memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag = nullptr);
+ memory_bank(address_space &space, int index, offs_t start, offs_t end, const char *tag = nullptr);
~memory_bank();
// getters
@@ -510,16 +538,16 @@ public:
int index() const { return m_index; }
int entry() const { return m_curentry; }
bool anonymous() const { return m_anonymous; }
- offs_t bytestart() const { return m_bytestart; }
+ offs_t addrstart() const { return m_addrstart; }
void *base() const { return *m_baseptr; }
const char *tag() const { return m_tag.c_str(); }
const char *name() const { return m_name.c_str(); }
// compare a range against our range
- bool matches_exactly(offs_t bytestart, offs_t byteend) const { return (m_bytestart == bytestart && m_byteend == byteend); }
- bool fully_covers(offs_t bytestart, offs_t byteend) const { return (m_bytestart <= bytestart && m_byteend >= byteend); }
- bool is_covered_by(offs_t bytestart, offs_t byteend) const { return (m_bytestart >= bytestart && m_byteend <= byteend); }
- bool straddles(offs_t bytestart, offs_t byteend) const { return (m_bytestart < byteend && m_byteend > bytestart); }
+ bool matches_exactly(offs_t addrstart, offs_t addrend) const { return (m_addrstart == addrstart && m_addrend == addrend); }
+ bool fully_covers(offs_t addrstart, offs_t addrend) const { return (m_addrstart <= addrstart && m_addrend >= addrend); }
+ bool is_covered_by(offs_t addrstart, offs_t addrend) const { return (m_addrstart >= addrstart && m_addrend <= addrend); }
+ bool straddles(offs_t addrstart, offs_t addrend) const { return (m_addrstart < addrend && m_addrend > addrstart); }
// track and verify address space references to this bank
bool references_space(const address_space &space, read_or_write readorwrite) const;
@@ -543,8 +571,8 @@ private:
u8 ** m_baseptr; // pointer to our base pointer in the global array
u16 m_index; // array index for this handler
bool m_anonymous; // are we anonymous or explicit?
- offs_t m_bytestart; // byte-adjusted start offset
- offs_t m_byteend; // byte-adjusted end offset
+ offs_t m_addrstart; // start offset
+ offs_t m_addrend; // end offset
int m_curentry; // current entry
std::vector<bank_entry> m_entry; // array of entries (dynamically allocated)
std::string m_name; // friendly name for this bank
@@ -791,10 +819,16 @@ private:
// backing that address
//-------------------------------------------------
-inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline void *direct_read_data<addr_shift>::read_ptr(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return &m_ptr[(byteaddress ^ directxor) & m_bytemask];
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return &m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)];
+ else if(addr_shift == 0)
+ return &m_ptr[(address ^ directxor) & m_addrmask];
+ else
+ return &m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)];
+ }
return nullptr;
}
@@ -804,11 +838,17 @@ inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u8 direct_read_data<addr_shift>::read_byte(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return m_ptr[(byteaddress ^ directxor) & m_bytemask];
- return m_space.read_byte(byteaddress);
+ if(addr_shift <= -1)
+ fatalerror("Can't direct_read_data::read_byte on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift == 0)
+ return m_ptr[(address ^ directxor) & m_addrmask];
+ else
+ return m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)];
+ }
+ return m_space.read_byte(address);
}
@@ -817,11 +857,19 @@ inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u16 direct_read_data<addr_shift>::read_word(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u16 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_word(byteaddress);
+ if(addr_shift <= -2)
+ fatalerror("Can't direct_read_data::read_word on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u16 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_word(address);
}
@@ -830,11 +878,19 @@ inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u32 direct_read_data<addr_shift>::read_dword(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u32 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_dword(byteaddress);
+ if(addr_shift <= -3)
+ fatalerror("Can't direct_read_data::read_dword on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u32 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_dword(address);
}
@@ -843,11 +899,17 @@ inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u64 direct_read_data::read_qword(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u64 direct_read_data<addr_shift>::read_qword(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u64 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_qword(byteaddress);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u64 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_qword(address);
}
#endif /* MAME_EMU_EMUMEM_H */
diff --git a/src/emu/inpttype.h b/src/emu/inpttype.h
index 247eced5037..b58ca37bec6 100644
--- a/src/emu/inpttype.h
+++ b/src/emu/inpttype.h
@@ -576,16 +576,16 @@ inline void construct_core_types_pedal(simple_list<input_type_entry> &typelist)
inline void construct_core_types_pedal2(simple_list<input_type_entry> &typelist)
{
- INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, "P1 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) )
- INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, "P2 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) )
- INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, "P3 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) )
- INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, "P4 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) )
- INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, "P5 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) )
- INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, "P6 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) )
- INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, "P7 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) )
- INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, "P8 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) )
- INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, "P9 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) )
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, "P10 Pedal 2", input_seq(JOYCODE_Z_POS_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) )
+ INPUT_PORT_ANALOG_TYPE( 1, PLAYER1, PEDAL2, "P1 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)), input_seq(), input_seq(KEYCODE_LALT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(0)) )
+ INPUT_PORT_ANALOG_TYPE( 2, PLAYER2, PEDAL2, "P2 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(1)), input_seq(), input_seq(KEYCODE_S, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(1)) )
+ INPUT_PORT_ANALOG_TYPE( 3, PLAYER3, PEDAL2, "P3 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(2)), input_seq(), input_seq(KEYCODE_RSHIFT, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(2)) )
+ INPUT_PORT_ANALOG_TYPE( 4, PLAYER4, PEDAL2, "P4 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(3)), input_seq(), input_seq(KEYCODE_DEL_PAD, input_seq::or_code, JOYCODE_BUTTON2_INDEXED(3)) )
+ INPUT_PORT_ANALOG_TYPE( 5, PLAYER5, PEDAL2, "P5 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(4)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(4)) )
+ INPUT_PORT_ANALOG_TYPE( 6, PLAYER6, PEDAL2, "P6 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(5)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(5)) )
+ INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PEDAL2, "P7 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(6)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(6)) )
+ INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PEDAL2, "P8 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(7)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(7)) )
+ INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PEDAL2, "P9 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(8)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(8)) )
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PEDAL2, "P10 Pedal 2", input_seq(JOYCODE_W_NEG_ABSOLUTE_INDEXED(9)), input_seq(), input_seq(JOYCODE_BUTTON2_INDEXED(9)) )
}
inline void construct_core_types_pedal3(simple_list<input_type_entry> &typelist)
@@ -627,7 +627,7 @@ inline void construct_core_types_paddle_v(simple_list<input_type_entry> &typelis
INPUT_PORT_ANALOG_TYPE( 7, PLAYER7, PADDLE_V, "Paddle V 7", input_seq(JOYCODE_Y_INDEXED(6), input_seq::or_code, MOUSECODE_Y_INDEXED(6)), input_seq(), input_seq() )
INPUT_PORT_ANALOG_TYPE( 8, PLAYER8, PADDLE_V, "Paddle V 8", input_seq(JOYCODE_Y_INDEXED(7), input_seq::or_code, MOUSECODE_Y_INDEXED(7)), input_seq(), input_seq() )
INPUT_PORT_ANALOG_TYPE( 9, PLAYER9, PADDLE_V, "Paddle V 9", input_seq(JOYCODE_Y_INDEXED(8), input_seq::or_code, MOUSECODE_Y_INDEXED(8)), input_seq(), input_seq() )
- INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, "Paddle V 10", input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() )
+ INPUT_PORT_ANALOG_TYPE( 10, PLAYER10, PADDLE_V, "Paddle V 10", input_seq(JOYCODE_Y_INDEXED(9), input_seq::or_code, MOUSECODE_Y_INDEXED(9)), input_seq(), input_seq() )
}
inline void construct_core_types_positional(simple_list<input_type_entry> &typelist)
diff --git a/src/emu/input.h b/src/emu/input.h
index f3e061b37bd..47c9a3276d9 100644
--- a/src/emu/input.h
+++ b/src/emu/input.h
@@ -830,12 +830,14 @@ private:
#define JOYCODE_Z_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS)
#define JOYCODE_U_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS)
#define JOYCODE_V_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS)
+#define JOYCODE_W_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS)
#define JOYCODE_X JOYCODE_X_INDEXED(0)
#define JOYCODE_Y JOYCODE_Y_INDEXED(0)
#define JOYCODE_Z JOYCODE_Z_INDEXED(0)
#define JOYCODE_U JOYCODE_U_INDEXED(0)
#define JOYCODE_V JOYCODE_V_INDEXED(0)
+#define JOYCODE_W JOYCODE_W_INDEXED(0)
// joystick axes as absolute half-axes
#define JOYCODE_X_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS)
@@ -848,6 +850,8 @@ private:
#define JOYCODE_U_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS)
#define JOYCODE_V_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS)
#define JOYCODE_V_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS)
+#define JOYCODE_W_POS_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS)
+#define JOYCODE_W_NEG_ABSOLUTE_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS)
#define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0)
#define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0)
@@ -859,6 +863,8 @@ private:
#define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0)
#define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0)
#define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)
// joystick axes as switches; X/Y are specially handled for left/right/up/down mapping
#define JOYCODE_X_LEFT_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS)
@@ -871,6 +877,8 @@ private:
#define JOYCODE_U_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS)
#define JOYCODE_V_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS)
#define JOYCODE_V_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS)
+#define JOYCODE_W_POS_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS)
+#define JOYCODE_W_NEG_SWITCH_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS)
#define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0)
#define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0)
@@ -882,6 +890,8 @@ private:
#define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0)
#define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0)
#define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0)
+#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0)
// joystick buttons
#define JOYCODE_BUTTON1_INDEXED(n) input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1)
diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp
index bf241f30b57..d76804a9573 100644
--- a/src/emu/ioport.cpp
+++ b/src/emu/ioport.cpp
@@ -153,7 +153,7 @@ inline s64 recip_scale(s64 scale)
inline s32 apply_scale(s32 value, s64 scale)
{
- return (s64(value) * scale) >> 24;
+ return (s64(value) * scale) / (1 << 24);
}
@@ -616,7 +616,9 @@ ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value def
// reset sequences and chars
for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
m_seq[seqtype].set_default();
- std::fill(std::begin(m_chars), std::end(m_chars), char32_t(0));
+
+ for (int i = 0; i < ARRAY_LENGTH(m_chars); i++)
+ std::fill(std::begin(m_chars[i]), std::end(m_chars[i]), char32_t(0));
// for DIP switches and configs, look for a default value from the owner
if (type == IPT_DIPSWITCH || type == IPT_CONFIG)
@@ -755,16 +757,20 @@ ioport_type_class ioport_field::type_class() const
//-------------------------------------------------
-// keyboard_code - accesses a particular keyboard
-// code
+// keyboard_codes - accesses a particular keyboard
+// code list
//-------------------------------------------------
-char32_t ioport_field::keyboard_code(int which) const
+std::vector<char32_t> ioport_field::keyboard_codes(int which) const
{
if (which >= ARRAY_LENGTH(m_chars))
throw emu_fatalerror("Tried to access keyboard_code with out-of-range index %d\n", which);
- return m_chars[which];
+ std::vector<char32_t> result;
+ for (int i = 0; i < ARRAY_LENGTH(m_chars[which]) && m_chars[which] != 0; i++)
+ result.push_back(m_chars[which][i]);
+
+ return result;
}
@@ -774,7 +780,8 @@ char32_t ioport_field::keyboard_code(int which) const
std::string ioport_field::key_name(int which) const
{
- char32_t ch = keyboard_code(which);
+ std::vector<char32_t> codes = keyboard_codes(which);
+ char32_t ch = codes.empty() ? 0 : codes[0];
// attempt to get the string from the character info table
switch (ch)
@@ -1373,8 +1380,8 @@ ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog)
// loop through each character on the field
for (int which = 0; which < 4; which++)
{
- char32_t const ch = field.keyboard_code(which);
- if (ch == 0)
+ std::vector<char32_t> const codes = field.keyboard_codes(which);
+ if (codes.empty())
break;
name.append(string_format("%-*s ", std::max(SPACE_COUNT - 1, 0), field.key_name(which)));
}
@@ -3059,16 +3066,27 @@ ioport_configurer& ioport_configurer::field_alloc(ioport_type type, ioport_value
// field_add_char - add a character to a field
//-------------------------------------------------
-ioport_configurer& ioport_configurer::field_add_char(char32_t ch)
+ioport_configurer& ioport_configurer::field_add_char(std::initializer_list<char32_t> charlist)
{
for (int index = 0; index < ARRAY_LENGTH(m_curfield->m_chars); index++)
- if (m_curfield->m_chars[index] == 0)
+ if (m_curfield->m_chars[index][0] == 0)
{
- m_curfield->m_chars[index] = ch;
+ const size_t char_count = ARRAY_LENGTH(m_curfield->m_chars[index]);
+ assert(charlist.size() > 0 && charlist.size() <= char_count);
+
+ for (size_t i = 0; i < char_count; i++)
+ m_curfield->m_chars[index][i] = i < charlist.size() ? *(charlist.begin() + i) : 0;
return *this;
}
- throw emu_fatalerror("PORT_CHAR(%d) could not be added - maximum amount exceeded\n", ch);
+ std::ostringstream s;
+ bool is_first = true;
+ for (char32_t ch : charlist)
+ {
+ util::stream_format(s, "%s%d", is_first ? "" : ",", (int)ch);
+ is_first = false;
+ }
+ throw emu_fatalerror("PORT_CHAR(%s) could not be added - maximum amount exceeded\n", s.str().c_str());
}
@@ -3328,10 +3346,6 @@ analog_field::analog_field(ioport_field &field)
// single axis that increases from default
m_scalepos = compute_scale(m_adjmax - m_adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
- // move from default
- if (m_adjdefvalue == m_adjmax)
- m_scalepos = -m_scalepos;
-
// make the scaling the same for easier coding when we need to scale
m_scaleneg = m_scalepos;
@@ -3370,7 +3384,13 @@ analog_field::analog_field(ioport_field &field)
// relative controls reverse from 1 past their max range
if (m_wraps)
- m_reverse_val -= INPUT_RELATIVE_PER_PIXEL;
+ {
+ // FIXME: positional needs -1, using INPUT_RELATIVE_PER_PIXEL skips a position (and reads outside the table array)
+ if(field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V)
+ m_reverse_val --;
+ else
+ m_reverse_val -= INPUT_RELATIVE_PER_PIXEL;
+ }
}
}
@@ -3392,25 +3412,11 @@ inline s32 analog_field::apply_min_max(s32 value) const
s32 adjmin = apply_inverse_sensitivity(m_minimum);
s32 adjmax = apply_inverse_sensitivity(m_maximum);
- // for absolute devices, clamp to the bounds absolutely
- if (!m_wraps)
- {
- if (value > adjmax)
- value = adjmax;
- else if (value < adjmin)
- value = adjmin;
- }
-
- // for relative devices, wrap around when we go past the edge
- else
- {
- s32 range = adjmax - adjmin;
- // rolls to other end when 1 position past end.
- value = (value - adjmin) % range;
- if (value < 0)
- value += range;
- value += adjmin;
- }
+ // clamp to the bounds absolutely
+ if (value > adjmax)
+ value = adjmax;
+ else if (value < adjmin)
+ value = adjmin;
return value;
}
@@ -3423,7 +3429,7 @@ inline s32 analog_field::apply_min_max(s32 value) const
inline s32 analog_field::apply_sensitivity(s32 value) const
{
- return s32((s64(value) * m_sensitivity) / 100.0 + 0.5);
+ return lround((s64(value) * m_sensitivity) / 100.0);
}
@@ -3446,7 +3452,8 @@ inline s32 analog_field::apply_inverse_sensitivity(s32 value) const
s32 analog_field::apply_settings(s32 value) const
{
// apply the min/max and then the sensitivity
- value = apply_min_max(value);
+ if (!m_wraps)
+ value = apply_min_max(value);
value = apply_sensitivity(value);
// apply reversal if needed
@@ -3464,6 +3471,18 @@ s32 analog_field::apply_settings(s32 value) const
value = apply_scale(value, m_scaleneg);
value += m_adjdefvalue;
+ // for relative devices, wrap around when we go past the edge
+ // (this is done last to prevent rounding errors)
+ if (m_wraps)
+ {
+ s32 range = m_adjmax - m_adjmin;
+ // rolls to other end when 1 position past end.
+ value = (value - m_adjmin) % range;
+ if (value < 0)
+ value += range;
+ value += m_adjmin;
+ }
+
return value;
}
@@ -3475,8 +3494,12 @@ s32 analog_field::apply_settings(s32 value) const
void analog_field::frame_update(running_machine &machine)
{
- // clamp the previous value to the min/max range and remember it
- m_previous = m_accum = apply_min_max(m_accum);
+ // clamp the previous value to the min/max range
+ if (!m_wraps)
+ m_accum = apply_min_max(m_accum);
+
+ // remember the previous value in case we need to interpolate
+ m_previous = m_accum;
// get the new raw analog value and its type
input_item_class itemclass;
diff --git a/src/emu/ioport.h b/src/emu/ioport.h
index 0e6932e683e..722c028e4dc 100644
--- a/src/emu/ioport.h
+++ b/src/emu/ioport.h
@@ -1063,7 +1063,7 @@ public:
const ioport_value *remap_table() const { return m_remap_table; }
u8 way() const { return m_way; }
- char32_t keyboard_code(int which) const;
+ std::vector<char32_t> keyboard_codes(int which) const;
std::string key_name(int which) const;
ioport_field_live &live() const { assert(m_live != nullptr); return *m_live; }
@@ -1149,7 +1149,7 @@ private:
// data relevant to other specific types
u8 m_way; // digital joystick 2/4/8-way descriptions
- char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)]; // unicode key data
+ char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)][2]; // unicode key data
};
@@ -1501,7 +1501,7 @@ public:
// field helpers
ioport_configurer& field_alloc(ioport_type type, ioport_value defval, ioport_value mask, const char *name = nullptr);
- ioport_configurer& field_add_char(char32_t ch);
+ ioport_configurer& field_add_char(std::initializer_list<char32_t> charlist);
ioport_configurer& field_add_code(input_seq_type which, input_code code);
ioport_configurer& field_set_way(int way) { m_curfield->m_way = way; return *this; }
ioport_configurer& field_set_rotated() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_ROTATED; return *this; }
@@ -1746,8 +1746,8 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s
configurer.setting_alloc((_default), (_name));
// keyboard chars
-#define PORT_CHAR(_ch) \
- configurer.field_add_char(_ch);
+#define PORT_CHAR(...) \
+ configurer.field_add_char({ __VA_ARGS__ });
// name of table
diff --git a/src/emu/layout/README.md b/src/emu/layout/README.md
index ce23c18751a..76dd0e3435e 100644
--- a/src/emu/layout/README.md
+++ b/src/emu/layout/README.md
@@ -1,6 +1,6 @@
# **Layout** #
-Layouts files are definiton files to describe look and fell of emulated machines, and are product
-of many different contributors.
+Layout files are definition files to describe the look and feel of emulated machines, and are
+the product of many different contributors.
Licensed under [CC0 1.0 Universal (CC0 1.0)](https://creativecommons.org/publicdomain/zero/1.0/)
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index 4af765831d6..fa6375ef937 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -974,6 +974,10 @@ void running_machine::logfile_callback(const char *buffer)
void running_machine::start_all_devices()
{
+ // resolve objects first to avoid messy start order dependencies
+ for (device_t &device : device_iterator(root_device()))
+ device.resolve_objects();
+
m_dummy_space.start();
// iterate through the devices
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index 9defa2f0fa1..2c579b6b894 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -580,11 +580,14 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
if (field.type() == IPT_KEYBOARD)
{
- char32_t const code = field.keyboard_code(0);
- if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END))
+ std::vector<char32_t> const codes = field.keyboard_codes(0);
+ for (char32_t code : codes)
{
- mask |= 1U << (code - UCHAR_SHIFT_BEGIN);
- shift[code - UCHAR_SHIFT_BEGIN] = &field;
+ if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END))
+ {
+ mask |= 1U << (code - UCHAR_SHIFT_BEGIN);
+ shift[code - UCHAR_SHIFT_BEGIN] = &field;
+ }
}
}
}
@@ -603,35 +606,38 @@ void natural_keyboard::build_codes(ioport_manager &manager)
if (!(curshift & ~mask))
{
// fetch the code, ignoring 0 and shiters
- char32_t const code = field.keyboard_code(curshift);
- if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
+ std::vector<char32_t> const codes = field.keyboard_codes(curshift);
+ for (char32_t code : codes)
{
- // prefer lowest shift state
- keycode_map::iterator const found(m_keycode_map.find(code));
- if ((m_keycode_map.end() == found) || (found->second.shift > curshift))
+ if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
{
- keycode_map_entry newcode;
- std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
- newcode.shift = curshift;
-
- unsigned fieldnum = 0;
- for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
- {
- if (BIT(bits, 0))
- newcode.field[fieldnum++] = shift[i];
- }
-
- assert(fieldnum < ARRAY_LENGTH(newcode.field));
- newcode.field[fieldnum] = &field;
- if (m_keycode_map.end() == found)
- m_keycode_map.emplace(code, newcode);
- else
- found->second = newcode;
-
- if (LOG_NATURAL_KEYBOARD)
+ // prefer lowest shift state
+ keycode_map::iterator const found(m_keycode_map.find(code));
+ if ((m_keycode_map.end() == found) || (found->second.shift > curshift))
{
- machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
+ keycode_map_entry newcode;
+ std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
+ newcode.shift = curshift;
+
+ unsigned fieldnum = 0;
+ for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
+ {
+ if (BIT(bits, 0))
+ newcode.field[fieldnum++] = shift[i];
+ }
+
+ assert(fieldnum < ARRAY_LENGTH(newcode.field));
+ newcode.field[fieldnum] = &field;
+ if (m_keycode_map.end() == found)
+ m_keycode_map.emplace(code, newcode);
+ else
+ found->second = newcode;
+
+ if (LOG_NATURAL_KEYBOARD)
+ {
+ machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
code, unicode_to_string(code), (void *)&port, field.name());
+ }
}
}
}
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index 2d5c177f9b9..52e5cefe37c 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -804,6 +804,39 @@ void screen_device::device_validity_check(validity_checker &valid) const
//-------------------------------------------------
+// device_resolve_objects - resolve objects that
+// may be needed for other devices to set
+// initial conditions at start time
+//-------------------------------------------------
+
+void screen_device::device_resolve_objects()
+{
+ // bind our handlers
+ m_screen_update_ind16.bind_relative_to(*owner());
+ m_screen_update_rgb32.bind_relative_to(*owner());
+ m_screen_vblank.resolve_safe();
+
+ // find the specified palette
+ if (m_palette_tag != nullptr && m_palette == nullptr)
+ {
+ // find our palette as a sibling device
+ device_t *palette = owner()->subdevice(m_palette_tag);
+ if (palette == nullptr)
+ fatalerror("Screen '%s' specifies nonexistent device '%s' as palette\n",
+ tag(),
+ m_palette_tag);
+ if (!palette->interface(m_palette))
+ fatalerror("Screen '%s' specifies device '%s' as palette, but it has no palette interface\n",
+ tag(),
+ m_palette_tag);
+
+ // assign our format to the palette before it starts
+ m_palette->m_format = format();
+ }
+}
+
+
+//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -826,13 +859,7 @@ void screen_device::device_start()
}
}
- // bind our handlers
- m_screen_update_ind16.bind_relative_to(*owner());
- m_screen_update_rgb32.bind_relative_to(*owner());
- m_screen_vblank.resolve_safe();
-
// if we have a palette and it's not started, wait for it
- resolve_palette();
if (m_palette != nullptr && !m_palette->device().started())
throw device_missing_dependencies();
@@ -1482,28 +1509,6 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap)
//-------------------------------------------------
-// resolve_palette - find the specified palette
-//-------------------------------------------------
-
-void screen_device::resolve_palette()
-{
- if (m_palette_tag != nullptr && m_palette == nullptr)
- {
- // find our palette as a sibling device
- device_t *palette = owner()->subdevice(m_palette_tag);
- if (palette == nullptr)
- fatalerror("Screen '%s' specifies nonexistent device '%s' as palette\n",
- tag(),
- m_palette_tag);
- if (!palette->interface(m_palette))
- fatalerror("Screen '%s' specifies device '%s' as palette, but it has no palette interface\n",
- tag(),
- m_palette_tag);
- }
-}
-
-
-//-------------------------------------------------
// vblank_begin - call any external callbacks to
// signal the VBLANK period has begun
//-------------------------------------------------
diff --git a/src/emu/screen.h b/src/emu/screen.h
index 3da146bac1d..c022c573316 100644
--- a/src/emu/screen.h
+++ b/src/emu/screen.h
@@ -239,7 +239,6 @@ public:
// additional helpers
void register_vblank_callback(vblank_state_delegate vblank_callback);
void register_screen_bitmap(bitmap_t &bitmap);
- void resolve_palette();
// internal to the video system
bool update_quads();
@@ -263,6 +262,7 @@ private:
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
+ virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp
index b7b6f0d6f90..dd70af41506 100644
--- a/src/emu/validity.cpp
+++ b/src/emu/validity.cpp
@@ -770,6 +770,38 @@ void validity_checker::validate_rgb()
rgb.mul_imm_rgba(actual_a, actual_r, actual_g, actual_b);
check_expected("rgbaint_t::mul_imm_rgba");
+ // test select alpha element multiplication
+ expected_a *= actual_a = random_i32();
+ expected_r *= actual_a;
+ expected_g *= actual_a;
+ expected_b *= actual_a;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_alpha32());
+ check_expected("rgbaint_t::mul(select_alpha32)");
+
+ // test select red element multiplication
+ expected_a *= actual_r = random_i32();
+ expected_r *= actual_r;
+ expected_g *= actual_r;
+ expected_b *= actual_r;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_red32());
+ check_expected("rgbaint_t::mul(select_red32)");
+
+ // test select green element multiplication
+ expected_a *= actual_g = random_i32();
+ expected_r *= actual_g;
+ expected_g *= actual_g;
+ expected_b *= actual_g;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_green32());
+ check_expected("rgbaint_t::mul(select_green32)");
+
+ // test select blue element multiplication
+ expected_a *= actual_b = random_i32();
+ expected_r *= actual_b;
+ expected_g *= actual_b;
+ expected_b *= actual_b;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_blue32());
+ check_expected("rgbaint_t::mul(select_blue32)");
+
// test RGB and not
expected_a &= ~(actual_a = random_i32());
expected_r &= ~(actual_r = random_i32());
@@ -1844,13 +1876,16 @@ void validity_checker::validate_inputs()
// verify natural keyboard codes
for (int which = 0; which < 1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1); which++)
{
- char32_t code = field.keyboard_code(which);
- if (code && !uchar_isvalid(code))
+ std::vector<char32_t> codes = field.keyboard_codes(which);
+ for (char32_t code : codes)
{
- osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n",
- name,
- (unsigned)code,
- (int)code);
+ if (!uchar_isvalid(code))
+ {
+ osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n",
+ name,
+ (unsigned)code,
+ (int)code);
+ }
}
}
}
diff --git a/src/emu/video/rgbgen.cpp b/src/emu/video/rgbgen.cpp
index 09b27090887..1882493b698 100644
--- a/src/emu/video/rgbgen.cpp
+++ b/src/emu/video/rgbgen.cpp
@@ -77,26 +77,6 @@ void rgbaint_t::scale_and_clamp(const rgbaint_t& scale)
}
-void rgbaint_t::scale_imm_add_and_clamp(s32 scale, const rgbaint_t& other)
-{
- m_a = (m_a * scale) >> 8;
- m_r = (m_r * scale) >> 8;
- m_g = (m_g * scale) >> 8;
- m_b = (m_b * scale) >> 8;
- m_a |= (m_a & 0x00800000) ? 0xff000000 : 0;
- m_r |= (m_r & 0x00800000) ? 0xff000000 : 0;
- m_g |= (m_g & 0x00800000) ? 0xff000000 : 0;
- m_b |= (m_b & 0x00800000) ? 0xff000000 : 0;
- m_a += other.m_a;
- m_r += other.m_r;
- m_g += other.m_g;
- m_b += other.m_b;
- if (u32(m_a) > 255) { m_a = (m_a < 0) ? 0 : 255; }
- if (u32(m_r) > 255) { m_r = (m_r < 0) ? 0 : 255; }
- if (u32(m_g) > 255) { m_g = (m_g < 0) ? 0 : 255; }
- if (u32(m_b) > 255) { m_b = (m_b < 0) ? 0 : 255; }
-}
-
void rgbaint_t::scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
m_a = (m_a * scale.m_a) >> 8;
diff --git a/src/emu/video/rgbgen.h b/src/emu/video/rgbgen.h
index 197769946a8..e460208d9fd 100644
--- a/src/emu/video/rgbgen.h
+++ b/src/emu/video/rgbgen.h
@@ -37,6 +37,12 @@ public:
m_b = b;
}
void set(const rgb_t& rgba) { set(rgba.a(), rgba.r(), rgba.g(), rgba.b()); }
+ // This function sets all elements to the same val
+ void set_all(const s32& val) { set(val, val, val, val); }
+ // This function zeros all elements
+ void zero() { set_all(0); }
+ // This function zeros only the alpha element
+ void zero_alpha() { m_a = 0; }
rgb_t to_rgba() const { return rgb_t(get_a(), get_r(), get_g(), get_b()); }
@@ -49,6 +55,7 @@ public:
return rgb_t(a, r, g, b);
}
+ void set_a16(const s32 value) { m_a = value; }
void set_a(const s32 value) { m_a = value; }
void set_r(const s32 value) { m_r = value; }
void set_g(const s32 value) { m_g = value; }
@@ -64,6 +71,12 @@ public:
s32 get_g32() const { return m_g; }
s32 get_b32() const { return m_b; }
+ // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
+ rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); }
+ rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); }
+ rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); }
+ rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); }
+
inline void add(const rgbaint_t& color)
{
add_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b);
@@ -304,7 +317,6 @@ public:
void scale_imm_and_clamp(const s32 scale);
void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2);
void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other);
- void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other);
void cmpeq(const rgbaint_t& value) { cmpeq_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); }
void cmpgt(const rgbaint_t& value) { cmpgt_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); }
@@ -338,6 +350,11 @@ public:
m_b = (m_b < b) ? 0xffffffff : 0;
}
+ void merge_alpha16(const rgbaint_t& alpha)
+ {
+ m_a = alpha.m_a;
+ }
+
void merge_alpha(const rgbaint_t& alpha)
{
m_a = alpha.m_a;
diff --git a/src/emu/video/rgbsse.h b/src/emu/video/rgbsse.h
index 68e57bca7fd..0b1a13c0beb 100644
--- a/src/emu/video/rgbsse.h
+++ b/src/emu/video/rgbsse.h
@@ -41,6 +41,12 @@ public:
void set(const u32& rgba) { m_value = _mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(rgba), _mm_setzero_si128()), _mm_setzero_si128()); }
void set(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_set_epi32(a, r, g, b); }
void set(const rgb_t& rgb) { set((const u32&) rgb); }
+ // This function sets all elements to the same val
+ void set_all(const s32& val) { m_value = _mm_set1_epi32(val); }
+ // This function zeros all elements
+ void zero() { m_value = _mm_xor_si128(m_value, m_value); }
+ // This function zeros only the alpha element
+ void zero_alpha() { m_value = _mm_and_si128(m_value, alpha_mask()); }
inline rgb_t to_rgba() const
{
@@ -52,6 +58,7 @@ public:
return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128()));
}
+ void set_a16(const s32 value) { m_value = _mm_insert_epi16(m_value, value, 6); }
#ifdef __SSE4_1__
void set_a(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 3); }
void set_r(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 2); }
@@ -67,7 +74,7 @@ public:
u8 get_a() const { return u8(unsigned(_mm_extract_epi16(m_value, 6))); }
u8 get_r() const { return u8(unsigned(_mm_extract_epi16(m_value, 4))); }
u8 get_g() const { return u8(unsigned(_mm_extract_epi16(m_value, 2))); }
- u8 get_b() const { return u8(unsigned(_mm_extract_epi16(m_value, 0))); }
+ u8 get_b() const { return u8(unsigned(_mm_cvtsi128_si32(m_value))); }
#ifdef __SSE4_1__
s32 get_a32() const { return _mm_extract_epi32(m_value, 3); }
@@ -75,12 +82,18 @@ public:
s32 get_g32() const { return _mm_extract_epi32(m_value, 1); }
s32 get_b32() const { return _mm_extract_epi32(m_value, 0); }
#else
- s32 get_a32() const { return (_mm_extract_epi16(m_value, 7) << 16) | _mm_extract_epi16(m_value, 6); }
- s32 get_r32() const { return (_mm_extract_epi16(m_value, 5) << 16) | _mm_extract_epi16(m_value, 4); }
- s32 get_g32() const { return (_mm_extract_epi16(m_value, 3) << 16) | _mm_extract_epi16(m_value, 2); }
- s32 get_b32() const { return (_mm_extract_epi16(m_value, 1) << 16) | _mm_extract_epi16(m_value, 0); }
+ s32 get_a32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 3)))); }
+ s32 get_r32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 2)))); }
+ s32 get_g32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 1)))); }
+ s32 get_b32() const { return (_mm_cvtsi128_si32(m_value)); }
#endif
+ // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
+ rgbaint_t select_alpha32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(3, 3, 3, 3)); }
+ rgbaint_t select_red32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(2, 2, 2, 2)); }
+ rgbaint_t select_green32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(1, 1, 1, 1)); }
+ rgbaint_t select_blue32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 0)); }
+
inline void add(const rgbaint_t& color2)
{
m_value = _mm_add_epi32(m_value, color2.m_value);
@@ -283,37 +296,74 @@ public:
void scale_and_clamp(const rgbaint_t& scale);
- inline void scale_imm_and_clamp(const s32 scale)
- {
- mul_imm(scale);
- sra_imm(8);
- clamp_to_uint8();
- }
-
- inline void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other)
- {
- mul_imm(scale);
- sra_imm(8);
- add(other);
- clamp_to_uint8();
+ // Leave this here in case Model3 blows up...
+ //inline void scale_imm_and_clamp(const s32 scale)
+ //{
+ // mul_imm(scale);
+ // sra_imm(8);
+ // clamp_to_uint8();
+ //}
+
+ // This version needs values to be 12 bits or less
+ inline void scale_imm_and_clamp(const s16 scale)
+ {
+ // Set mult a 16 bit inputs to scale
+ __m128i immv = _mm_set1_epi16(scale);
+ // Shift up by 4
+ immv = _mm_slli_epi16(immv, 4);
+ // Pack color into mult b 16 bit inputs
+ m_value = _mm_packs_epi32(m_value, _mm_setzero_si128());
+ // Shift up by 4
+ m_value = _mm_slli_epi16(m_value, 4);
+ // Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results
+ m_value = _mm_mulhi_epi16(m_value, immv);
+ // Clamp to u8
+ m_value = _mm_packus_epi16(m_value, _mm_setzero_si128());
+ // Unpack up to s32
+ m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128());
+ m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128());
}
+ // This function needs values to be 12 bits or less
inline void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
- mul(scale);
- sra_imm(8);
+ // Pack scale into mult a 16 bits
+ __m128i tmp1 = _mm_packs_epi32(scale.m_value, _mm_setzero_si128());
+ // Shift up by 4
+ tmp1 = _mm_slli_epi16(tmp1, 4);
+ // Pack color into mult b 16 bit inputs
+ m_value = _mm_packs_epi32(m_value, _mm_setzero_si128());
+ // Shift up by 4
+ m_value = _mm_slli_epi16(m_value, 4);
+ // Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results
+ m_value = _mm_mulhi_epi16(m_value, tmp1);
+ // Clamp to u8
+ m_value = _mm_packus_epi16(m_value, _mm_setzero_si128());
+ // Unpack up to s32
+ m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128());
+ m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128());
add(other);
clamp_to_uint8();
}
+ // This function needs values to be 12 bits or less
inline void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2)
{
- rgbaint_t color2(other);
- color2.mul(scale2);
-
- mul(scale);
- add(color2);
- sra_imm(8);
+ // Pack both scale values into mult a 16 bits
+ __m128i tmp1 = _mm_packs_epi32(scale.m_value, scale2.m_value);
+ // Shift up by 4
+ tmp1 = _mm_slli_epi16(tmp1, 4);
+ // Pack both color values into mult b 16 bit inputs
+ m_value = _mm_packs_epi32(m_value, other.m_value);
+ // Shift up by 4
+ m_value = _mm_slli_epi16(m_value, 4);
+ // Do the 16 bit multiply, top and bottom 64 bits will contain 16 bit truncated results
+ tmp1 = _mm_mulhi_epi16(m_value, tmp1);
+ // Unpack the results
+ m_value = _mm_unpacklo_epi16(tmp1, _mm_setzero_si128());
+ tmp1 = _mm_unpackhi_epi16(tmp1, _mm_setzero_si128());
+ // Add the results
+ m_value = _mm_add_epi32(m_value, tmp1);
clamp_to_uint8();
}
@@ -366,6 +416,11 @@ public:
return *this;
}
+ inline void merge_alpha16(const rgbaint_t& alpha)
+ {
+ m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 6), 6);
+ }
+
inline void merge_alpha(const rgbaint_t& alpha)
{
#ifdef __SSE4_1__
diff --git a/src/emu/video/rgbutil.h b/src/emu/video/rgbutil.h
index e0ccd299a4e..74f425e3417 100644
--- a/src/emu/video/rgbutil.h
+++ b/src/emu/video/rgbutil.h
@@ -14,6 +14,7 @@
// use SSE on 64-bit implementations, where it can be assumed
#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64)
+
#include "rgbsse.h"
#elif defined(__ALTIVEC__)
#include "rgbvmx.h"
diff --git a/src/emu/video/rgbvmx.h b/src/emu/video/rgbvmx.h
index 824e8dd3799..05d26cd9e21 100644
--- a/src/emu/video/rgbvmx.h
+++ b/src/emu/video/rgbvmx.h
@@ -75,6 +75,13 @@ public:
#endif
}
+ // This function sets all elements to the same val
+ void set_all(const s32& val) { set(val, val, val, val); }
+ // This function zeros all elements
+ void zero() { set_all(0); }
+ // This function zeros only the alpha element
+ void zero_alpha() { set_a(0); }
+
inline rgb_t to_rgba() const
{
VECU32 temp = VECU32(vec_packs(m_value, m_value));
@@ -93,6 +100,12 @@ public:
return result;
}
+ void set_a16(const s32 value)
+ {
+ const VECS32 temp = { value, value, value, value };
+ m_value = vec_perm(m_value, temp, alpha_perm);
+ }
+
void set_a(const s32 value)
{
const VECS32 temp = { value, value, value, value };
@@ -205,6 +218,12 @@ public:
return result;
}
+ // These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
+ rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); }
+ rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); }
+ rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); }
+ rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); }
+
inline void add(const rgbaint_t& color2)
{
m_value = vec_add(m_value, color2.m_value);
@@ -460,14 +479,6 @@ public:
void scale_and_clamp(const rgbaint_t& scale);
void scale_imm_and_clamp(const s32 scale);
- void scale_imm_add_and_clamp(const s32 scale, const rgbaint_t& other)
- {
- mul_imm(scale);
- sra_imm(8);
- add(other);
- clamp_to_uint8();
- }
-
void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
mul(scale);
@@ -601,6 +612,11 @@ public:
return *this;
}
+ inline void merge_alpha16(const rgbaint_t& alpha)
+ {
+ m_value = vec_perm(m_value, alpha.m_value, alpha_perm);
+ }
+
inline void merge_alpha(const rgbaint_t& alpha)
{
m_value = vec_perm(m_value, alpha.m_value, alpha_perm);