summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/emumem_hedr.ipp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/emumem_hedr.ipp')
-rw-r--r--src/emu/emumem_hedr.ipp608
1 files changed, 441 insertions, 167 deletions
diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp
index 844cae6dd90..9994f251897 100644
--- a/src/emu/emumem_hedr.ipp
+++ b/src/emu/emumem_hedr.ipp
@@ -1,7 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
+#ifndef MAME_EMU_EMUMEM_HEDR_IPP
+#define MAME_EMU_EMUMEM_HEDR_IPP
+
+#pragma once
-#include "emu.h"
#include "emumem_mud.h"
#include "emumem_hea.h"
#include "emumem_heu.h"
@@ -9,178 +12,283 @@
#include "emumem_hep.h"
#include "emumem_hedr.h"
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> const handler_entry_read<Width, AddrShift, Endian> *const *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::get_dispatch() const
+template<int HighBits, int Width, int AddrShift> const handler_entry_read<Width, AddrShift> *const *handler_entry_read_dispatch<HighBits, Width, AddrShift>::get_dispatch() const
{
- return m_dispatch;
+ return m_a_dispatch;
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift, Endian> *handler) : handler_entry_read<Width, AddrShift, Endian>(space, handler_entry::F_DISPATCH)
+template<int HighBits, int Width, int AddrShift> handler_entry_read_dispatch<HighBits, Width, AddrShift>::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read<Width, AddrShift> *handler) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_DISPATCH), m_view(nullptr)
{
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
if (!handler)
- handler = space->get_unmap_r<Width, AddrShift, Endian>();
+ handler = space->get_unmap_r<Width, AddrShift>();
handler->ref(COUNT);
for(unsigned int i=0; i != COUNT; i++) {
- m_dispatch[i] = handler;
- m_ranges[i] = init;
+ m_u_dispatch[i] = handler;
+ m_u_ranges[i] = init;
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::~handler_entry_read_dispatch()
+template<int HighBits, int Width, int AddrShift> handler_entry_read_dispatch<HighBits, Width, AddrShift>::handler_entry_read_dispatch(address_space *space, memory_view &view) : handler_entry_read<Width, AddrShift>(space, handler_entry::F_VIEW), m_view(&view), m_a_dispatch(nullptr), m_a_ranges(nullptr), m_u_dispatch(nullptr), m_u_ranges(nullptr)
{
- for(unsigned int i=0; i != COUNT; i++)
- m_dispatch[i]->unref();
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ auto handler = space->get_unmap_r<Width, AddrShift>();
+ handler->ref(COUNT);
+ for(unsigned int i=0; i != COUNT; i++) {
+ m_u_dispatch[i] = handler;
+ m_u_ranges[i].set(0, 0);
+ }
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const
+template<int HighBits, int Width, int AddrShift> handler_entry_read_dispatch<HighBits, Width, AddrShift>::handler_entry_read_dispatch(handler_entry_read_dispatch<HighBits, Width, AddrShift> *src) : handler_entry_read<Width, AddrShift>(src->m_space, handler_entry::F_DISPATCH), m_view(nullptr)
{
- for(unsigned int i=0; i != COUNT; i++)
- refs.add(m_dispatch[i]);
+ m_ranges_array.resize(1);
+ m_dispatch_array.resize(1);
+ m_a_ranges = m_ranges_array[0].data();
+ m_a_dispatch = m_dispatch_array[0].data();
+ m_u_ranges = m_ranges_array[0].data();
+ m_u_dispatch = m_dispatch_array[0].data();
+
+ for(unsigned int i=0; i != COUNT; i++) {
+ m_u_dispatch[i] = src->m_u_dispatch[i]->dup();
+ m_u_ranges[i] = src->m_u_ranges[i];
+ }
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::dump_map(std::vector<memory_entry> &map) const
+
+template<int HighBits, int Width, int AddrShift> handler_entry_read_dispatch<HighBits, Width, AddrShift>::~handler_entry_read_dispatch()
{
- offs_t cur = map.empty() ? 0 : map.back().end + 1;
- offs_t base = cur & UPMASK;
- do {
- offs_t entry = (cur >> LowBits) & BITMASK;
- if(m_dispatch[entry]->is_dispatch())
- m_dispatch[entry]->dump_map(map);
- else
- map.emplace_back(memory_entry{ m_ranges[entry].start, m_ranges[entry].end, m_dispatch[entry] });
- cur = map.back().end + 1;
- } while(cur && !((cur ^ base) & UPMASK));
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ p->unref();
+}
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::enumerate_references(handler_entry::reflist &refs) const
+{
+ for(auto &d : m_dispatch_array)
+ for(auto p : d)
+ if(p)
+ refs.add(p);
+}
+
+template<int HighBits, int Width, int AddrShift> offs_t handler_entry_read_dispatch<HighBits, Width, AddrShift>::dispatch_entry(offs_t address) const
+{
+ return (address & HIGHMASK) >> LowBits;
+}
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::dump_map(std::vector<memory_entry> &map) const
+{
+ if(m_view) {
+ for(u32 i = 0; i != m_dispatch_array.size(); i++) {
+ u32 j = map.size();
+ offs_t cur = map.empty() ? m_view->m_addrstart & HIGHMASK : map.back().end + 1;
+ offs_t end = m_view->m_addrend + 1;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_dispatch_array[i][entry]->is_dispatch() || m_dispatch_array[i][entry]->is_view())
+ m_dispatch_array[i][entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_ranges_array[i][entry].start, m_ranges_array[i][entry].end, m_dispatch_array[i][entry] });
+ cur = map.back().end + 1;
+ } while(cur != end);
+ if(i == 0) {
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, true, 0 });
+ } else {
+ int slot = m_view->id_to_slot(int(i)-1);
+ for(u32 k = j; k != map.size(); k++)
+ map[k].context.emplace(map[k].context.begin(), memory_entry_context{ m_view, false, slot });
+ }
+ }
+ } else {
+ offs_t cur = map.empty() ? 0 : map.back().end + 1;
+ offs_t base = cur & UPMASK;
+ do {
+ offs_t entry = (cur >> LowBits) & BITMASK;
+ if(m_a_dispatch[entry]->is_dispatch() || m_a_dispatch[entry]->is_view())
+ m_a_dispatch[entry]->dump_map(map);
+ else
+ map.emplace_back(memory_entry{ m_a_ranges[entry].start, m_a_ranges[entry].end, m_a_dispatch[entry] });
+ cur = map.back().end + 1;
+ } while(cur && !((cur ^ base) & UPMASK));
+ }
+}
+
+template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read(offs_t offset, uX mem_mask) const
+{
+ return dispatch_read<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
+}
+
+template<int HighBits, int Width, int AddrShift> emu::detail::handler_entry_size_t<Width> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_interruptible(offs_t offset, uX mem_mask) const
+{
+ return dispatch_read_interruptible<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> typename emu::detail::handler_entry_size<Width>::uX handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::read(offs_t offset, uX mem_mask) const
+template<int HighBits, int Width, int AddrShift> std::pair<emu::detail::handler_entry_size_t<Width>, u16> handler_entry_read_dispatch<HighBits, Width, AddrShift>::read_flags(offs_t offset, uX mem_mask) const
{
- return dispatch_read<Level, Width, AddrShift, Endian>(HIGHMASK, offset, mem_mask, m_dispatch);
+ return dispatch_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::get_ptr(offs_t offset) const
+template<int HighBits, int Width, int AddrShift> u16 handler_entry_read_dispatch<HighBits, Width, AddrShift>::lookup_flags(offs_t offset, uX mem_mask) const
{
- return m_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
+ return dispatch_lookup_read_flags<Level, Width, AddrShift>(HIGHMASK, offset, mem_mask, m_a_dispatch);
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> std::string handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::name() const
+template<int HighBits, int Width, int AddrShift> void *handler_entry_read_dispatch<HighBits, Width, AddrShift>::get_ptr(offs_t offset) const
{
- return "dispatch";
+ return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset);
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift, Endian> *&handler) const
+template<int HighBits, int Width, int AddrShift> std::string handler_entry_read_dispatch<HighBits, Width, AddrShift>::name() const
+{
+ return m_view ? "view" : "dispatch";
+}
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift> *&handler) const
{
offs_t slot = (address >> LowBits) & BITMASK;
- auto h = m_dispatch[slot];
- if(h->is_dispatch())
+ auto h = m_a_dispatch[slot];
+ if(h->is_dispatch() || h->is_view())
h->lookup(address, start, end, handler);
else {
- start = m_ranges[slot].start;
- end = m_ranges[slot].end;
+ start = m_a_ranges[slot].start;
+ end = m_a_ranges[slot].end;
handler = h;
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_before(offs_t address, int start)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::range_cut_before(offs_t address, int start)
{
- while(--start >= 0) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_before(address);
+ while(--start >= 0 && m_u_dispatch[start]) {
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift> *>(m_u_dispatch[start])->range_cut_before(address);
break;
}
- if(m_ranges[start].end <= address)
+ if(m_u_ranges[start].end <= address)
break;
- m_ranges[start].end = address;
+ m_u_ranges[start].end = address;
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::range_cut_after(offs_t address, int start)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::range_cut_after(offs_t address, int start)
{
- while(++start < COUNT) {
- if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) {
- static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian> *>(m_dispatch[start])->range_cut_after(address);
+ while(++start < COUNT && m_u_dispatch[start]) {
+ if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) {
+ static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift> *>(m_u_dispatch[start])->range_cut_after(address);
break;
}
- if(m_ranges[start].start >= address)
+ if(m_u_ranges[start].start >= address)
break;
- m_ranges[start].start = address;
+ m_u_ranges[start].start = address;
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *handler)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_nomirror(start, end, ostart, oend, handler);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_nomirror(start, end, ostart, oend, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift, Endian> *handler)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift> *handler)
{
- offs_t start_entry = start >> LowBits;
- offs_t end_entry = end >> LowBits;
+ offs_t start_entry = (start & HIGHMASK) >> LowBits;
+ offs_t end_entry = (end & HIGHMASK) >> LowBits;
range_cut_before(ostart-1, start_entry);
range_cut_after(oend+1, end_entry);
- if(LowBits <= Width + AddrShift) {
+ if constexpr(LowBits <= Width + AddrShift) {
+ if(handler->is_view()) {
+ int delta = dispatch_entry(ostart) - handler->dispatch_entry(ostart);
+ handler->init_handlers(start >> LowBits, end >> LowBits, LowBits, ostart, oend, m_u_dispatch + delta, m_u_ranges + delta);
+ }
handler->ref(end_entry - start_entry);
for(offs_t ent = start_entry; ent <= end_entry; ent++) {
- m_dispatch[ent]->unref();
- m_dispatch[ent] = handler;
- m_ranges[ent].set(ostart, oend);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_ranges[ent].set(ostart, oend);
}
} else if(start_entry == end_entry) {
if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) {
- m_dispatch[start_entry]->unref();
- m_dispatch[start_entry] = handler;
- m_ranges[start_entry].set(ostart, oend);
+ if(handler->is_view()) {
+ int delta = dispatch_entry(ostart) - handler->dispatch_entry(ostart);
+ handler->init_handlers(start >> LowBits, end >> LowBits, LowBits, ostart, oend, m_u_dispatch + delta, m_u_ranges + delta);
+ }
+ m_u_dispatch[start_entry]->unref();
+ m_u_dispatch[start_entry] = handler;
+ m_u_ranges[start_entry].set(ostart, oend);
} else
- populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler);
+ populate_nomirror_subdispatch(start_entry, start, end, ostart, oend, handler);
} else {
if(start & LOWMASK) {
- populate_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler);
+ populate_nomirror_subdispatch(start_entry, start, start | LOWMASK, ostart, oend, handler);
start_entry++;
+ start = (start | LOWMASK) + 1;
if(start_entry <= end_entry)
handler->ref();
}
if((end & LOWMASK) != LOWMASK) {
- populate_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler);
+ populate_nomirror_subdispatch(end_entry, end & ~LOWMASK, end, ostart, oend, handler);
end_entry--;
+ end = (end & ~LOWMASK) - 1;
if(start_entry <= end_entry)
handler->ref();
}
if(start_entry <= end_entry) {
+ if(handler->is_view()) {
+ int delta = dispatch_entry(ostart) - handler->dispatch_entry(ostart);
+ handler->init_handlers(start >> LowBits, end >> LowBits, LowBits, ostart, oend, m_u_dispatch + delta, m_u_ranges + delta);
+ }
handler->ref(end_entry - start_entry);
for(offs_t ent = start_entry; ent <= end_entry; ent++) {
- m_dispatch[ent]->unref();
- m_dispatch[ent] = handler;
- m_ranges[ent].set(ostart, oend);
+ m_u_dispatch[ent]->unref();
+ m_u_dispatch[ent] = handler;
+ m_u_ranges[ent].set(ostart, oend);
}
}
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift, Endian> *handler)
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift> *handler)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_mirror(start, end, ostart, oend, mirror, handler);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler);
+ range_cut_before((entry << LowBits) - 1, entry);
+ range_cut_after((entry + 1) << LowBits, entry);
}
}
-
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift, Endian> *handler)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read<Width, AddrShift> *handler)
{
offs_t hmirror = mirror & HIGHMASK;
offs_t lmirror = mirror & LOWMASK;
@@ -190,12 +298,10 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
offs_t add = 1 + ~hmirror;
offs_t offset = 0;
offs_t base_entry = start >> LowBits;
- start &= LOWMASK;
- end &= LOWMASK;
do {
if(offset)
handler->ref();
- populate_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler);
+ populate_mirror_subdispatch(base_entry | (offset >> LowBits), start | offset, end | offset, ostart | offset, oend | offset, lmirror, handler);
offset = (offset + add) & hmirror;
} while(offset);
} else {
@@ -211,11 +317,11 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::mismatched_patch(const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 rkey, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift, Endian> *&target)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::mismatched_patch(const memory_units_descriptor<Width, AddrShift> &descriptor, u8 rkey, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift> *&target)
{
u8 ukey = descriptor.rkey_to_ukey(rkey);
- handler_entry_read<Width, AddrShift, Endian> *original = target->is_units() ? target : nullptr;
- handler_entry_read<Width, AddrShift, Endian> *replacement = nullptr;
+ handler_entry_read<Width, AddrShift> *original = target->is_units() ? target : nullptr;
+ handler_entry_read<Width, AddrShift> *replacement = nullptr;
for(const auto &p : mappings)
if(p.ukey == ukey && p.original == original) {
replacement = p.patched;
@@ -223,9 +329,9 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
if(!replacement) {
if(original)
- replacement = new handler_entry_read_units<Width, AddrShift, Endian>(descriptor, ukey, static_cast<handler_entry_read_units<Width, AddrShift, Endian> *>(original));
+ replacement = new handler_entry_read_units<Width, AddrShift>(descriptor, ukey, static_cast<handler_entry_read_units<Width, AddrShift> *>(original));
else
- replacement = new handler_entry_read_units<Width, AddrShift, Endian>(descriptor, ukey, inh::m_space);
+ replacement = new handler_entry_read_units<Width, AddrShift>(descriptor, ukey, this->m_space);
mappings.emplace_back(mapping{ original, replacement, ukey });
} else
@@ -234,92 +340,91 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
target = replacement;
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 rkey, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift> &descriptor, u8 rkey, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings);
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, u8 rkey, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mismatched_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor<Width, AddrShift> &descriptor, u8 rkey, std::vector<mapping> &mappings)
{
- offs_t start_entry = start >> LowBits;
- offs_t end_entry = end >> LowBits;
+ offs_t start_entry = (start & HIGHMASK) >> LowBits;
+ offs_t end_entry = (end & HIGHMASK) >> LowBits;
range_cut_before(ostart-1, start_entry);
range_cut_after(oend+1, end_entry);
- if(LowBits <= Width + AddrShift) {
+ if constexpr(LowBits <= Width + AddrShift) {
for(offs_t ent = start_entry; ent <= end_entry; ent++) {
u8 rkey1 = rkey;
if(ent != start_entry)
rkey1 &= ~handler_entry::START;
if(ent != end_entry)
rkey1 &= ~handler_entry::END;
- mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]);
- m_ranges[ent].set(ostart, oend);
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].set(ostart, oend);
}
} else if(start_entry == end_entry) {
if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) {
- if(m_dispatch[start_entry]->is_dispatch())
- m_dispatch[start_entry]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings);
+ if(m_u_dispatch[start_entry]->is_dispatch())
+ m_u_dispatch[start_entry]->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings);
else {
- mismatched_patch(descriptor, rkey, mappings, m_dispatch[start_entry]);
- m_ranges[start_entry].set(ostart, oend);
+ mismatched_patch(descriptor, rkey, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].set(ostart, oend);
}
} else
- populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings);
+ populate_mismatched_nomirror_subdispatch(start_entry, start, end, ostart, oend, descriptor, rkey, mappings);
} else {
if(start & LOWMASK) {
- populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::END, mappings);
+ populate_mismatched_nomirror_subdispatch(start_entry, start, start | LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::END, mappings);
start_entry++;
rkey &= ~handler_entry::START;
}
if((end & LOWMASK) != LOWMASK) {
- populate_mismatched_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, descriptor, rkey & ~handler_entry::START, mappings);
+ populate_mismatched_nomirror_subdispatch(end_entry, end & ~LOWMASK, end, ostart, oend, descriptor, rkey & ~handler_entry::START, mappings);
end_entry--;
rkey &= ~handler_entry::END;
}
- if(start_entry <= end_entry) {
- for(offs_t ent = start_entry; ent <= end_entry; ent++) {
- u8 rkey1 = rkey;
- if(ent != start_entry)
- rkey1 &= ~handler_entry::START;
- if(ent != end_entry)
- rkey1 &= ~handler_entry::END;
- if(m_dispatch[ent]->is_dispatch())
- m_dispatch[ent]->populate_mismatched_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey1, mappings);
- else {
- mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]);
- m_ranges[ent].set(ostart, oend);
- }
+ offs_t base = start & ~LOWMASK;
+ for(offs_t ent = start_entry; ent <= end_entry; ent++) {
+ u8 rkey1 = rkey;
+ if(ent != start_entry)
+ rkey1 &= ~handler_entry::START;
+ if(ent != end_entry)
+ rkey1 &= ~handler_entry::END;
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_dispatch[ent]->populate_mismatched_nomirror(base | (ent << LowBits), base | (ent << LowBits) | LOWMASK, ostart, oend, descriptor, rkey1, mappings);
+ else {
+ mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].set(ostart, oend);
}
}
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mismatched_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings);
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift, Endian> &descriptor, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_mismatched_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, const memory_units_descriptor<Width, AddrShift> &descriptor, std::vector<mapping> &mappings)
{
offs_t hmirror = mirror & HIGHMASK;
offs_t lmirror = mirror & LOWMASK;
@@ -329,8 +434,6 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
offs_t add = 1 + ~hmirror;
offs_t offset = 0;
offs_t base_entry = start >> LowBits;
- start &= LOWMASK;
- end &= LOWMASK;
do {
populate_mismatched_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, descriptor, mappings);
offset = (offset + add) & hmirror;
@@ -346,95 +449,139 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
}
-
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::passthrough_patch(handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift, Endian> *&target)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::passthrough_patch(handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings, handler_entry_read<Width, AddrShift> *&target)
{
- handler_entry_read<Width, AddrShift, Endian> *original = target;
- handler_entry_read<Width, AddrShift, Endian> *replacement = nullptr;
+ // Look in cache first
for(const auto &p : mappings)
- if(p.original == original) {
- replacement = p.patched;
- break;
+ if(p.original == target) {
+ p.patched->ref();
+ target->unref();
+ target = p.patched;
+ return;
}
- if(!replacement) {
- replacement = handler->instantiate(original);
+
+ handler_entry_read<Width, AddrShift> *original = target;
+ u32 target_priority = original->f_get_pt();
+ u32 new_priority = handler->f_get_pt();
+
+ // 3 cases: new one on top, new one on bottom, or new one replaces old one
+
+ if(!target_priority || new_priority > target_priority || (new_priority == target_priority && !(new_priority & 1))) {
+ // New one goes over the old one
+ // previous one is not passthrough (target_priority = 0)
+ // new one has higher priority
+ // both have the same priority, and the priority is even which means keep both
+
+ // We instantiate the new one with the old one under it and put it in place and in the cache
+
+ handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(original);
mappings.emplace_back(mapping{ original, replacement });
- } else
- replacement->ref();
- target->unref();
- target = replacement;
+ target->unref();
+ target = replacement;
+
+ } else if(new_priority == target_priority) {
+ // New one replaces the old one
+ // both have the same priority, and the priority is odd which means keep only the new one
+
+ // We instantiate the new one with the old one's subtarget and put it in place and in the cache
+
+ handler_entry_read<Width, AddrShift> *replacement = handler->instantiate(static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler());
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+
+ } else {
+ // New one goes under the old one
+ // both are passthrough and new one has lower priority
+ //
+ // This can be recursive, so do the passthrough patch on the subhandler, then instantiate the old one with the result
+
+ handler_entry_read<Width, AddrShift> *recursive = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->get_subhandler();
+ recursive->ref();
+
+ passthrough_patch(handler, mappings, recursive);
+
+ handler_entry_read<Width, AddrShift> *replacement = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(original)->instantiate(recursive);
+ mappings.emplace_back(mapping{ original, replacement });
+ target->unref();
+ target = replacement;
+ recursive->unref();
+ }
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
{
offs_t start_entry = (start & HIGHMASK) >> LowBits;
offs_t end_entry = (end & HIGHMASK) >> LowBits;
range_cut_before(ostart-1, start_entry);
range_cut_after(oend+1, end_entry);
- if(LowBits <= Width + AddrShift) {
+ if constexpr(LowBits <= Width + AddrShift) {
for(offs_t ent = start_entry; ent <= end_entry; ent++) {
- passthrough_patch(handler, mappings, m_dispatch[ent]);
- m_ranges[ent].intersect(ostart, oend);
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].intersect(ostart, oend);
}
} else if(start_entry == end_entry) {
if(!(start & LOWMASK) && (end & LOWMASK) == LOWMASK) {
- passthrough_patch(handler, mappings, m_dispatch[start_entry]);
- m_ranges[start_entry].intersect(ostart, oend);
+ if(m_u_dispatch[start_entry]->is_dispatch())
+ m_u_dispatch[start_entry]->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings);
+ else {
+ passthrough_patch(handler, mappings, m_u_dispatch[start_entry]);
+ m_u_ranges[start_entry].intersect(ostart, oend);
+ }
} else
- populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings);
+ populate_passthrough_nomirror_subdispatch(start_entry, start, end, ostart, oend, handler, mappings);
} else {
if(start & LOWMASK) {
- populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler, mappings);
+ populate_passthrough_nomirror_subdispatch(start_entry, start, start | LOWMASK, ostart, oend, handler, mappings);
start_entry++;
}
if((end & LOWMASK) != LOWMASK) {
- populate_passthrough_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler, mappings);
+ populate_passthrough_nomirror_subdispatch(end_entry, end & ~LOWMASK, end, ostart, oend, handler, mappings);
end_entry--;
}
- if(start_entry <= end_entry) {
- for(offs_t ent = start_entry; ent <= end_entry; ent++) {
- if(m_dispatch[ent]->is_dispatch())
- m_dispatch[ent]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings);
- else {
- passthrough_patch(handler, mappings, m_dispatch[ent]);
- m_ranges[ent].intersect(ostart, oend);
- }
+ offs_t base = start & ~LOWMASK;
+ for(offs_t ent = start_entry; ent <= end_entry; ent++) {
+ if(m_u_dispatch[ent]->is_dispatch())
+ m_u_dispatch[ent]->populate_passthrough_nomirror(base | (ent << LowBits), base | (ent << LowBits) | LOWMASK, ostart, oend, handler, mappings);
+ else {
+ passthrough_patch(handler, mappings, m_u_dispatch[ent]);
+ m_u_ranges[ent].intersect(ostart, oend);
}
}
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
{
- auto cur = m_dispatch[entry];
+ auto cur = m_u_dispatch[entry];
if(cur->is_dispatch())
cur->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings);
else {
- auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift, Endian>(handler_entry::m_space, m_ranges[entry], cur);
+ auto subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], cur);
cur->unref();
- m_dispatch[entry] = subdispatch;
+ m_u_dispatch[entry] = subdispatch;
subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings);
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift, Endian> *handler, std::vector<mapping> &mappings)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::populate_passthrough_mirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read_passthrough<Width, AddrShift> *handler, std::vector<mapping> &mappings)
{
offs_t hmirror = mirror & HIGHMASK;
offs_t lmirror = mirror & LOWMASK;
@@ -444,10 +591,8 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
offs_t add = 1 + ~hmirror;
offs_t offset = 0;
offs_t base_entry = start >> LowBits;
- start &= LOWMASK;
- end &= LOWMASK;
do {
- populate_passthrough_mirror_subdispatch(base_entry | (offset >> LowBits), start, end, ostart | offset, oend | offset, lmirror, handler, mappings);
+ populate_passthrough_mirror_subdispatch(base_entry | (offset >> LowBits), start | offset, end | offset, ostart | offset, oend | offset, lmirror, handler, mappings);
offset = (offset + add) & hmirror;
} while(offset);
} else {
@@ -461,25 +606,154 @@ template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handl
}
}
-template<int HighBits, int Width, int AddrShift, endianness_t Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers)
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::detach(const std::unordered_set<handler_entry *> &handlers)
{
for(unsigned int i=0; i != COUNT; i++) {
- if(m_dispatch[i]->is_dispatch()) {
- m_dispatch[i]->detach(handlers);
+ if(m_u_dispatch[i]->is_dispatch()) {
+ m_u_dispatch[i]->detach(handlers);
continue;
}
- if(!m_dispatch[i]->is_passthrough())
+ if(!m_u_dispatch[i]->is_passthrough())
continue;
- auto np = static_cast<handler_entry_read_passthrough<Width, AddrShift, Endian> *>(m_dispatch[i]);
+ auto np = static_cast<handler_entry_read_passthrough<Width, AddrShift> *>(m_u_dispatch[i]);
if(handlers.find(np) != handlers.end()) {
- m_dispatch[i] = np->get_subhandler();
- m_dispatch[i]->ref();
+ m_u_dispatch[i] = np->get_subhandler();
+ m_u_dispatch[i]->ref();
np->unref();
} else
np->detach(handlers);
}
}
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, offs_t ostart, offs_t oend, handler_entry_read<Width, AddrShift> **dispatch, handler_entry::range *ranges)
+{
+ if(lowbits < LowBits) {
+ offs_t entry = start_entry >> LowBits;
+ if(entry != (end_entry >> LowBits))
+ fatalerror("Recursive init_handlers spanning multiple entries.\n");
+ entry &= BITMASK;
+ handler_entry_read_dispatch<LowBits, Width, AddrShift> *subdispatch;
+ if(m_u_dispatch[entry]->flags() & handler_entry::F_DISPATCH)
+ subdispatch = static_cast<handler_entry_read_dispatch<LowBits, Width, AddrShift> *>(m_u_dispatch[entry]);
+
+ else if(!(m_u_dispatch[entry]->flags() & handler_entry::F_UNMAP))
+ fatalerror("Collision on multiple init_handlers calls");
+
+ else {
+ m_u_dispatch[entry]->unref();
+ m_u_dispatch[entry] = subdispatch = new handler_entry_read_dispatch<LowBits, Width, AddrShift>(this->m_space, m_u_ranges[entry], nullptr);
+ }
+ int delta = dispatch_entry(ostart) - subdispatch->dispatch_entry(ostart);
+ subdispatch->init_handlers(start_entry, end_entry, lowbits, ostart, oend, dispatch + delta, ranges + delta);
+
+ } else if(lowbits != LowBits) {
+ u32 dt = lowbits - LowBits;
+ u32 ne = 1 << dt;
+ u32 ee = end_entry - start_entry;
+ if(m_view) {
+ auto filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) { r.intersect(s, e); return r; };
+
+ for(offs_t entry = 0; entry <= ee; entry++) {
+ dispatch[entry]->ref(ne);
+ u32 e0 = (entry << dt) & BITMASK;
+ for(offs_t e = 0; e != ne; e++) {
+ offs_t e1 = e0 | e;
+ if(!(m_u_dispatch[e1]->flags() & handler_entry::F_UNMAP))
+ fatalerror("Collision on multiple init_handlers calls");
+ m_u_dispatch[e1]->unref();
+ m_u_dispatch[e1] = dispatch[entry];
+ m_u_ranges[e1] = filter(ranges[entry]);
+ }
+ }
+ } else {
+ for(offs_t entry = 0; entry <= ee; entry++) {
+ dispatch[entry]->ref(ne);
+ u32 e0 = (entry << dt) & BITMASK;
+ for(offs_t e = 0; e != ne; e++) {
+ offs_t e1 = e0 | e;
+ if(!(m_u_dispatch[e1]->flags() & handler_entry::F_UNMAP))
+ fatalerror("Collision on multiple init_handlers calls");
+ m_u_dispatch[e1]->unref();
+ m_u_dispatch[e1] = dispatch[entry];
+ m_u_ranges[e1] = ranges[entry];
+ }
+ }
+ }
+
+ } else {
+ if(m_view) {
+ auto filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) { r.intersect(s, e); return r; };
+
+ for(offs_t entry = start_entry & BITMASK; entry <= (end_entry & BITMASK); entry++) {
+ if(!(m_u_dispatch[entry]->flags() & handler_entry::F_UNMAP))
+ fatalerror("Collision on multiple init_handlers calls");
+ m_u_dispatch[entry]->unref();
+ m_u_dispatch[entry] = dispatch[entry];
+ m_u_ranges[entry] = filter(ranges[entry]);
+ dispatch[entry]->ref();
+ }
+ } else {
+ for(offs_t entry = start_entry & BITMASK; entry <= (end_entry & BITMASK); entry++) {
+ if(!(m_u_dispatch[entry]->flags() & handler_entry::F_UNMAP))
+ fatalerror("Collision on multiple init_handlers calls");
+ m_u_dispatch[entry]->unref();
+ m_u_dispatch[entry] = dispatch[entry];
+ m_u_ranges[entry] = ranges[entry];
+ dispatch[entry]->ref();
+ }
+ }
+ }
+}
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::select_a(int id)
+{
+ u32 i = id+1;
+ if(i >= m_dispatch_array.size())
+ fatalerror("out-of-range view selection.");
+
+ m_a_ranges = m_ranges_array[i].data();
+ m_a_dispatch = m_dispatch_array[i].data();
+}
+
+template<int HighBits, int Width, int AddrShift> void handler_entry_read_dispatch<HighBits, Width, AddrShift>::select_u(int id)
+{
+ u32 i = id+1;
+ if(i > m_dispatch_array.size())
+ fatalerror("out-of-range view update selection.");
+ else if(i == m_dispatch_array.size()) {
+ u32 aid = (handler_array *)(m_a_dispatch) - m_dispatch_array.data();
+
+ m_dispatch_array.resize(i+1);
+ m_ranges_array.resize(i+1);
+ m_a_ranges = m_ranges_array[aid].data();
+ m_a_dispatch = m_dispatch_array[aid].data();
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+
+ for(u32 entry = 0; entry != COUNT; entry++)
+ if(m_dispatch_array[0][entry]) {
+ m_u_dispatch[entry] = m_dispatch_array[0][entry]->dup();
+ m_u_ranges[entry] = m_ranges_array[0][entry];
+ }
+
+ } else {
+ m_u_ranges = m_ranges_array[i].data();
+ m_u_dispatch = m_dispatch_array[i].data();
+ }
+}
+
+template<int HighBits, int Width, int AddrShift> handler_entry_read<Width, AddrShift> *handler_entry_read_dispatch<HighBits, Width, AddrShift>::dup()
+{
+ if(m_view) {
+ handler_entry::ref();
+ return this;
+ }
+
+ return new handler_entry_read_dispatch<HighBits, Width, AddrShift>(this);
+}
+
+#endif // MAME_EMU_EMUMEM_HEDR_IPP