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.
This commit is contained in:
Olivier Galibert 2020-05-19 18:29:36 +02:00
parent beb60b8721
commit ecef74a610
3 changed files with 200 additions and 108 deletions

View File

@ -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);
};
}

View File

@ -529,6 +529,10 @@ public:
return new memory_access_cache<Width, AddrShift, Endian>(*this, m_root_read, m_root_write);
}
void *create_specific() override {
return new memory_access_specific<Width, AddrShift, Endian>(*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<Width, AddrShift, Endian>(m_mask_read, m_shift_read, offset, mask, m_dispatch_read);;
g_profiler.stop();
return result;
return dispatch_read<Width, AddrShift, Endian>(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<Width, AddrShift, Endian>(m_mask_read, m_shift_read, offset, uX(0xffffffffffffffffU), m_dispatch_read);;
g_profiler.stop();
return result;
return dispatch_read<Width, AddrShift, Endian>(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<Width, AddrShift, Endian>(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<Width, AddrShift, Endian>(m_mask_write, m_shift_write, offset, data, uX(0xffffffffffffffffU), m_dispatch_write);;
g_profiler.stop();
}
// virtual access to these functions

View File

@ -976,6 +976,78 @@ template<int Width, int AddrShift, int Endian> 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<int Width, int AddrShift, int Endian> class memory_access_specific
{
using NativeType = typename emu::detail::handler_entry_size<Width>::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 <Width, AddrShift, Endian> *const *dispatch_read,
offs_t mask_read, u8 shift_read,
handler_entry_write<Width, AddrShift, Endian> *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<Width, AddrShift, Endian, 0, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 0, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, true>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 1, false>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, true>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 2, false>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, true>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian, 3, false>([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<Width, AddrShift, Endian> *const *m_dispatch_read;
handler_entry_write<Width, AddrShift, Endian> *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<Width, AddrShift, Endian>(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<Width, AddrShift, Endian>(m_mask_write, m_shift_write, address, data, mask, m_dispatch_write);;
}
};
// ======================> memory_access_cache
@ -1155,6 +1227,18 @@ public:
return static_cast<memory_access_cache<Width, AddrShift, Endian> *>(create_cache());
}
template<int Width, int AddrShift, int Endian> memory_access_specific<Width, AddrShift, Endian> *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<memory_access_specific<Width, AddrShift, Endian> *>(create_specific());
}
int add_change_notifier(std::function<void (read_or_write)> 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<int Width, int AddrShift, int Endian> memory_access_specific<Width, AddrShift, Endian>::memory_access_specific(address_space &space,
handler_entry_read <Width, AddrShift, Endian> *const *dispatch_read,
offs_t mask_read, u8 shift_read,
handler_entry_write<Width, AddrShift, Endian> *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 */