From ecef74a6103101ead7da9df827abd84afb9c2987 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 19 May 2020 18:29:36 +0200 Subject: [PATCH] emumem: Another slight speedup, implemented on the 680x0 for now [O. Galibert] memory_access_specific is declared and used exactly like memory_access_cache, but does not cache. It does, however, shortcut the virtual call into address_space, so that's one layer of call less. Gives another nice speedup for accesses with bad locality (e.g. anything that's not opcodes), at the expense of having a specifically typed object in the class. Should do well for cpus in general, drivers can keep using the address_space access calls for easier logistics. --- src/devices/cpu/m68000/m68kcpu.cpp | 181 +++++++++++++++-------------- src/emu/emumem.cpp | 26 +---- src/emu/emumem.h | 101 ++++++++++++++++ 3 files changed, 200 insertions(+), 108 deletions(-) diff --git a/src/devices/cpu/m68000/m68kcpu.cpp b/src/devices/cpu/m68000/m68kcpu.cpp index a14d411e279..a95025507ca 100644 --- a/src/devices/cpu/m68000/m68kcpu.cpp +++ b/src/devices/cpu/m68000/m68kcpu.cpp @@ -1306,14 +1306,15 @@ void m68000_base_device::init8(address_space &space, address_space &ospace) m_space = &space; m_ospace = &ospace; auto ocache = ospace.cache<0, 0, ENDIANNESS_BIG>(); + auto pspec = space.specific<0, 0, ENDIANNESS_BIG>(); m_readimm16 = [ocache](offs_t address) -> u16 { return ocache->read_word(address); }; - m_read8 = [this](offs_t address) -> u8 { return m_space->read_byte(address); }; - m_read16 = [this](offs_t address) -> u16 { return m_space->read_word(address); }; - m_read32 = [this](offs_t address) -> u32 { return m_space->read_dword(address); }; - m_write8 = [this](offs_t address, u8 data) { m_space->write_byte(address, data); }; - m_write16 = [this](offs_t address, u16 data) { m_space->write_word(address, data); }; - m_write32 = [this](offs_t address, u32 data) { m_space->write_dword(address, data); }; + m_read8 = [pspec](offs_t address) -> u8 { return pspec->read_byte(address); }; + m_read16 = [pspec](offs_t address) -> u16 { return pspec->read_word(address); }; + m_read32 = [pspec](offs_t address) -> u32 { return pspec->read_dword(address); }; + m_write8 = [pspec](offs_t address, u8 data) { pspec->write_byte(address, data); }; + m_write16 = [pspec](offs_t address, u16 data) { pspec->write_word(address, data); }; + m_write32 = [pspec](offs_t address, u32 data) { pspec->write_dword(address, data); }; } /**************************************************************************** @@ -1325,14 +1326,15 @@ void m68000_base_device::init16(address_space &space, address_space &ospace) m_space = &space; m_ospace = &ospace; auto ocache = ospace.cache<1, 0, ENDIANNESS_BIG>(); + auto pspec = space.specific<1, 0, ENDIANNESS_BIG>(); m_readimm16 = [ocache](offs_t address) -> u16 { return ocache->read_word(address); }; - m_read8 = [this](offs_t address) -> u8 { return m_space->read_byte(address); }; - m_read16 = [this](offs_t address) -> u16 { return m_space->read_word(address); }; - m_read32 = [this](offs_t address) -> u32 { return m_space->read_dword(address); }; - m_write8 = [this](offs_t address, u8 data) { m_space->write_word(address & ~1, data | (data << 8), address & 1 ? 0x00ff : 0xff00); }; - m_write16 = [this](offs_t address, u16 data) { m_space->write_word(address, data); }; - m_write32 = [this](offs_t address, u32 data) { m_space->write_dword(address, data); }; + m_read8 = [pspec](offs_t address) -> u8 { return pspec->read_byte(address); }; + m_read16 = [pspec](offs_t address) -> u16 { return pspec->read_word(address); }; + m_read32 = [pspec](offs_t address) -> u32 { return pspec->read_dword(address); }; + m_write8 = [pspec](offs_t address, u8 data) { pspec->write_word(address & ~1, data | (data << 8), address & 1 ? 0x00ff : 0xff00); }; + m_write16 = [pspec](offs_t address, u16 data) { pspec->write_word(address, data); }; + m_write32 = [pspec](offs_t address, u32 data) { pspec->write_dword(address, data); }; } /**************************************************************************** @@ -1349,53 +1351,54 @@ void m68000_base_device::init32(address_space &space, address_space &ospace) m_space = &space; m_ospace = &ospace; auto ocache = ospace.cache<2, 0, ENDIANNESS_BIG>(); + auto pspec = space.specific<2, 0, ENDIANNESS_BIG>(); m_readimm16 = [ocache](offs_t address) -> u16 { return ocache->read_word(address); }; - m_read8 = [this](offs_t address) -> u8 { return m_space->read_byte(address); }; - m_read16 = [this](offs_t address) -> u16 { return m_space->read_word_unaligned(address); }; - m_read32 = [this](offs_t address) -> u32 { return m_space->read_dword_unaligned(address); }; - m_write8 = [this](offs_t address, u8 data) { - m_space->write_dword(address & 0xfffffffcU, dword_from_byte(data), 0xff000000U >> 8 * (address & 3)); + m_read8 = [pspec](offs_t address) -> u8 { return pspec->read_byte(address); }; + m_read16 = [pspec](offs_t address) -> u16 { return pspec->read_word_unaligned(address); }; + m_read32 = [pspec](offs_t address) -> u32 { return pspec->read_dword_unaligned(address); }; + m_write8 = [pspec](offs_t address, u8 data) { + pspec->write_dword(address & 0xfffffffcU, dword_from_byte(data), 0xff000000U >> 8 * (address & 3)); }; - m_write16 = [this](offs_t address, u16 data) { + m_write16 = [pspec](offs_t address, u16 data) { switch (address & 3) { case 0: - m_space->write_dword(address, dword_from_word(data), 0xffff0000U); + pspec->write_dword(address, dword_from_word(data), 0xffff0000U); break; case 1: - m_space->write_dword(address - 1, dword_from_unaligned_word(data), 0x00ffff00); + pspec->write_dword(address - 1, dword_from_unaligned_word(data), 0x00ffff00); break; case 2: - m_space->write_dword(address - 2, dword_from_word(data), 0x0000ffff); + pspec->write_dword(address - 2, dword_from_word(data), 0x0000ffff); break; case 3: - m_space->write_dword(address - 3, dword_from_unaligned_word(data), 0x000000ff); - m_space->write_dword(address + 1, dword_from_byte(data & 0x00ff), 0xff000000U); + pspec->write_dword(address - 3, dword_from_unaligned_word(data), 0x000000ff); + pspec->write_dword(address + 1, dword_from_byte(data & 0x00ff), 0xff000000U); break; } }; - m_write32 = [this](offs_t address, u32 data) { + m_write32 = [pspec](offs_t address, u32 data) { switch (address & 3) { case 0: - m_space->write_dword(address, data, 0xffffffffU); + pspec->write_dword(address, data, 0xffffffffU); break; case 1: - m_space->write_dword(address - 1, (data & 0xff000000U) | (data & 0xffffff00U) >> 8, 0x00ffffff); - m_space->write_dword(address + 3, dword_from_byte(data & 0x000000ff), 0xff000000U); + pspec->write_dword(address - 1, (data & 0xff000000U) | (data & 0xffffff00U) >> 8, 0x00ffffff); + pspec->write_dword(address + 3, dword_from_byte(data & 0x000000ff), 0xff000000U); break; case 2: - m_space->write_dword(address - 2, dword_from_word((data & 0xffff0000U) >> 16), 0x0000ffff); - m_space->write_dword(address + 2, dword_from_word(data & 0x0000ffff), 0xffff0000U); + pspec->write_dword(address - 2, dword_from_word((data & 0xffff0000U) >> 16), 0x0000ffff); + pspec->write_dword(address + 2, dword_from_word(data & 0x0000ffff), 0xffff0000U); break; case 3: - m_space->write_dword(address - 3, dword_from_unaligned_word((data & 0xffff0000U) >> 16), 0x000000ff); - m_space->write_dword(address + 1, (data & 0x00ffffff) << 8 | (data & 0xff000000U) >> 24, 0xffffff00U); + pspec->write_dword(address - 3, dword_from_unaligned_word((data & 0xffff0000U) >> 16), 0x000000ff); + pspec->write_dword(address + 1, (data & 0x00ffffff) << 8 | (data & 0xff000000U) >> 24, 0xffffff00U); break; } }; @@ -1407,6 +1410,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) m_space = &space; m_ospace = &ospace; auto ocache = ospace.cache<2, 0, ENDIANNESS_BIG>(); + auto pspec = space.specific<2, 0, ENDIANNESS_BIG>(); m_readimm16 = [this, ocache](offs_t address) -> u16 { if (m_pmmu_enabled) { @@ -1418,32 +1422,32 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) return ocache->read_word(address); }; - m_read8 = [this](offs_t address) -> u8 { + m_read8 = [this, pspec](offs_t address) -> u8 { if (m_pmmu_enabled) { address = pmmu_translate_addr(address, 1); if (m_mmu_tmp_buserror_occurred) return ~0; } - return m_space->read_byte(address); + return pspec->read_byte(address); }; - m_read16 = [this](offs_t address) -> u16 { + m_read16 = [this, pspec](offs_t address) -> u16 { if (m_pmmu_enabled) { u32 address0 = pmmu_translate_addr(address, 1); if (m_mmu_tmp_buserror_occurred) return ~0; if (WORD_ALIGNED(address)) - return m_space->read_word(address0); + return pspec->read_word(address0); u32 address1 = pmmu_translate_addr(address + 1, 1); if (m_mmu_tmp_buserror_occurred) return ~0; - u16 result = m_space->read_byte(address0) << 8; - return result | m_space->read_byte(address1); + u16 result = pspec->read_byte(address0) << 8; + return result | pspec->read_byte(address1); } - return m_space->read_word_unaligned(address); + return pspec->read_word_unaligned(address); }; - m_read32 = [this](offs_t address) -> u32 { + m_read32 = [this, pspec](offs_t address) -> u32 { if (m_pmmu_enabled) { u32 address0 = pmmu_translate_addr(address, 1); if (m_mmu_tmp_buserror_occurred) @@ -1452,37 +1456,37 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) // not at page boundary; use default code address = address0; else if (DWORD_ALIGNED(address)) // 0 - return m_space->read_dword(address0); + return pspec->read_dword(address0); else { u32 address2 = pmmu_translate_addr(address+2, 1); if (m_mmu_tmp_buserror_occurred) return ~0; if (WORD_ALIGNED(address)) { // 2 - u32 result = m_space->read_word(address0) << 16; - return result | m_space->read_word(address2); + u32 result = pspec->read_word(address0) << 16; + return result | pspec->read_word(address2); } u32 address1 = pmmu_translate_addr(address+1, 1); u32 address3 = pmmu_translate_addr(address+3, 1); if (m_mmu_tmp_buserror_occurred) return ~0; - u32 result = m_space->read_byte(address0) << 24; - result |= m_space->read_word(address1) << 8; - return result | m_space->read_byte(address3); + u32 result = pspec->read_byte(address0) << 24; + result |= pspec->read_word(address1) << 8; + return result | pspec->read_byte(address3); } } - return m_space->read_dword_unaligned(address); + return pspec->read_dword_unaligned(address); }; - m_write8 = [this](offs_t address, u8 data) { + m_write8 = [this, pspec](offs_t address, u8 data) { if (m_pmmu_enabled) { address = pmmu_translate_addr(address, 0); if (m_mmu_tmp_buserror_occurred) return; } - m_space->write_dword(address & 0xfffffffcU, dword_from_byte(data), 0xff000000U >> 8 * (address & 3)); + pspec->write_dword(address & 0xfffffffcU, dword_from_byte(data), 0xff000000U >> 8 * (address & 3)); }; - m_write16 = [this](offs_t address, u16 data) { + m_write16 = [this, pspec](offs_t address, u16 data) { u32 address0 = address; if (m_pmmu_enabled) { address0 = pmmu_translate_addr(address0, 0); @@ -1491,15 +1495,15 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) } switch (address & 3) { case 0: - m_space->write_dword(address0, dword_from_word(data), 0xffff0000U); + pspec->write_dword(address0, dword_from_word(data), 0xffff0000U); break; case 1: - m_space->write_dword(address0 - 1, dword_from_unaligned_word(data), 0x00ffff00); + pspec->write_dword(address0 - 1, dword_from_unaligned_word(data), 0x00ffff00); break; case 2: - m_space->write_dword(address0 - 2, dword_from_word(data), 0x0000ffff); + pspec->write_dword(address0 - 2, dword_from_word(data), 0x0000ffff); break; case 3: @@ -1510,14 +1514,14 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) if (m_mmu_tmp_buserror_occurred) return; } - m_space->write_dword(address0 - 3, dword_from_unaligned_word(data), 0x000000ff); - m_space->write_dword(address1, dword_from_byte(data & 0x00ff), 0xff000000U); + pspec->write_dword(address0 - 3, dword_from_unaligned_word(data), 0x000000ff); + pspec->write_dword(address1, dword_from_byte(data & 0x00ff), 0xff000000U); break; } } }; - m_write32 = [this](offs_t address, u32 data) { + m_write32 = [this, pspec](offs_t address, u32 data) { u32 address0 = address; if (m_pmmu_enabled) { address0 = pmmu_translate_addr(address0, 0); @@ -1526,7 +1530,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) } switch (address & 3) { case 0: - m_space->write_dword(address0, data, 0xffffffffU); + pspec->write_dword(address0, data, 0xffffffffU); break; case 1: @@ -1537,8 +1541,8 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) if (m_mmu_tmp_buserror_occurred) return; } - m_space->write_dword(address0 - 1, (data & 0xff000000U) | (data & 0xffffff00U) >> 8, 0x00ffffff); - m_space->write_dword(address3, dword_from_byte(data & 0x000000ff), 0xff000000U); + pspec->write_dword(address0 - 1, (data & 0xff000000U) | (data & 0xffffff00U) >> 8, 0x00ffffff); + pspec->write_dword(address3, dword_from_byte(data & 0x000000ff), 0xff000000U); break; } @@ -1550,8 +1554,8 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) if (m_mmu_tmp_buserror_occurred) return; } - m_space->write_dword(address0 - 2, dword_from_word((data & 0xffff0000U) >> 16), 0x0000ffff); - m_space->write_dword(address2, dword_from_word(data & 0x0000ffff), 0xffff0000U); + pspec->write_dword(address0 - 2, dword_from_word((data & 0xffff0000U) >> 16), 0x0000ffff); + pspec->write_dword(address2, dword_from_word(data & 0x0000ffff), 0xffff0000U); break; } @@ -1563,8 +1567,8 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace) if (m_mmu_tmp_buserror_occurred) return; } - m_space->write_dword(address0 - 3, dword_from_unaligned_word((data & 0xffff0000U) >> 16), 0x000000ff); - m_space->write_dword(address1, (data & 0x00ffffff) << 8 | (data & 0xff000000U) >> 24, 0xffffff00U); + pspec->write_dword(address0 - 3, dword_from_unaligned_word((data & 0xffff0000U) >> 16), 0x000000ff); + pspec->write_dword(address1, (data & 0x00ffffff) << 8 | (data & 0xff000000U) >> 24, 0xffffff00U); break; } } @@ -1576,6 +1580,7 @@ void m68000_base_device::init32hmmu(address_space &space, address_space &ospace) m_space = &space; m_ospace = &ospace; auto ocache = ospace.cache<2, 0, ENDIANNESS_BIG>(); + auto pspec = space.specific<2, 0, ENDIANNESS_BIG>(); m_readimm16 = [this, ocache](offs_t address) -> u16 { if (m_hmmu_enabled) @@ -1583,69 +1588,69 @@ void m68000_base_device::init32hmmu(address_space &space, address_space &ospace) return ocache->read_word(address); }; - m_read8 = [this](offs_t address) -> u8 { + m_read8 = [this, pspec](offs_t address) -> u8 { if (m_hmmu_enabled) address = hmmu_translate_addr(address); - return m_space->read_byte(address); + return pspec->read_byte(address); }; - m_read16 = [this](offs_t address) -> u16 { + m_read16 = [this, pspec](offs_t address) -> u16 { if (m_hmmu_enabled) address = hmmu_translate_addr(address); if (WORD_ALIGNED(address)) - return m_space->read_word(address); - u16 result = m_space->read_byte(address) << 8; - return result | m_space->read_byte(address + 1); + return pspec->read_word(address); + u16 result = pspec->read_byte(address) << 8; + return result | pspec->read_byte(address + 1); }; - m_read32 = [this](offs_t address) -> u32 { + m_read32 = [this, pspec](offs_t address) -> u32 { if (m_hmmu_enabled) address = hmmu_translate_addr(address); if (DWORD_ALIGNED(address)) - return m_space->read_dword(address); + return pspec->read_dword(address); if (WORD_ALIGNED(address)) { - u32 result = m_space->read_word(address) << 16; - return result | m_space->read_word(address + 2); + u32 result = pspec->read_word(address) << 16; + return result | pspec->read_word(address + 2); } - u32 result = m_space->read_byte(address) << 24; - result |= m_space->read_word(address + 1) << 8; - return result | m_space->read_byte(address + 3); + u32 result = pspec->read_byte(address) << 24; + result |= pspec->read_word(address + 1) << 8; + return result | pspec->read_byte(address + 3); }; - m_write8 = [this](offs_t address, u8 data) { + m_write8 = [this, pspec](offs_t address, u8 data) { if (m_hmmu_enabled) address = hmmu_translate_addr(address); - m_space->write_byte(address, data); + pspec->write_byte(address, data); }; - m_write16 = [this](offs_t address, u16 data) { + m_write16 = [this, pspec](offs_t address, u16 data) { if (m_hmmu_enabled) address = hmmu_translate_addr(address); if (WORD_ALIGNED(address)) { - m_space->write_word(address, data); + pspec->write_word(address, data); return; } - m_space->write_byte(address, data >> 8); - m_space->write_byte(address + 1, data); + pspec->write_byte(address, data >> 8); + pspec->write_byte(address + 1, data); }; - m_write32 = [this](offs_t address, u32 data) { + m_write32 = [this, pspec](offs_t address, u32 data) { if (m_hmmu_enabled) address = hmmu_translate_addr(address); if (DWORD_ALIGNED(address)) { - m_space->write_dword(address, data); + pspec->write_dword(address, data); return; } if (WORD_ALIGNED(address)) { - m_space->write_word(address, data >> 16); - m_space->write_word(address + 2, data); + pspec->write_word(address, data >> 16); + pspec->write_word(address + 2, data); return; } - m_space->write_byte(address, data >> 24); - m_space->write_word(address + 1, data >> 8); - m_space->write_byte(address + 3, data); + pspec->write_byte(address, data >> 24); + pspec->write_word(address + 1, data >> 8); + pspec->write_byte(address + 3, data); }; } diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index edf76418e5a..1881bbbc013 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -529,6 +529,10 @@ public: return new memory_access_cache(*this, m_root_read, m_root_write); } + void *create_specific() override { + return new memory_access_specific(*this, m_dispatch_read, m_mask_read, m_shift_read, m_dispatch_write, m_mask_write, m_shift_write); + } + void delayed_ref(handler_entry *e) { e->ref(); m_delayed_unrefs.insert(e); @@ -593,43 +597,25 @@ public: // native read NativeType read_native(offs_t offset, NativeType mask) { - g_profiler.start(PROFILER_MEMREAD); - - uX result = dispatch_read(m_mask_read, m_shift_read, offset, mask, m_dispatch_read);; - - g_profiler.stop(); - return result; + return dispatch_read(m_mask_read, m_shift_read, offset, mask, m_dispatch_read);; } // mask-less native read NativeType read_native(offs_t offset) { - g_profiler.start(PROFILER_MEMREAD); - - uX result = dispatch_read(m_mask_read, m_shift_read, offset, uX(0xffffffffffffffffU), m_dispatch_read);; - - g_profiler.stop(); - return result; + return dispatch_read(m_mask_read, m_shift_read, offset, uX(0xffffffffffffffffU), m_dispatch_read);; } // native write void write_native(offs_t offset, NativeType data, NativeType mask) { - g_profiler.start(PROFILER_MEMWRITE); - dispatch_write(m_mask_write, m_shift_write, offset, data, mask, m_dispatch_write);; - - g_profiler.stop(); } // mask-less native write void write_native(offs_t offset, NativeType data) { - g_profiler.start(PROFILER_MEMWRITE); - dispatch_write(m_mask_write, m_shift_write, offset, data, uX(0xffffffffffffffffU), m_dispatch_write);; - - g_profiler.stop(); } // virtual access to these functions diff --git a/src/emu/emumem.h b/src/emu/emumem.h index f205a1317d9..bc4063e671e 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -976,6 +976,78 @@ template void dispatch_write(offs_t mask, } +// ======================> memory_access_specific + +// memory_access_specific does uncached but faster accesses by shortcutting the address_space virtual call + +template class memory_access_specific +{ + using NativeType = typename emu::detail::handler_entry_size::uX; + static constexpr u32 NATIVE_BYTES = 1 << Width; + static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0; + +public: + // construction/destruction + memory_access_specific(address_space &space, + handler_entry_read *const *dispatch_read, + offs_t mask_read, u8 shift_read, + handler_entry_write *const *dispatch_write, + offs_t mask_write, u8 shift_write); + + + // getters + address_space &space() const { return m_space; } + + u8 read_byte(offs_t address) { address &= m_addrmask; return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } + u16 read_word(offs_t address) { address &= m_addrmask; return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word(offs_t address, u16 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u16 read_word_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word_unaligned(offs_t address, u16 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword(offs_t address) { address &= m_addrmask; return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword(offs_t address, u32 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword_unaligned(offs_t address, u32 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword(offs_t address) { address &= m_addrmask; return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword(offs_t address, u64 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword_unaligned(offs_t address) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword_unaligned(offs_t address, u64 mask) { address &= m_addrmask; return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + + void write_byte(offs_t address, u8 data) { address &= m_addrmask; if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } + void write_word(offs_t address, u16 data) { address &= m_addrmask; if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word(offs_t address, u16 data, u16 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_word_unaligned(offs_t address, u16 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word_unaligned(offs_t address, u16 data, u16 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword(offs_t address, u32 data) { address &= m_addrmask; if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword(offs_t address, u32 data, u32 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword_unaligned(offs_t address, u32 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword_unaligned(offs_t address, u32 data, u32 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword(offs_t address, u64 data) { address &= m_addrmask; if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword(offs_t address, u64 data, u64 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword_unaligned(offs_t address, u64 data) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword_unaligned(offs_t address, u64 data, u64 mask) { address &= m_addrmask; memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + +private: + address_space & m_space; + + offs_t m_addrmask; // address mask + + handler_entry_read *const *m_dispatch_read; + handler_entry_write *const *m_dispatch_write; + offs_t m_mask_read; + offs_t m_mask_write; + u8 m_shift_read; + u8 m_shift_write; + + NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)) { + return dispatch_read(m_mask_read, m_shift_read, address, mask, m_dispatch_read);; + } + + void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) { + dispatch_write(m_mask_write, m_shift_write, address, data, mask, m_dispatch_write);; + } +}; + + // ======================> memory_access_cache @@ -1155,6 +1227,18 @@ public: return static_cast *>(create_cache()); } + template memory_access_specific *specific() { + if(AddrShift != m_config.addr_shift()) + fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); + if(8 << Width != m_config.data_width()) + fatalerror("Requesting cache() with data width %d while the config says %d\n", 8 << Width, m_config.data_width()); + if(Endian != m_config.endianness()) + fatalerror("Requesting cache() with endianness %s while the config says %s\n", + endianness_names[Endian], endianness_names[m_config.endianness()]); + + return static_cast *>(create_specific()); + } + int add_change_notifier(std::function n); void remove_change_notifier(int id); @@ -1476,6 +1560,7 @@ public: protected: // internal helpers virtual void *create_cache() = 0; + virtual void *create_specific() = 0; void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite); virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0; @@ -1848,4 +1933,20 @@ void memory_passthrough_handler::remove() m_space.remove_passthrough(m_handlers); } +template memory_access_specific::memory_access_specific(address_space &space, + handler_entry_read *const *dispatch_read, + offs_t mask_read, u8 shift_read, + handler_entry_write *const *dispatch_write, + offs_t mask_write, u8 shift_write) + : m_space(space), + m_addrmask(space.addrmask()), + m_dispatch_read(dispatch_read), + m_dispatch_write(dispatch_write), + m_mask_read(mask_read), + m_mask_write(mask_write), + m_shift_read(shift_read), + m_shift_write(shift_write) +{ +} + #endif /* MAME_EMU_EMUMEM_H */