diff options
author | 2018-06-29 10:58:19 +0200 | |
---|---|---|
committer | 2018-06-29 20:04:28 +0200 | |
commit | a704ed7b1b121c3bcff52d49bff8372360fe907c (patch) | |
tree | 53dd19f2dbe2bd0bf0f747dcccd989beabfafbf7 /src/emu/emumem_hedr.ipp | |
parent | f16d1298a44e71c18c337fc321faebe4fe691e06 (diff) |
emumem: Backend modernization [O. Galibert]
Diffstat (limited to 'src/emu/emumem_hedr.ipp')
-rw-r--r-- | src/emu/emumem_hedr.ipp | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp new file mode 100644 index 00000000000..5f368b57448 --- /dev/null +++ b/src/emu/emumem_hedr.ipp @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_heu.h" +#include "emumem_heun.h" +#include "emumem_hep.h" +#include "emumem_hedr.h" + +template<int HighBits, int Width, int AddrShift, int 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) +{ + if (!handler) + handler = space->get_unmap_r<Width, AddrShift, Endian>(); + handler->ref(COUNT); + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i] = handler; + m_ranges[i] = init; + } +} + +template<int HighBits, int Width, int AddrShift, int Endian> handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::~handler_entry_read_dispatch() +{ + for(unsigned int i=0; i != COUNT; i++) + m_dispatch[i]->unref(); +} + +template<int HighBits, int Width, int AddrShift, int Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::enumerate_references(handler_entry::reflist &refs) const +{ + for(unsigned int i=0; i != COUNT; i++) + refs.add(m_dispatch[i]); +} + +template<int HighBits, int Width, int AddrShift, int Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::dump_map(std::vector<memory_entry> &map) const +{ + 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)); + +} + +template<int HighBits, int Width, int AddrShift, int Endian> typename handler_entry_size<Width>::uX handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::read(offs_t offset, uX mem_mask) +{ + return m_dispatch[(offset >> LowBits) & BITMASK]->read(offset, mem_mask); +} + +template<int HighBits, int Width, int AddrShift, int Endian> void *handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::get_ptr(offs_t offset) const +{ + return m_dispatch[(offset >> LowBits) & BITMASK]->get_ptr(offset); +} + +template<int HighBits, int Width, int AddrShift, int Endian> std::string handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::name() const +{ + return "dispatch"; +} + +template<int HighBits, int Width, int AddrShift, int 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 +{ + offs_t slot = (address >> LowBits) & BITMASK; + auto h = m_dispatch[slot]; + if(h->is_dispatch()) + h->lookup(address, start, end, handler); + else { + start = m_ranges[slot].start; + end = m_ranges[slot].end; + handler = h; + } +} + +template<int HighBits, int Width, int AddrShift, int Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::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); + break; + } + if(m_ranges[start].end <= address) + break; + m_ranges[start].end = address; + } +} + +template<int HighBits, int Width, int AddrShift, int Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::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); + break; + } + if(m_ranges[start].start >= address) + break; + m_ranges[start].start = address; + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_nomirror(start, end, ostart, oend, handler); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + offs_t start_entry = start >> LowBits; + offs_t end_entry = end >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(LowBits <= Width + AddrShift) { + 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); + } + + } 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); + } else + populate_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler); + + } else { + if(start & LOWMASK) { + populate_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler); + start_entry++; + if(start_entry <= end_entry) + handler->ref(); + } + if((end & LOWMASK) != LOWMASK) { + populate_nomirror_subdispatch(end_entry, 0, end & LOWMASK, ostart, oend, handler); + end_entry--; + if(start_entry <= end_entry) + handler->ref(); + } + + if(start_entry <= end_entry) { + 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); + } + } + } +} +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mirror(start, end, ostart, oend, mirror, handler); + } +} + + +template<int HighBits, int Width, int AddrShift, int 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) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + 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); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + if(offset) + handler->ref(); + populate_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + 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; + for(const auto &p : mappings) + if(p.ukey == ukey && p.original == original) { + replacement = p.patched; + break; + } + 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)); + else + replacement = new handler_entry_read_units<Width, AddrShift, Endian>(descriptor, ukey, inh::m_space); + + mappings.emplace_back(mapping{ original, replacement, ukey }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_nomirror(start, end, ostart, oend, descriptor, rkey, mappings); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + offs_t start_entry = start >> LowBits; + offs_t end_entry = end >> LowBits; + range_cut_before(ostart-1, start_entry); + range_cut_after(oend+1, end_entry); + + if(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); + } + + } 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); + else { + mismatched_patch(descriptor, rkey, mappings, m_dispatch[start_entry]); + m_ranges[start_entry].set(ostart, oend); + } + } else + populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, 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); + 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); + 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); + } + } + } + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_mismatched_mirror(start, end, ostart, oend, mirror, descriptor, mappings); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + 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; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_mismatched_nomirror(start | offset, end | offset, ostart | offset, oend | offset, descriptor, handler_entry::START|handler_entry::END, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + + +template<int HighBits, int Width, int AddrShift, int 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) +{ + handler_entry_read<Width, AddrShift, Endian> *original = target; + handler_entry_read<Width, AddrShift, Endian> *replacement = nullptr; + for(const auto &p : mappings) + if(p.original == original) { + replacement = p.patched; + break; + } + if(!replacement) { + replacement = handler->instantiate(original); + mappings.emplace_back(mapping{ original, replacement }); + } else + replacement->ref(); + target->unref(); + target = replacement; +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_nomirror(start, end, ostart, oend, handler, mappings); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + 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) { + for(offs_t ent = start_entry; ent <= end_entry; ent++) { + if(m_dispatch[start_entry]->is_dispatch()) + m_dispatch[start_entry]->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); + } + } + + } 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); + } else + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + + } else { + if(start & LOWMASK) { + populate_passthrough_nomirror_subdispatch(start_entry, start & LOWMASK, LOWMASK, ostart, oend, handler, mappings); + start_entry++; + } + if((end & LOWMASK) != LOWMASK) { + populate_passthrough_nomirror_subdispatch(end_entry, 0, end & LOWMASK, 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); + } + } + } + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + auto cur = m_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); + cur->unref(); + m_dispatch[entry] = subdispatch; + subdispatch->populate_passthrough_mirror(start, end, ostart, oend, mirror, handler, mappings); + } +} + +template<int HighBits, int Width, int AddrShift, int 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) +{ + offs_t hmirror = mirror & HIGHMASK; + offs_t lmirror = mirror & LOWMASK; + + if(lmirror) { + // If lmirror is non-zero, then each mirror instance is a single entry + 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); + offset = (offset + add) & hmirror; + } while(offset); + } else { + // If lmirror is zero, call the nomirror version as needed + offs_t add = 1 + ~hmirror; + offs_t offset = 0; + do { + populate_passthrough_nomirror(start | offset, end | offset, ostart | offset, oend | offset, handler, mappings); + offset = (offset + add) & hmirror; + } while(offset); + } +} + +template<int HighBits, int Width, int AddrShift, int Endian> void handler_entry_read_dispatch<HighBits, Width, AddrShift, Endian>::detach(const std::unordered_set<handler_entry *> &handlers) +{ + for(unsigned int i=0; i != COUNT; i++) { + m_dispatch[i]->unref(); + if(!m_dispatch[i]->is_passthrough()) + continue; + auto np = static_cast<handler_entry_read_passthrough<Width, AddrShift, Endian> *>(m_dispatch[i]); + + if(handlers.find(np) != handlers.end()) { + m_dispatch[i] = np->get_subhandler(); + m_dispatch[i]->ref(); + np->unref(); + + } else + np->detach(handlers); + } +} |