From c12f2ee58d1a65d5007440804e08d466220398e6 Mon Sep 17 00:00:00 2001 From: AJR Date: Thu, 15 Feb 2018 22:02:35 -0500 Subject: Set up heavily mirrored memory ranges with subunit masks (e.g. orunners) much more efficiently --- src/emu/emumem.cpp | 92 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index 851d9825b28..8d10ed5af4c 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -331,14 +331,15 @@ public: void apply_mask(offs_t addrmask) { m_addrmask &= addrmask; } void clear_conflicting_subunits(u64 handlermask); - bool overriden_by_mask(u64 handlermask); + bool overriden_by_mask(u64 handlermask) const; protected: // Subunit description information struct subunit_info { offs_t m_addrmask; // addrmask for this subunit - u32 m_csmask; // chip select mask for this subunit + u64 m_datamask; // datamask for this subunit + u64 m_csmask; // chip select mask for this subunit s32 m_offset; // offset to add to the address u32 m_multiplier; // multiplier to the pre-split address u8 m_size; // size (8, 16 or 32) @@ -525,7 +526,7 @@ template class handler_entry_proxy { public: - handler_entry_proxy(std::list _handlers, u64 _umask, int _cswidth) : handlers(std::move(_handlers)), umask(_umask), cswidth(_cswidth) {} + handler_entry_proxy(std::list &&_handlers, u64 _umask, int _cswidth) : handlers(std::move(_handlers)), umask(_umask), cswidth(_cswidth) {} handler_entry_proxy(const handler_entry_proxy &hep) : handlers(hep.handlers), umask(hep.umask), cswidth(hep.cswidth) {} // forward delegate callbacks configuration @@ -607,7 +608,7 @@ public: // table mapping helpers void map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u16 staticentry); - void setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask, std::list &entries); + std::list setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); u16 derive_range(offs_t address, offs_t &addrstart, offs_t &addrend) const; // misc helpers @@ -665,8 +666,9 @@ private: u16 handler_free; u16 get_free_handler(); void verify_reference_counts(); - void setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, std::list &entries); - void setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask, std::list &entries); + bool range_simply_masks(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); + std::list setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror); + std::list setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask); void handler_ref(u16 entry, int count) { @@ -705,12 +707,11 @@ public: // range getter handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries; - setup_range(addrstart, addrend, addrmask, addrmirror, umask, entries); + std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); std::list handlers; for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_read(*i)); - return handler_entry_proxy(handlers, umask, cswidth); + return handler_entry_proxy(std::move(handlers), umask, cswidth); } private: @@ -778,12 +779,11 @@ public: // range getter handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries; - setup_range(addrstart, addrend, addrmask, addrmirror, umask, entries); + std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); std::list handlers; for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_write(*i)); - return handler_entry_proxy(handlers, umask, cswidth); + return handler_entry_proxy(std::move(handlers), umask, cswidth); } private: @@ -856,12 +856,11 @@ public: // range getter handler_entry_proxy handler_map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask = 0, int cswidth = 0) { - std::list entries; - setup_range(addrstart, addrend, addrmask, addrmirror, umask, entries); + std::list entries = setup_range(addrstart, addrend, addrmask, addrmirror, umask); std::list handlers; for (std::list::const_iterator i = entries.begin(); i != entries.end(); ++i) handlers.push_back(&handler_setoffset(*i)); - return handler_entry_proxy(handlers, umask, cswidth); + return handler_entry_proxy(std::move(handlers), umask, cswidth); } private: @@ -2074,7 +2073,7 @@ void address_space::check_optimize_all(const char *function, int width, offs_t a // Check if the 1-blocks are of appropriate size u64 block_mask = 0xffffffffffffffffU >> (64 - width); u64 cs_mask = 0xffffffffffffffffU >> (64 - ncswidth); - for(int pos = 0; pos != 64; pos += ncswidth) { + for(int pos = 0; pos < 64; pos += ncswidth) { u64 cmask = (unitmask >> pos) & cs_mask; while (cmask != 0 && (cmask & block_mask) == 0) cmask >>= width; @@ -3244,15 +3243,37 @@ u16 address_table::get_free_handler() // it //------------------------------------------------- -void address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask, std::list &entries) +std::list address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) { // Careful, you can't shift by 64 or more u64 testmask = (1ULL << (m_space.data_width()-1) << 1) - 1; - if ((umask & testmask) == 0 || (umask & testmask) == testmask) - setup_range_solid(addrstart, addrend, addrmask, addrmirror, entries); + if ((umask & testmask) == 0 || (umask & testmask) == testmask || range_simply_masks(addrstart, addrend, addrmask, addrmirror, umask)) + return setup_range_solid(addrstart, addrend, addrmask, addrmirror); else - setup_range_masked(addrstart, addrend, addrmask, addrmirror, umask, entries); + return setup_range_masked(addrstart, addrend, addrmask, addrmirror, umask); +} + +//------------------------------------------------- +// range_simply_masks - determine if a handler +// can fully override part of one existing range +// (speeds up mapping in heavily mirrored cases) +//------------------------------------------------- + +bool address_table::range_simply_masks(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) +{ + // convert addresses to bytes + m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); + + // Validity checks + assert_always(addrstart <= addrend, "address_table::setup_range called with start greater than end"); + assert_always((addrstart & (m_space.alignment() - 1)) == 0, "address_table::setup_range called with misaligned start address"); + assert_always((addrend & (m_space.alignment() - 1)) == (m_space.alignment() - 1), "address_table::setup_range called with misaligned end address"); + + offs_t range_start, range_end; + u16 entry = derive_range(addrstart, range_start, range_end); + + return range_end >= (addrend | addrmirror) && (entry < STATIC_COUNT || handler(entry).overriden_by_mask(umask)); } //------------------------------------------------- @@ -3261,8 +3282,10 @@ void address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmas // it. Replace what's there. //------------------------------------------------- -void address_table::setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, std::list &entries) +std::list address_table::setup_range_solid(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror) { + std::list entries; + // Grab a free entry u16 entry = get_free_handler(); @@ -3271,10 +3294,12 @@ void address_table::setup_range_solid(offs_t addrstart, offs_t addrend, offs_t a // Configure and map it map_range(addrstart, addrend, addrmask, addrmirror, entry); + + return entries; } //------------------------------------------------- -// setup_range_solid - finds an appropriate handler +// setup_range_masked - finds an appropriate handler // entry and requests to populate the address map with // it. Handle non-overlapping subunits. //------------------------------------------------- @@ -3286,8 +3311,10 @@ namespace { }; } -void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask, std::list &entries) +std::list address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, u64 umask) { + std::list entries; + // convert addresses to bytes m_space.adjust_addresses(addrstart, addrend, addrmask, addrmirror); @@ -3312,7 +3339,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t { offs_t range_start, range_end; u16 entry = derive_range(base_address, range_start, range_end); - u32 stop_address = range_end > end_address ? end_address : range_end; + u32 stop_address = std::min(range_end, end_address); if (entry < STATIC_COUNT || handler(entry).overriden_by_mask(umask)) range_override.push_back(subrange(base_address, stop_address)); @@ -3393,6 +3420,7 @@ void address_table::setup_range_masked(offs_t addrstart, offs_t addrend, offs_t } // verify_reference_counts(); + return entries; } @@ -4648,6 +4676,7 @@ void handler_entry::configure_subunits(u64 handlermask, int handlerbits, int csw if (((handlermask >> shift) & unitmask) != 0) { m_subunit_infos[m_subunits].m_addrmask = m_bytemask / (maxunits / multiplier); + m_subunit_infos[m_subunits].m_datamask = unitmask << shift; m_subunit_infos[m_subunits].m_csmask = selectmask << (((unitnum^shift_xor_mask) & ~(granularity-1)) * handlerbits); m_subunit_infos[m_subunits].m_offset = cur_offset++; m_subunit_infos[m_subunits].m_size = handlerbits; @@ -4682,7 +4711,7 @@ void handler_entry::clear_conflicting_subunits(u64 handlermask) // Start by the end to avoid unnecessary memmoves for (int i=m_subunits-1; i>=0; i--) - if (((handlermask >> m_subunit_infos[i].m_shift) & ((u64(1) << m_subunit_infos[m_subunits].m_size) - 1)) != 0) + if ((handlermask & m_subunit_infos[i].m_datamask) != 0) { if (i != m_subunits-1) memmove (m_subunit_infos+i, m_subunit_infos+i+1, (m_subunits-i-1)*sizeof(m_subunit_infos[0])); @@ -4692,7 +4721,7 @@ void handler_entry::clear_conflicting_subunits(u64 handlermask) // Recompute the inverse mask m_invsubmask = 0; for (int i = 0; i < m_subunits; i++) - m_invsubmask |= ((u64(1) << m_subunit_infos[m_subunits].m_size) - 1) << m_subunit_infos[i].m_shift; + m_invsubmask |= m_subunit_infos[i].m_datamask; m_invsubmask = ~m_invsubmask; } @@ -4703,7 +4732,7 @@ void handler_entry::clear_conflicting_subunits(u64 handlermask) // that's currently present //------------------------------------------------- -bool handler_entry::overriden_by_mask(u64 handlermask) +bool handler_entry::overriden_by_mask(u64 handlermask) const { // A mask of 0 is in fact an alternative way of saying ~0 if (!handlermask) @@ -4715,7 +4744,7 @@ bool handler_entry::overriden_by_mask(u64 handlermask) // Check whether a subunit would be left for (int i=0; i != m_subunits; i++) - if (((handlermask >> m_subunit_infos[i].m_shift) & ((u64(1) << m_subunit_infos[i].m_size) - 1)) == 0) + if ((handlermask & m_subunit_infos[i].m_datamask) == 0) return false; return true; @@ -4735,13 +4764,14 @@ void handler_entry::description(char *buffer) const { if (i) *buffer++ = ' '; - buffer += sprintf (buffer, "%d:%d:%x:%d:%x:%x:%s", + buffer += sprintf (buffer, "%d:%d:%x:%d:%x:%s:%s:%s", m_subunit_infos[i].m_size, m_subunit_infos[i].m_shift, m_subunit_infos[i].m_offset, m_subunit_infos[i].m_multiplier, m_subunit_infos[i].m_addrmask, - m_subunit_infos[i].m_csmask, + core_i64_hex_format(m_subunit_infos[i].m_datamask, m_datawidth), + core_i64_hex_format(m_subunit_infos[i].m_csmask, m_datawidth), subunit_name(i)); } } @@ -5053,7 +5083,7 @@ u64 handler_entry_read::read_stub_64(address_space &space, offs_t offset, u64 ma val = m_subread[index].r32(space, aoffset & si.m_addrmask, mask >> si.m_shift); break; } - result |= u64(val) << si.m_shift; + result |= u64(val) << si.m_shift; } } return result; -- cgit v1.2.3