diff --git a/docs/source/techspecs/memory.rst b/docs/source/techspecs/memory.rst index 0b9b24dc7f434..87fd4afd64023 100644 --- a/docs/source/techspecs/memory.rst +++ b/docs/source/techspecs/memory.rst @@ -64,6 +64,20 @@ Memory regions are read-only memory zones in which ROMs are loaded. All of these have names allowing to access them. +2.4 Views +~~~~~~~~~ + +Views are a way to multiplex different submaps over a memory range +with fast switching. It is to be used when multiple devices map at +the same addresses and are switched in externally. They must be +created as an object of the device and then setup either statically in +a memory map or dynamically through install_* calls. + +Switchable submaps, aka variants, are named through an integer. An +internal indirection through a map ensures that any integer value can +be used. + + 3. Memory objects ----------------- @@ -225,6 +239,37 @@ The ``memregion`` device method retrieves a memory region by name. Beware that the lookup can be expensive, prefer finders instead. +3.4 Views - memory_view +~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: C++ + + class memory_view { + memory_view(device_t &device, std::string name); + memory_view_entry &operator[](int slot); + + void select(int entry); + void disable(); + + const std::string &name() const; + } + +A view allows to switch part of a memory map between multiple +possibilities, or even disable it entirely to see what was there +before. It is created as an object of the device. + +.. code-block:: C++ + + memory_view m_view; + + [device constructor] m_view(*this, "name"), + +It is then setup through the address map API or dynamically. The, at +runtime, a variant, which is numbered, can be selected through the +``select`` method or the view can be disabled through the ``disabled`` +method. A disabled view can be reenabled at any time. + + 4. Address maps API ------------------- @@ -543,6 +588,40 @@ trigger the handler if a wider part of the bus is accessed. The parameter is that trigger width (would be 16 in the 68000 case). +4.5 View setup +~~~~~~~~~~~~~~ + +.. code-block:: C++ + + map(start, end).view(m_view); + m_view[0](start1, end1).[...]; + +A view is setup in a address map with the view method. The only +qualifier accepted is mirror. The "disabled" version of the view will +include what was in the range prior to the view setup. + +The different variants are setup by indexing the view with the variant +number and setting up an entry in the usual way. The entries within a +variant must of course stay within the range. There are no other +additional constraints. The contents of a variant, by default, are +what was there before, e.g. the contents of the disabled view, and +then setting it up allows to override part or all of it. + +Variants can only be setup once the view itself has been setup with +the ``view`` method. + +A view can only be put in one address map and in only one position. +If multiple views have identical or similar contents remember that +setting up a map is nothing more than a method call, and creating a +second method to setup a view is perfectly reasonable. A view is of +type **memory_view** and an indexed entry (e.g. a variant to setup) is +of type **memory_view::memory_view_entry &**. + +A view can be installed in another view, but don't forget that a view +can be installed only once. A view can also being part of "what was +there before". + + 5. Address space dynamic mapping API ------------------------------------ @@ -695,3 +774,21 @@ with an optional mirror. Install a device address with an address map in a space. The ``unitmask`` and ``cswidth`` arguments are optional. + +5.9 View installation +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: C++ + + space.install_view(addrstart, addrend, view) + space.install_view(addrstart, addrend, addrmirror, view) + + view[0].install... + +Installs a view in a space. This can be only done once and in only +one space, and the view must not have been setup through the address +map API before. Once the view is installed variants can be selected +through indexation to call a dynamic mapping method on it. + +A view can be installed into a variant of another view without issues +with the only usual constraint of single installation. diff --git a/scripts/src/emu.lua b/scripts/src/emu.lua index ca3188d0b824d..4e7e294ad323b 100644 --- a/scripts/src/emu.lua +++ b/scripts/src/emu.lua @@ -117,6 +117,8 @@ files { MAME_DIR .. "src/emu/emucore.h", MAME_DIR .. "src/emu/emumem.cpp", MAME_DIR .. "src/emu/emumem.h", + MAME_DIR .. "src/emu/emumem_aspace.cpp", + MAME_DIR .. "src/emu/emumem_mview.cpp", MAME_DIR .. "src/emu/emumem_mud.cpp", MAME_DIR .. "src/emu/emumem_mud.h", MAME_DIR .. "src/emu/emumem_hea.h", diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index ebc0331a76724..246a4306d879f 100644 --- a/src/emu/addrmap.cpp +++ b/src/emu/addrmap.cpp @@ -19,39 +19,6 @@ #define DETECT_OVERLAPPING_MEMORY (0) -/*------------------------------------------------- - core_i64_hex_format - i64 format printf helper - why isn't fatalerror going through the same - channels as logerror exactly? --------------------------------------------------*/ - -static char *core_i64_hex_format(u64 value, u8 mindigits) -{ - static char buffer[16][64]; - // TODO: this can overflow - e.g. when a lot of unmapped writes are logged - static int index; - char *bufbase = &buffer[index++ % 16][0]; - char *bufptr = bufbase; - s8 curdigit; - - for (curdigit = 15; curdigit >= 0; curdigit--) - { - int nibble = (value >> (curdigit * 4)) & 0xf; - if (nibble != 0 || curdigit < mindigits) - { - mindigits = curdigit; - *bufptr++ = "0123456789ABCDEF"[nibble]; - } - } - if (bufptr == bufbase) - *bufptr++ = '0'; - *bufptr = 0; - - return bufbase; -} - - - //************************************************************************** // ADDRESS MAP ENTRY //************************************************************************** @@ -201,6 +168,15 @@ address_map_entry &address_map_entry::m(device_t *device, address_map_constructo return *this; } +void address_map_entry::view(memory_view &mv) +{ + m_read.m_type = AMH_VIEW; + m_read.m_tag = nullptr; + m_write.m_type = AMH_VIEW; + m_write.m_tag = nullptr; + m_view = &mv; + mv.initialize_from_address_map(m_addrstart, m_addrend, m_map.get_config()); +} //------------------------------------------------- // r/w/rw - handler setters for @@ -787,8 +763,9 @@ bool address_map_entry::unitmask_is_appropriate(u8 width, u64 unitmask, const ch address_map::address_map(device_t &device, int spacenum) : m_spacenum(spacenum), m_device(&device), + m_view(nullptr), m_unmapval(0), - m_globalmask(0) + m_globalmask(0) { // get our memory interface const device_memory_interface *memintf; @@ -796,8 +773,8 @@ address_map::address_map(device_t &device, int spacenum) throw emu_fatalerror("No memory interface defined for device '%s'\n", m_device->tag()); // and then the configuration for the current address space - const address_space_config *spaceconfig = memintf->space_config(spacenum); - if (spaceconfig == nullptr) + m_config = memintf->space_config(spacenum); + if (m_config == nullptr) throw emu_fatalerror("No memory address space configuration found for device '%s', space %d\n", m_device->tag(), spacenum); // append the map provided by the owner @@ -809,8 +786,8 @@ address_map::address_map(device_t &device, int spacenum) } // construct the internal device map (last so it takes priority) - if (!spaceconfig->m_internal_map.isnull()) - spaceconfig->m_internal_map(*this); + if (!m_config->m_internal_map.isnull()) + m_config->m_internal_map(*this); } @@ -822,6 +799,7 @@ address_map::address_map(device_t &device, int spacenum) address_map::address_map(device_t &device, address_map_entry *entry) : m_spacenum(AS_PROGRAM), m_device(&device), + m_view(nullptr), m_unmapval(0), m_globalmask(0) { @@ -839,6 +817,7 @@ address_map::address_map(device_t &device, address_map_entry *entry) address_map::address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate) : m_spacenum(space.spacenum()), m_device(&device), + m_view(nullptr), m_unmapval(space.unmap()), m_globalmask(space.addrmask()) { @@ -846,6 +825,21 @@ address_map::address_map(const address_space &space, offs_t start, offs_t end, u } +//---------------------------------------------------------- +// address_map - constructor memory view mapping case +//---------------------------------------------------------- + +address_map::address_map(memory_view &view) + : m_spacenum(-1), + m_device(&view.m_device), + m_view(&view), + m_config(view.m_config), + m_unmapval(0), + m_globalmask(0) +{ +} + + //------------------------------------------------- // ~address_map - destructor //------------------------------------------------- @@ -981,7 +975,7 @@ void address_map::import_submaps(running_machine &machine, device_t &owner, int subentry_ratio ++; subentry_ratio = data_width / subentry_ratio; if (ratio * subentry_ratio > data_width / 8) - fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %s combined with an entry unitmask of %s does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, core_i64_hex_format(entry->m_mask, data_width/4), core_i64_hex_format(subentry->m_mask, data_width/4), data_width); + fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %0*x combined with an entry unitmask of %0*x does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, data_width/4, entry->m_mask, data_width/4, subentry->m_mask, data_width); // Regenerate the unitmask u64 newmask = 0; @@ -1394,3 +1388,8 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons valid.validate_tag(entry.m_share); } } + +const address_space_config &address_map::get_config() const +{ + return *m_config; +} diff --git a/src/emu/addrmap.h b/src/emu/addrmap.h index 229db15caa102..6f2f903306d47 100644 --- a/src/emu/addrmap.h +++ b/src/emu/addrmap.h @@ -40,7 +40,8 @@ enum map_handler_type AMH_DEVICE_DELEGATE_SMO, AMH_PORT, AMH_BANK, - AMH_DEVICE_SUBMAP + AMH_DEVICE_SUBMAP, + AMH_VIEW }; @@ -184,6 +185,8 @@ class address_map_entry address_map_entry &m(const char *tag, address_map_constructor func); address_map_entry &m(device_t *device, address_map_constructor func); + // view initialization + void view(memory_view &mv); // implicit base -> delegate converter template @@ -404,6 +407,7 @@ class address_map_entry device_t *m_submap_device; address_map_constructor m_submap_delegate; + memory_view *m_view; // information used during processing void * m_memory; // pointer to memory backing this entry @@ -477,6 +481,7 @@ class address_map public: // construction/destruction address_map(device_t &device, int spacenum); + address_map(memory_view &view); address_map(device_t &device, address_map_entry *entry); address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate); ~address_map(); @@ -492,12 +497,15 @@ class address_map // public data int m_spacenum; // space number of the map device_t * m_device; // associated device + memory_view * m_view; // view, when in one + const address_space_config * m_config; // space configuration u8 m_unmapval; // unmapped memory value offs_t m_globalmask; // global mask simple_list m_entrylist; // list of entries void import_submaps(running_machine &machine, device_t &owner, int data_width, endianness_t endian, int addr_shift); void map_validity_check(validity_checker &valid, int spacenum) const; + const address_space_config &get_config() const; }; #endif // MAME_EMU_ADDRMAP_H diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp index a5856a9b79478..949f1194061bc 100644 --- a/src/emu/debug/debugcmd.cpp +++ b/src/emu/debug/debugcmd.cpp @@ -3767,10 +3767,15 @@ void debugger_commands::execute_memdump(int ref, const std::vector for (memory_entry &entry : entries[mode]) { if (octal) - fprintf(file, "%0*o - %0*o", nc, entry.start, nc, entry.end); + fprintf(file, "%0*o - %0*o:", nc, entry.start, nc, entry.end); else - fprintf(file, "%0*x - %0*x", nc, entry.start, nc, entry.end); - fprintf(file, ": %s\n", entry.entry->name().c_str()); + fprintf(file, "%0*x - %0*x:", nc, entry.start, nc, entry.end); + for(const auto &c : entry.context) + if(c.disabled) + fprintf(file, " %s[off]", c.view->name().c_str()); + else + fprintf(file, " %s[%d]", c.view->name().c_str(), c.slot); + fprintf(file, " %s\n", entry.entry->name().c_str()); } fprintf(file, "\n"); } diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index be33acf32ed7c..1b6b48af5220e 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -149,6 +149,7 @@ class memory_bank; class memory_manager; class memory_region; class memory_share; +class memory_view; // declared in emuopts.h class emu_options; diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index 4e8bfb2636328..51eab43fcf751 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -48,6 +48,16 @@ void handler_entry::dump_map(std::vector &map) const fatalerror("dump_map called on non-dispatching class\n"); } +void handler_entry::select_a(int slot) +{ + fatalerror("select_a called on non-view\n"); +} + +void handler_entry::select_u(int slot) +{ + fatalerror("select_u called on non-view\n"); +} + void handler_entry::reflist::add(const handler_entry *entry) { refcounts[entry]++; @@ -132,11 +142,22 @@ template void *handler_entry_read return nullptr; } +template handler_entry_read *handler_entry_read::dup() +{ + ref(); + return this; +} + template void handler_entry_read::detach(const std::unordered_set &handlers) { fatalerror("detach called on non-dispatching class\n"); } +template void handler_entry_read::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read **dispatch, handler_entry::range *ranges) +{ + fatalerror("init_handlers called on non-view class\n"); +} + template const handler_entry_write *const *handler_entry_write::get_dispatch() const { @@ -183,651 +204,75 @@ template void *handler_entry_writ return nullptr; } -template void handler_entry_write::detach(const std::unordered_set &handlers) +template handler_entry_write *handler_entry_write::dup() { - fatalerror("detach called on non-dispatching class\n"); + ref(); + return this; } - - -/*------------------------------------------------- - core_i64_hex_format - i64 format printf helper --------------------------------------------------*/ - -static char *core_i64_hex_format(u64 value, u8 mindigits) +template void handler_entry_write::detach(const std::unordered_set &handlers) { - static char buffer[16][64]; - // TODO: this can overflow - e.g. when a lot of unmapped writes are logged - static int index; - char *bufbase = &buffer[index++ % 16][0]; - char *bufptr = bufbase; - s8 curdigit; - - for (curdigit = 15; curdigit >= 0; curdigit--) - { - int nibble = (value >> (curdigit * 4)) & 0xf; - if (nibble != 0 || curdigit < mindigits) - { - mindigits = curdigit; - *bufptr++ = "0123456789ABCDEF"[nibble]; - } - } - if (bufptr == bufbase) - *bufptr++ = '0'; - *bufptr = 0; - - return bufbase; + fatalerror("detach called on non-dispatching class\n"); } - - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -namespace { - -template struct handler_width; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 0; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 1; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 2; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -template <> struct handler_width { static constexpr int value = 3; }; -} // anonymous namespace - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> address_space_specific - -// this is a derived class of address_space with specific width, endianness, and table size -template -class address_space_specific : public address_space -{ - using uX = typename emu::detail::handler_entry_size::uX; - using NativeType = uX; - using this_type = address_space_specific; - - // constants describing the native size - static constexpr u32 NATIVE_BYTES = 1 << Width; - static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); - static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; - static constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; - - static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } - -public: - const handler_entry_read *const *m_dispatch_read; - const handler_entry_write *const *m_dispatch_write; - - std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const override; - void dump_maps(std::vector &read_map, std::vector &write_map) const override; - - void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) override; - void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) override; - void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) override; - void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) override; - void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0) override; - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override - { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } - void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } - void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override - { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } - - using address_space::install_read_tap; - using address_space::install_write_tap; - using address_space::install_readwrite_tap; - - virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; - virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) override; - - // construction/destruction - address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum, int address_width) - : address_space(manager, memory, spacenum) - { - m_unmap_r = new handler_entry_read_unmapped (this); - m_unmap_w = new handler_entry_write_unmapped(this); - m_nop_r = new handler_entry_read_nop (this); - m_nop_w = new handler_entry_write_nop(this); - - handler_entry::range r{ 0, 0xffffffff >> (32 - address_width) }; - - switch (address_width) { - case 1: m_root_read = new handler_entry_read_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); break; - case 2: m_root_read = new handler_entry_read_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); break; - case 3: m_root_read = new handler_entry_read_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); break; - case 4: m_root_read = new handler_entry_read_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); break; - case 5: m_root_read = new handler_entry_read_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); break; - case 6: m_root_read = new handler_entry_read_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); break; - case 7: m_root_read = new handler_entry_read_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); break; - case 8: m_root_read = new handler_entry_read_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); break; - case 9: m_root_read = new handler_entry_read_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); break; - case 10: m_root_read = new handler_entry_read_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); break; - case 11: m_root_read = new handler_entry_read_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); break; - case 12: m_root_read = new handler_entry_read_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); break; - case 13: m_root_read = new handler_entry_read_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); break; - case 14: m_root_read = new handler_entry_read_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); break; - case 15: m_root_read = new handler_entry_read_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); break; - case 16: m_root_read = new handler_entry_read_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); break; - case 17: m_root_read = new handler_entry_read_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); break; - case 18: m_root_read = new handler_entry_read_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); break; - case 19: m_root_read = new handler_entry_read_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); break; - case 20: m_root_read = new handler_entry_read_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); break; - case 21: m_root_read = new handler_entry_read_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); break; - case 22: m_root_read = new handler_entry_read_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); break; - case 23: m_root_read = new handler_entry_read_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); break; - case 24: m_root_read = new handler_entry_read_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); break; - case 25: m_root_read = new handler_entry_read_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); break; - case 26: m_root_read = new handler_entry_read_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); break; - case 27: m_root_read = new handler_entry_read_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); break; - case 28: m_root_read = new handler_entry_read_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); break; - case 29: m_root_read = new handler_entry_read_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); break; - case 30: m_root_read = new handler_entry_read_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); break; - case 31: m_root_read = new handler_entry_read_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); break; - case 32: m_root_read = new handler_entry_read_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); break; - default: fatalerror("Unhandled address bus width %d\n", address_width); - } - - m_dispatch_read = m_root_read ->get_dispatch(); - m_dispatch_write = m_root_write->get_dispatch(); - } - - ~address_space_specific() { - m_root_read->unref(); - m_root_write->unref(); - } - - std::pair get_cache_info() override { - std::pair rw; - rw.first = m_root_read; - rw.second = m_root_write; - return rw; - } - - std::pair get_specific_info() override { - std::pair rw; - rw.first = m_dispatch_read; - rw.second = m_dispatch_write; - return rw; - } - - void delayed_ref(handler_entry *e) { - e->ref(); - m_delayed_unrefs.insert(e); - } - - void delayed_unref(handler_entry *e) { - m_delayed_unrefs.erase(m_delayed_unrefs.find(e)); - e->unref(); - } - - void validate_reference_counts() const override { - handler_entry::reflist refs; - refs.add(m_root_read); - refs.add(m_root_write); - refs.add(m_unmap_r); - refs.add(m_unmap_w); - refs.add(m_nop_r); - refs.add(m_nop_w); - for(handler_entry *e : m_delayed_unrefs) - refs.add(e); - refs.propagate(); - refs.check(); - } - - virtual void remove_passthrough(std::unordered_set &handlers) override { - invalidate_caches(read_or_write::READWRITE); - m_root_read->detach(handlers); - m_root_write->detach(handlers); - } - - // generate accessor table - virtual void accessors(data_accessors &accessors) const override - { - accessors.read_byte = reinterpret_cast(&read_byte_static); - accessors.read_word = reinterpret_cast(&read_word_static); - accessors.read_word_masked = reinterpret_cast(&read_word_masked_static); - accessors.read_dword = reinterpret_cast(&read_dword_static); - accessors.read_dword_masked = reinterpret_cast(&read_dword_masked_static); - accessors.read_qword = reinterpret_cast(&read_qword_static); - accessors.read_qword_masked = reinterpret_cast(&read_qword_masked_static); - accessors.write_byte = reinterpret_cast(&write_byte_static); - accessors.write_word = reinterpret_cast(&write_word_static); - accessors.write_word_masked = reinterpret_cast(&write_word_masked_static); - accessors.write_dword = reinterpret_cast(&write_dword_static); - accessors.write_dword_masked = reinterpret_cast(&write_dword_masked_static); - accessors.write_qword = reinterpret_cast(&write_qword_static); - accessors.write_qword_masked = reinterpret_cast(&write_qword_masked_static); - } - - // return a pointer to the read bank, or nullptr if none - virtual void *get_read_ptr(offs_t address) const override - { - return m_root_read->get_ptr(address); - } - - // return a pointer to the write bank, or nullptr if none - virtual void *get_write_ptr(offs_t address) const override - { - return m_root_write->get_ptr(address); - } - - // native read - NativeType read_native(offs_t offset, NativeType mask) - { - return dispatch_read(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read); - } - - // mask-less native read - NativeType read_native(offs_t offset) - { - return dispatch_read(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read); - } - - // native write - void write_native(offs_t offset, NativeType data, NativeType mask) - { - dispatch_write(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write); - } - - // mask-less native write - void write_native(offs_t offset, NativeType data) - { - dispatch_write(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write); - } - - // virtual access to these functions - u8 read_byte(offs_t address) override { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } - u16 read_word(offs_t address) override { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u16 read_word_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } - u16 read_word_unaligned(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword(offs_t address) override { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u32 read_dword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } - u32 read_dword_unaligned(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword(offs_t address) override { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - u64 read_qword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } - u64 read_qword_unaligned(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } - - void write_byte(offs_t address, u8 data) override { if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } - void write_word(offs_t address, u16 data) override { if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } - void write_word(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_word_unaligned(offs_t address, u16 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } - void write_word_unaligned(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_dword(offs_t address, u32 data) override { if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } - void write_dword(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_dword_unaligned(offs_t address, u32 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } - void write_dword_unaligned(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_qword(offs_t address, u64 data) override { if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - void write_qword(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - void write_qword_unaligned(offs_t address, u64 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - void write_qword_unaligned(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } - - // static access to these functions - static u8 read_byte_static(this_type &space, offs_t address) { return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); } - static u16 read_word_static(this_type &space, offs_t address) { return Width == 1 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffff); } - static u16 read_word_masked_static(this_type &space, offs_t address, u16 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static u32 read_dword_static(this_type &space, offs_t address) { return Width == 2 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffff); } - static u32 read_dword_masked_static(this_type &space, offs_t address, u32 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static u64 read_qword_static(this_type &space, offs_t address) { return Width == 3 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffffffffffffU); } - static u64 read_qword_masked_static(this_type &space, offs_t address, u64 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } - static void write_byte_static(this_type &space, offs_t address, u8 data) { if (Width == 0) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xff); } - static void write_word_static(this_type &space, offs_t address, u16 data) { if (Width == 1) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffff); } - static void write_word_masked_static(this_type &space, offs_t address, u16 data, u16 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - static void write_dword_static(this_type &space, offs_t address, u32 data) { if (Width == 2) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffff); } - static void write_dword_masked_static(this_type &space, offs_t address, u32 data, u32 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - static void write_qword_static(this_type &space, offs_t address, u64 data) { if (Width == 3) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } - static void write_qword_masked_static(this_type &space, offs_t address, u64 data, u64 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } - - handler_entry_read *m_root_read; - handler_entry_write *m_root_write; - - std::unordered_set m_delayed_unrefs; - -private: - template - void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r) - { - try { handler_r.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - install_read_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r); - } - - template - void install_write_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, WRITE &handler_w) - { - try { handler_w.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - install_write_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_w); - } - - template - void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r, WRITE &handler_w) - { - static_assert(handler_width::value == handler_width::value, "handler widths do not match"); - try { handler_r.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - try { handler_w.resolve(); } - catch (const binding_type_exception &) { - osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); - throw; - } - install_readwrite_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r, handler_w); - } - - - template - void install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const READ &handler_r) - { - if constexpr (Width < AccessWidth) { - fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); - } else { - VPRINTF("address_space::install_read_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmask, m_addrchars, addrmirror, - 8 << Width, 8 << AccessWidth, - handler_r.name(), data_width() / 4, unitmask); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_read_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - if constexpr (Width == AccessWidth) { - auto hand_r = new handler_entry_read_delegate(this, handler_r); - hand_r->set_address_info(nstart, nmask); - m_root_read->populate(nstart, nend, nmirror, hand_r); - } else { - auto hand_r = new handler_entry_read_delegate(this, handler_r); - memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); - hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_read->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_r->unref(); - } - invalidate_caches(read_or_write::READ); - } - } - - template - void install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const WRITE &handler_w) - { - if constexpr (Width < AccessWidth) { - fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); - } else { - VPRINTF("address_space::install_write_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmask, m_addrchars, addrmirror, - 8 << Width, 8 << AccessWidth, - handler_w.name(), data_width() / 4, unitmask); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_write_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - if constexpr (Width == AccessWidth) { - auto hand_w = new handler_entry_write_delegate(this, handler_w); - hand_w->set_address_info(nstart, nmask); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } else { - auto hand_w = new handler_entry_write_delegate(this, handler_w); - memory_units_descriptor descriptor(AccessWidth, Endian, hand_w, nstart, nend, nmask, nunitmask, ncswidth); - hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_w->unref(); - } - invalidate_caches(read_or_write::WRITE); - } - } - - template - void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, - const READ &handler_r, - const WRITE &handler_w) - { - if constexpr (Width < AccessWidth) { - fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); - } else { - VPRINTF("address_space::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmask, m_addrchars, addrmirror, - 8 << Width, 8 << AccessWidth, - handler_r.name(), handler_w.name(), data_width() / 4, unitmask); - - offs_t nstart, nend, nmask, nmirror; - u64 nunitmask; - int ncswidth; - check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); - - if constexpr (Width == AccessWidth) { - auto hand_r = new handler_entry_read_delegate (this, handler_r); - hand_r->set_address_info(nstart, nmask); - m_root_read ->populate(nstart, nend, nmirror, hand_r); - - auto hand_w = new handler_entry_write_delegate(this, handler_w); - hand_w->set_address_info(nstart, nmask); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } else { - auto hand_r = new handler_entry_read_delegate (this, handler_r); - memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); - hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_read ->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_r->unref(); - - auto hand_w = new handler_entry_write_delegate(this, handler_w); - descriptor.set_subunit_handler(hand_w); - hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); - m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); - hand_w->unref(); - } - invalidate_caches(read_or_write::READWRITE); - } - } -}; - - +template void handler_entry_write::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write **dispatch, handler_entry::range *ranges) +{ + fatalerror("init_handlers called on non-view class\n"); +} + +template class handler_entry_read<0, 1, ENDIANNESS_LITTLE>; +template class handler_entry_read<0, 1, ENDIANNESS_BIG>; +template class handler_entry_read<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read<0, 0, ENDIANNESS_BIG>; +template class handler_entry_read<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read<1, 3, ENDIANNESS_BIG>; +template class handler_entry_read<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read<1, 0, ENDIANNESS_BIG>; +template class handler_entry_read<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read<1, -1, ENDIANNESS_BIG>; +template class handler_entry_read<2, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read<2, 3, ENDIANNESS_BIG>; +template class handler_entry_read<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read<2, 0, ENDIANNESS_BIG>; +template class handler_entry_read<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read<2, -1, ENDIANNESS_BIG>; +template class handler_entry_read<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read<2, -2, ENDIANNESS_BIG>; +template class handler_entry_read<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read<3, 0, ENDIANNESS_BIG>; +template class handler_entry_read<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read<3, -1, ENDIANNESS_BIG>; +template class handler_entry_read<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read<3, -2, ENDIANNESS_BIG>; +template class handler_entry_read<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read<3, -3, ENDIANNESS_BIG>; + +template class handler_entry_write<0, 1, ENDIANNESS_LITTLE>; +template class handler_entry_write<0, 1, ENDIANNESS_BIG>; +template class handler_entry_write<0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write<0, 0, ENDIANNESS_BIG>; +template class handler_entry_write<1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write<1, 3, ENDIANNESS_BIG>; +template class handler_entry_write<1, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write<1, 0, ENDIANNESS_BIG>; +template class handler_entry_write<1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write<1, -1, ENDIANNESS_BIG>; +template class handler_entry_write<2, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write<2, 3, ENDIANNESS_BIG>; +template class handler_entry_write<2, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write<2, 0, ENDIANNESS_BIG>; +template class handler_entry_write<2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write<2, -1, ENDIANNESS_BIG>; +template class handler_entry_write<2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write<2, -2, ENDIANNESS_BIG>; +template class handler_entry_write<3, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write<3, 0, ENDIANNESS_BIG>; +template class handler_entry_write<3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write<3, -1, ENDIANNESS_BIG>; +template class handler_entry_write<3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write<3, -2, ENDIANNESS_BIG>; +template class handler_entry_write<3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write<3, -3, ENDIANNESS_BIG>; //************************************************************************** // MEMORY MANAGER @@ -850,94 +295,6 @@ memory_manager::~memory_manager() { } -//------------------------------------------------- -// allocate - allocate memory spaces -//------------------------------------------------- - -void memory_manager::allocate(device_memory_interface &memory) -{ - for (int spacenum = 0; spacenum < memory.max_space_count(); ++spacenum) - { - // if there is a configuration for this space, we need an address space - address_space_config const *const spaceconfig = memory.space_config(spacenum); - if (spaceconfig) - { - int level = emu::detail::handler_entry_dispatch_level(spaceconfig->addr_width()); - // allocate one of the appropriate type - switch ((level << 8) | (spaceconfig->endianness() == ENDIANNESS_BIG ? 0x1000 : 0) |spaceconfig->data_width() | (spaceconfig->addr_shift() + 4)) - { - case 0x0000|0x000| 8|(4+1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000| 8|(4+1): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100| 8|(4+1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100| 8|(4+1): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000| 8|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000| 8|(4-0): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100| 8|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100| 8|(4-0): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|16|(4+3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|16|(4+3): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|16|(4+3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|16|(4+3): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|16|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|16|(4-0): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|16|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|16|(4-0): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|16|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|16|(4-1): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|16|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|16|(4-1): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|32|(4+3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|32|(4+3): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|32|(4+3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|32|(4+3): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|32|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|32|(4-0): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|32|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|32|(4-0): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|32|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|32|(4-1): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|32|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|32|(4-1): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|32|(4-2): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|32|(4-2): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|32|(4-2): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|32|(4-2): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|64|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|64|(4-0): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|64|(4-0): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|64|(4-0): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|64|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|64|(4-1): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|64|(4-1): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|64|(4-1): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|64|(4-2): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|64|(4-2): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|64|(4-2): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|64|(4-2): memory.allocate>(*this, spacenum); break; - - case 0x0000|0x000|64|(4-3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x000|64|(4-3): memory.allocate>(*this, spacenum); break; - case 0x0000|0x100|64|(4-3): memory.allocate>(*this, spacenum); break; - case 0x1000|0x100|64|(4-3): memory.allocate>(*this, spacenum); break; - - default: - throw emu_fatalerror("Invalid width %d/shift %d specified for address_space::allocate", spaceconfig->data_width(), spaceconfig->addr_shift()); - } - } - } -} - //------------------------------------------------- // initialize - initialize the memory system //------------------------------------------------- @@ -1021,12 +378,12 @@ void memory_manager::region_free(std::string name) //------------------------------------------------- -// anonymous_alloc - allocates a anonymousd memory zone +// anonymous_alloc - allocates a anonymous memory zone //------------------------------------------------- -void *memory_manager::anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end) +void *memory_manager::anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end, const std::string &key) { - std::string name = util::string_format("%x-%x", start, end); + std::string name = util::string_format("%s%x-%x", key, start, end); return allocate_memory(space.device(), space.spacenum(), name, width, bytes); } @@ -1146,58 +503,7 @@ address_space_config::address_space_config(const char *name, endianness_t endian } -//************************************************************************** -// ADDRESS SPACE -//************************************************************************** - -//------------------------------------------------- -// address_space - constructor -//------------------------------------------------- - -address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum) - : m_config(*memory.space_config(spacenum)), - m_device(memory.device()), - m_addrmask(make_bitmask(m_config.addr_width())), - m_logaddrmask(make_bitmask(m_config.logaddr_width())), - m_unmap(0), - m_spacenum(spacenum), - m_log_unmap(true), - m_name(memory.space_config(spacenum)->name()), - m_addrchars((m_config.addr_width() + 3) / 4), - m_logaddrchars((m_config.logaddr_width() + 3) / 4), - m_notifier_id(0), - m_in_notification(0), - m_manager(manager) -{ -} - - -//------------------------------------------------- -// ~address_space - destructor -//------------------------------------------------- - -address_space::~address_space() -{ - m_unmap_r->unref(); - m_unmap_w->unref(); - m_nop_r->unref(); - m_nop_w->unref(); -} - -//------------------------------------------------- -// adjust_addresses - adjust addresses for a -// given address space in a standard fashion -//------------------------------------------------- - -inline void address_space::adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror) -{ - // adjust start/end/mask values - mask &= m_addrmask; - start &= ~mirror & m_addrmask; - end &= ~mirror & m_addrmask; -} - -void address_space::check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth) +void address_space_installer::check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth) { if (addrstart > addrend) fatalerror("%s: In range %x-%x mask %x mirror %x select %x, start address is after the end address.\n", function, addrstart, addrend, addrmask, addrmirror, addrselect); @@ -1265,7 +571,7 @@ void address_space::check_optimize_all(const char *function, int width, offs_t a while (cmask != 0 && (cmask & block_mask) == 0) cmask >>= width; if (cmask != 0 && cmask != block_mask) - fatalerror("%s: In range %x-%x mask %x mirror %x select %x, the unitmask of %s has incorrect granularity for %d-bit chip selection.\n", function, addrstart, addrend, addrmask, addrmirror, addrselect, core_i64_hex_format(unitmask, 16), cswidth); + fatalerror("%s: In range %x-%x mask %x mirror %x select %x, the unitmask of %016x has incorrect granularity for %d-bit chip selection.\n", function, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth); } } @@ -1291,7 +597,7 @@ void address_space::check_optimize_all(const char *function, int width, offs_t a } } -void address_space::check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror) +void address_space_installer::check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror) { if (addrstart > addrend) fatalerror("%s: In range %x-%x mirror %x, start address is after the end address.\n", function, addrstart, addrend, addrmirror); @@ -1341,7 +647,7 @@ void address_space::check_optimize_mirror(const char *function, offs_t addrstart } } -void address_space::check_address(const char *function, offs_t addrstart, offs_t addrend) +void address_space_installer::check_address(const char *function, offs_t addrstart, offs_t addrend) { if (addrstart > addrend) fatalerror("%s: In range %x-%x, start address is after the end address.\n", function, addrstart, addrend); @@ -1358,141 +664,13 @@ void address_space::check_address(const char *function, offs_t addrstart, offs_t } -//------------------------------------------------- -// prepare_map - allocate the address map and -// walk through it to find implicit memory regions -// and identify shared regions -//------------------------------------------------- - -void address_space::prepare_map() -{ - memory_region *devregion = (m_spacenum == 0) ? m_device.memregion(DEVICE_SELF) : nullptr; - u32 devregionsize = (devregion != nullptr) ? devregion->bytes() : 0; - - // allocate the address map - m_map = std::make_unique(m_device, m_spacenum); - - // merge in the submaps - m_map->import_submaps(m_manager.machine(), m_device.owner() ? *m_device.owner() : m_device, data_width(), endianness(), addr_shift()); - - // extract global parameters specified by the map - m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0; - if (m_map->m_globalmask != 0) - { - if (m_map->m_globalmask & ~m_addrmask) - fatalerror("Can't set a global address mask of %08x on a %d-bits address width bus.\n", m_map->m_globalmask, addr_width()); - - m_addrmask = m_map->m_globalmask; - } - - // make a pass over the address map, adjusting for the device and getting memory pointers - for (address_map_entry &entry : m_map->m_entrylist) - { - // computed adjusted addresses first - adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror); - - // if we have a share entry, add it to our map - if (entry.m_share != nullptr) - { - // if we can't find it, add it to our map - std::string fulltag = entry.m_devbase.subtag(entry.m_share); - memory_share *share = m_manager.share_find(fulltag); - if (!share) - { - VPRINTF("Creating share '%s' of length 0x%X\n", fulltag.c_str(), entry.m_addrend + 1 - entry.m_addrstart); - share = m_manager.share_alloc(m_device, fulltag, m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); - } - else - { - std::string result = share->compare(m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); - if (!result.empty()) - fatalerror("%s\n", result); - } - entry.m_memory = share->ptr(); - } - - // if this is a ROM handler without a specified region and not shared, attach it to the implicit region - if (m_spacenum == AS_PROGRAM && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && entry.m_share == nullptr) - { - // make sure it fits within the memory region before doing so, however - if (entry.m_addrend < devregionsize) - { - entry.m_region = m_device.tag(); - entry.m_rgnoffs = address_to_byte(entry.m_addrstart); - } - } - - // validate adjusted addresses against implicit regions - if (entry.m_region != nullptr) - { - // determine full tag - std::string fulltag = entry.m_devbase.subtag(entry.m_region); - - // find the region - memory_region *region = m_manager.machine().root_device().memregion(fulltag); - if (region == nullptr) - fatalerror("device '%s' %s space memory map entry %X-%X references nonexistent region \"%s\"\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); - - // validate the region - if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes()) - fatalerror("device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes()); - - if (entry.m_share != nullptr) - fatalerror("device '%s' %s space memory map entry %X-%X has both .region() and .share()\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend); - } - - // convert any region-relative entries to their memory pointers - if (entry.m_region != nullptr) - { - // determine full tag - std::string fulltag = entry.m_devbase.subtag(entry.m_region); - - // set the memory address - entry.m_memory = m_manager.machine().root_device().memregion(fulltag)->base() + entry.m_rgnoffs; - } - - // allocate anonymous ram when needed - if (!entry.m_memory && (entry.m_read.m_type == AMH_RAM || entry.m_write.m_type == AMH_RAM)) - entry.m_memory = m_manager.anonymous_alloc(*this, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend); - } -} - - -//------------------------------------------------- -// populate_from_map - walk the map in reverse -// order and install the appropriate handler for -// each case -//------------------------------------------------- - -void address_space::populate_from_map(address_map *map) -{ - // no map specified, use the space-specific one - if (map == nullptr) - map = m_map.get(); - - // no map, nothing to do - if (map == nullptr) - return; - - // install the handlers, using the original, unadjusted memory map - for (const address_map_entry &entry : map->m_entrylist) { - // map both read and write halves - populate_map_entry(entry, read_or_write::READ); - populate_map_entry(entry, read_or_write::WRITE); - } - - if(VALIDATE_REFCOUNTS) - validate_reference_counts(); -} - - //------------------------------------------------- // populate_map_entry - map a single read or // write entry based on information from an // address map entry //------------------------------------------------- -void address_space::populate_map_entry(const address_map_entry &entry, read_or_write readorwrite) +void address_space_installer::populate_map_entry(const address_map_entry &entry, read_or_write readorwrite) { const map_handler_data &data = (readorwrite == read_or_write::READ) ? entry.m_read : entry.m_write; // based on the handler type, alter the bits, name, funcptr, and object @@ -1653,363 +831,77 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w case AMH_DEVICE_SUBMAP: throw emu_fatalerror("Internal mapping error: leftover mapping of '%s'.\n", data.m_tag); + + case AMH_VIEW: + if (readorwrite == read_or_write::READ) + install_view(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, *entry.m_view); + break; } } -memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 32-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus read tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 32-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 8-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 16-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tap, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tap, memory_passthrough_handler *mph) { fatalerror("Tryingw to install a 32-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } -memory_passthrough_handler *address_space::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +memory_passthrough_handler *address_space_installer::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) { fatalerror("Trying to install a 64-bits wide bus read/write tap in a %d-bits wide bus\n", data_width()); } - -//------------------------------------------------- -// get_handler_string - return a string -// describing the handler at a particular offset -//------------------------------------------------- - -template std::string address_space_specific::get_handler_string(read_or_write readorwrite, offs_t address) const -{ - if (readorwrite == read_or_write::READ) { - offs_t start, end; - handler_entry_read *handler; - m_root_read->lookup(address, start, end, handler); - return handler->name(); - } else { - offs_t start, end; - handler_entry_write *handler; - m_root_write->lookup(address, start, end, handler); - return handler->name(); - } -} - -template void address_space_specific::dump_maps(std::vector &read_map, std::vector &write_map) const -{ - read_map.clear(); - write_map.clear(); - m_root_read->dump_map(read_map); - m_root_write->dump_map(write_map); -} - - -//************************************************************************** -// DYNAMIC ADDRESS SPACE MAPPING -//************************************************************************** - -//------------------------------------------------- -// unmap - unmap a section of address space -//------------------------------------------------- - -template void address_space_specific::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) -{ - VPRINTF("address_space::unmap(%*x-%*x mirror=%*x, %s, %s)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmirror, - (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", - quiet ? "quiet" : "normal"); - - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("unmap_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - - // read space - if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) { - auto handler = static_cast *>(quiet ? m_nop_r : m_unmap_r); - handler->ref(); - m_root_read->populate(nstart, nend, nmirror, handler); - } - - // write space - if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) { - auto handler = static_cast *>(quiet ? m_nop_w : m_unmap_w); - handler->ref(); - m_root_write->populate(nstart, nend, nmirror, handler); - } - - invalidate_caches(readorwrite); -} - -//------------------------------------------------- -// install_read_tap - install a read tap on the bus -//------------------------------------------------- - -template memory_passthrough_handler *address_space_specific::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) -{ - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if(!mph) { - m_mphs.emplace_back(std::make_unique(*this)); - mph = m_mphs.back().get(); - } - - auto handler = new handler_entry_read_tap(this, *mph, name, tap); - m_root_read->populate_passthrough(nstart, nend, nmirror, handler); - handler->unref(); - - invalidate_caches(read_or_write::READ); - - return mph; -} - -//------------------------------------------------- -// install_write_tap - install a write tap on the bus -//------------------------------------------------- - -template memory_passthrough_handler *address_space_specific::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) -{ - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if(!mph) { - m_mphs.emplace_back(std::make_unique(*this)); - mph = m_mphs.back().get(); - } - - auto handler = new handler_entry_write_tap(this, *mph, name, tap); - m_root_write->populate_passthrough(nstart, nend, nmirror, handler); - handler->unref(); - - invalidate_caches(read_or_write::WRITE); - - return mph; -} -//------------------------------------------------- -// install_write_tap - install a read and a write tap on the bus -//------------------------------------------------- - -template memory_passthrough_handler *address_space_specific::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) -{ - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - if(!mph) { - m_mphs.emplace_back(std::make_unique(*this)); - mph = m_mphs.back().get(); - } - - auto rhandler = new handler_entry_read_tap (this, *mph, name, tapr); - m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler); - rhandler->unref(); - - auto whandler = new handler_entry_write_tap(this, *mph, name, tapw); - m_root_write->populate_passthrough(nstart, nend, nmirror, whandler); - whandler->unref(); - - invalidate_caches(read_or_write::READWRITE); - - return mph; -} - - - - - -//------------------------------------------------- -// install_device_delegate - install the memory map -// of a live device into this address space -//------------------------------------------------- - -template void address_space_specific::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth) -{ - check_address("install_device_delegate", addrstart, addrend); - address_map map(*this, addrstart, addrend, unitmask, cswidth, m_device, delegate); - map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift()); - populate_from_map(&map); -} - - - -//------------------------------------------------- -// install_readwrite_port - install a new I/O port -// handler into this address space -//------------------------------------------------- - -template void address_space_specific::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) -{ - VPRINTF("address_space::install_readwrite_port(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmirror, - rtag.empty() ? "(none)" : rtag.c_str(), wtag.empty() ? "(none)" : wtag.c_str()); - - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_readwrite_port", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - - // read handler - if (rtag != "") - { - // find the port - ioport_port *port = device().owner()->ioport(rtag); - if (port == nullptr) - throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag.c_str(), m_name, m_device.tag()); - - // map the range and set the ioport - auto hand_r = new handler_entry_read_ioport(this, port); - m_root_read->populate(nstart, nend, nmirror, hand_r); - } - - if (wtag != "") - { - // find the port - ioport_port *port = device().owner()->ioport(wtag); - if (port == nullptr) - fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag.c_str(), m_name, m_device.tag()); - - // map the range and set the ioport - auto hand_w = new handler_entry_write_ioport(this, port); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } - - invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); -} - - -//------------------------------------------------- -// install_bank_generic - install a range as -// mapping to a particular bank -//------------------------------------------------- - -template void address_space_specific::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) -{ - VPRINTF("address_space::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmirror, - (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)"); - - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - - // map the read bank - if (rbank != nullptr) - { - auto hand_r = new handler_entry_read_memory_bank(this, *rbank); - hand_r->set_address_info(nstart, nmask); - m_root_read->populate(nstart, nend, nmirror, hand_r); - } - - // map the write bank - if (wbank != nullptr) - { - auto hand_w = new handler_entry_write_memory_bank(this, *wbank); - hand_w->set_address_info(nstart, nmask); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } - - invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); -} - - -//------------------------------------------------- -// install_ram_generic - install a simple fixed -// RAM region into the given address space -//------------------------------------------------- - -template void address_space_specific::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) -{ - VPRINTF("address_space::install_ram_generic(%s-%s mirror=%s, %s, %p)\n", - m_addrchars, addrstart, m_addrchars, addrend, - m_addrchars, addrmirror, - (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", - baseptr); - - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_ram_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - - // map for read - if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) - { - auto hand_r = new handler_entry_read_memory(this, baseptr); - hand_r->set_address_info(nstart, nmask); - m_root_read->populate(nstart, nend, nmirror, hand_r); - } - - // map for write - if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) - { - auto hand_w = new handler_entry_write_memory(this, baseptr); - hand_w->set_address_info(nstart, nmask); - m_root_write->populate(nstart, nend, nmirror, hand_w); - } - - invalidate_caches(readorwrite); -} - - -//************************************************************************** -// MEMORY MAPPING HELPERS -//************************************************************************** - -int address_space::add_change_notifier(std::function n) -{ - int id = m_notifier_id++; - m_notifiers.emplace_back(notifier_t{ std::move(n), id }); - return id; -} - -void address_space::remove_change_notifier(int id) -{ - for(auto i = m_notifiers.begin(); i != m_notifiers.end(); i++) - if(i->m_id == id) { - m_notifiers.erase(i); - return; - } - fatalerror("Unknown notifier id %d, double remove?\n", id); -} - - //************************************************************************** // MEMORY BANK //************************************************************************** @@ -2141,4 +1033,3 @@ std::string memory_share::compare(u8 width, size_t bytes, endianness_t endiannes m_endianness == ENDIANNESS_LITTLE ? "little" : "big"); return ""; } - diff --git a/src/emu/emumem.h b/src/emu/emumem.h index e9a2fe0029a59..be26838b91e2f 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -80,9 +80,16 @@ struct data_accessors }; // a line in the memory structure dump +struct memory_entry_context { + memory_view *view; + bool disabled; + int slot; +}; + struct memory_entry { offs_t start, end; class handler_entry *entry; + std::vector context; }; @@ -480,6 +487,7 @@ class handler_entry static constexpr u32 F_DISPATCH = 0x00000001; // handler that forwards the access to other handlers static constexpr u32 F_UNITS = 0x00000002; // handler that merges/splits an access among multiple handlers (unitmask support) static constexpr u32 F_PASSTHROUGH = 0x00000004; // handler that passes through the request to another handler + static constexpr u32 F_VIEW = 0x00000008; // handler for a view (kinda like dispatch except not entirely) // Start/end of range flags static constexpr u8 START = 1; @@ -507,6 +515,7 @@ class handler_entry inline u32 flags() const { return m_flags; } inline bool is_dispatch() const { return m_flags & F_DISPATCH; } + inline bool is_view() const { return m_flags & F_VIEW; } inline bool is_units() const { return m_flags & F_UNITS; } inline bool is_passthrough() const { return m_flags & F_PASSTHROUGH; } @@ -516,6 +525,9 @@ class handler_entry virtual void enumerate_references(handler_entry::reflist &refs) const; u32 get_refcount() const { return m_refcount; } + virtual void select_a(int slot); + virtual void select_u(int slot); + protected: // Address range storage struct range { @@ -610,6 +622,9 @@ template class handler_entry_read // Return the internal structures of the root dispatch virtual const handler_entry_read *const *get_dispatch() const; + + virtual void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read **dispatch, handler_entry::range *ranges); + virtual handler_entry_read *dup(); }; // =====================-> The parent class of all write handlers @@ -682,6 +697,9 @@ template class handler_entry_writ // Return the internal structures of the root dispatch virtual const handler_entry_write *const *get_dispatch() const; + + virtual void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write **dispatch, handler_entry::range *ranges); + virtual handler_entry_write *dup(); }; // =====================-> Passthrough handler management structure @@ -1231,137 +1249,29 @@ class address_space_config // ======================> address_space -// address_space holds live information about an address space -class address_space -{ - friend class memory_bank; - friend class memory_block; - template friend class handler_entry_read_unmapped; - template friend class handler_entry_write_unmapped; - - struct notifier_t { - std::function m_notifier; - int m_id; - }; - -protected: - // construction/destruction - address_space(memory_manager &manager, device_memory_interface &memory, int spacenum); - +class address_space_installer { public: - virtual ~address_space(); - - // getters - device_t &device() const { return m_device; } - const char *name() const { return m_name; } - int spacenum() const { return m_spacenum; } - address_map *map() const { return m_map.get(); } - - template void cache(emu::detail::memory_access_cache &v) { - 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()]); - - v.set(this, get_cache_info()); - } - - template void specific(emu::detail::memory_access_specific &v) { - if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width())) - fatalerror("Requesting specific() with wrong level, bad address width (the config says %d)\n", m_config.addr_width()); - if(AddrShift != m_config.addr_shift()) - fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); - if(8 << Width != m_config.data_width()) - fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width()); - if(Endian != m_config.endianness()) - fatalerror("Requesting spefific() with endianness %s while the config says %s\n", - endianness_names[Endian], endianness_names[m_config.endianness()]); - - v.set(this, get_specific_info()); - } - - int add_change_notifier(std::function n); - void remove_change_notifier(int id); - - void invalidate_caches(read_or_write mode) { - if(u32(mode) & ~m_in_notification) { - u32 old = m_in_notification; - m_in_notification |= u32(mode); - for(const auto &n : m_notifiers) - n.m_notifier(mode); - m_in_notification = old; - } - } - - virtual void validate_reference_counts() const = 0; - - virtual void remove_passthrough(std::unordered_set &handlers) = 0; - + const address_space_config &space_config() const { return m_config; } int data_width() const { return m_config.data_width(); } int addr_width() const { return m_config.addr_width(); } int logaddr_width() const { return m_config.logaddr_width(); } int alignment() const { return m_config.alignment(); } endianness_t endianness() const { return m_config.endianness(); } int addr_shift() const { return m_config.addr_shift(); } - u64 unmap() const { return m_unmap; } bool is_octal() const { return m_config.is_octal(); } - offs_t addrmask() const { return m_addrmask; } - u8 addrchars() const { return m_addrchars; } - offs_t logaddrmask() const { return m_logaddrmask; } - u8 logaddrchars() const { return m_logaddrchars; } - - // debug helpers - virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0; - virtual void dump_maps(std::vector &read_map, std::vector &write_map) const = 0; - bool log_unmap() const { return m_log_unmap; } - void set_log_unmap(bool log) { m_log_unmap = log; } - - // general accessors - virtual void accessors(data_accessors &accessors) const = 0; - virtual void *get_read_ptr(offs_t address) const = 0; - virtual void *get_write_ptr(offs_t address) const = 0; - - // read accessors - virtual u8 read_byte(offs_t address) = 0; - virtual u16 read_word(offs_t address) = 0; - virtual u16 read_word(offs_t address, u16 mask) = 0; - virtual u16 read_word_unaligned(offs_t address) = 0; - virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0; - virtual u32 read_dword(offs_t address) = 0; - virtual u32 read_dword(offs_t address, u32 mask) = 0; - virtual u32 read_dword_unaligned(offs_t address) = 0; - virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0; - virtual u64 read_qword(offs_t address) = 0; - virtual u64 read_qword(offs_t address, u64 mask) = 0; - virtual u64 read_qword_unaligned(offs_t address) = 0; - virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0; - - // write accessors - virtual void write_byte(offs_t address, u8 data) = 0; - virtual void write_word(offs_t address, u16 data) = 0; - virtual void write_word(offs_t address, u16 data, u16 mask) = 0; - virtual void write_word_unaligned(offs_t address, u16 data) = 0; - virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0; - virtual void write_dword(offs_t address, u32 data) = 0; - virtual void write_dword(offs_t address, u32 data, u32 mask) = 0; - virtual void write_dword_unaligned(offs_t address, u32 data) = 0; - virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0; - virtual void write_qword(offs_t address, u64 data) = 0; - virtual void write_qword(offs_t address, u64 data, u64 mask) = 0; - virtual void write_qword_unaligned(offs_t address, u64 data) = 0; - virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; - // address-to-byte conversion helpers offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); } offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); } offs_t byte_to_address(offs_t address) const { return m_config.byte2addr(address); } offs_t byte_to_address_end(offs_t address) const { return m_config.byte2addr_end(address); } - // umap ranges (short form) + offs_t addrmask() const { return m_addrmask; } + u8 addrchars() const { return m_addrchars; } + offs_t logaddrmask() const { return m_logaddrmask; } + u8 logaddrchars() const { return m_logaddrchars; } + + // unmap ranges (short form) void unmap_read(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READ, false); } void unmap_write(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, false); } void unmap_readwrite(offs_t addrstart, offs_t addrend, offs_t addrmirror = 0) { unmap_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, false); } @@ -1427,6 +1337,9 @@ class address_space virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph = nullptr); + // install views + void install_view(offs_t addrstart, offs_t addrend, memory_view &view) { install_view(addrstart, addrend, 0, view); } + virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) = 0; // install new-style delegate handlers (short form) void install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) { install_read_handler(addrstart, addrend, 0, 0, 0, rhandler, unitmask, cswidth); } @@ -1586,6 +1499,154 @@ class address_space virtual void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; virtual void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) = 0; +protected: + virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0; + virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0; + virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0; + + void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite); + void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror) { + // adjust start/end/mask values + mask &= m_addrmask; + start &= ~mirror & m_addrmask; + end &= ~mirror & m_addrmask; + } + + void check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth); + void check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror); + void check_address(const char *function, offs_t addrstart, offs_t addrend); + + address_space_installer(const address_space_config &config, memory_manager &manager) + : m_config(config), + m_manager(manager), + m_addrmask(make_bitmask(m_config.addr_width())), + m_logaddrmask(make_bitmask(m_config.logaddr_width())), + m_addrchars((m_config.addr_width() + 3) / 4), + m_logaddrchars((m_config.logaddr_width() + 3) / 4) + {} + + const address_space_config &m_config; // configuration of this space + memory_manager & m_manager; // reference to the owning manager + offs_t m_addrmask; // physical address mask + offs_t m_logaddrmask; // logical address mask + u8 m_addrchars; // number of characters to use for physical addresses + u8 m_logaddrchars; // number of characters to use for logical addresses +}; + +// address_space holds live information about an address space +class address_space : public address_space_installer +{ + friend class memory_bank; + friend class memory_block; + template friend class handler_entry_read_unmapped; + template friend class handler_entry_write_unmapped; + + struct notifier_t { + std::function m_notifier; + int m_id; + }; + +protected: + // construction/destruction + address_space(memory_manager &manager, device_memory_interface &memory, int spacenum); + +public: + virtual ~address_space(); + + // getters + device_t &device() const { return m_device; } + const char *name() const { return m_name; } + int spacenum() const { return m_spacenum; } + address_map *map() const { return m_map.get(); } + + template void cache(emu::detail::memory_access_cache &v) { + 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()]); + + v.set(this, get_cache_info()); + } + + template void specific(emu::detail::memory_access_specific &v) { + if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width())) + fatalerror("Requesting specific() with wrong level, bad address width (the config says %d)\n", m_config.addr_width()); + if(AddrShift != m_config.addr_shift()) + fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift()); + if(8 << Width != m_config.data_width()) + fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width()); + if(Endian != m_config.endianness()) + fatalerror("Requesting spefific() with endianness %s while the config says %s\n", + endianness_names[Endian], endianness_names[m_config.endianness()]); + + v.set(this, get_specific_info()); + } + + int add_change_notifier(std::function n); + void remove_change_notifier(int id); + + void invalidate_caches(read_or_write mode) { + if(u32(mode) & ~m_in_notification) { + u32 old = m_in_notification; + m_in_notification |= u32(mode); + for(const auto &n : m_notifiers) + n.m_notifier(mode); + m_in_notification = old; + } + } + + virtual void validate_reference_counts() const = 0; + + virtual void remove_passthrough(std::unordered_set &handlers) = 0; + + u64 unmap() const { return m_unmap; } + + memory_passthrough_handler *make_mph(); + + // debug helpers + virtual std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const = 0; + virtual void dump_maps(std::vector &read_map, std::vector &write_map) const = 0; + bool log_unmap() const { return m_log_unmap; } + void set_log_unmap(bool log) { m_log_unmap = log; } + + // general accessors + virtual void accessors(data_accessors &accessors) const = 0; + virtual void *get_read_ptr(offs_t address) const = 0; + virtual void *get_write_ptr(offs_t address) const = 0; + + // read accessors + virtual u8 read_byte(offs_t address) = 0; + virtual u16 read_word(offs_t address) = 0; + virtual u16 read_word(offs_t address, u16 mask) = 0; + virtual u16 read_word_unaligned(offs_t address) = 0; + virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0; + virtual u32 read_dword(offs_t address) = 0; + virtual u32 read_dword(offs_t address, u32 mask) = 0; + virtual u32 read_dword_unaligned(offs_t address) = 0; + virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0; + virtual u64 read_qword(offs_t address) = 0; + virtual u64 read_qword(offs_t address, u64 mask) = 0; + virtual u64 read_qword_unaligned(offs_t address) = 0; + virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0; + + // write accessors + virtual void write_byte(offs_t address, u8 data) = 0; + virtual void write_word(offs_t address, u16 data) = 0; + virtual void write_word(offs_t address, u16 data, u16 mask) = 0; + virtual void write_word_unaligned(offs_t address, u16 data) = 0; + virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0; + virtual void write_dword(offs_t address, u32 data) = 0; + virtual void write_dword(offs_t address, u32 data, u32 mask) = 0; + virtual void write_dword_unaligned(offs_t address, u32 data) = 0; + virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0; + virtual void write_qword(offs_t address, u64 data) = 0; + virtual void write_qword(offs_t address, u64 data, u64 mask) = 0; + virtual void write_qword_unaligned(offs_t address, u64 data) = 0; + virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0; + // setup void prepare_map(); void populate_from_map(address_map *map = nullptr); @@ -1593,32 +1654,23 @@ class address_space template handler_entry_read_unmapped *get_unmap_r() const { return static_cast *>(m_unmap_r); } template handler_entry_write_unmapped *get_unmap_w() const { return static_cast *>(m_unmap_w); } + handler_entry *unmap_r() const { return m_unmap_r; } + handler_entry *unmap_w() const { return m_unmap_w; } + handler_entry *nop_r() const { return m_nop_r; } + handler_entry *nop_w() const { return m_nop_w; } + protected: // internal helpers virtual std::pair get_cache_info() = 0; virtual std::pair get_specific_info() = 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; - virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) = 0; - virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) = 0; - void adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror); - void check_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth); - void check_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror); - void check_address(const char *function, offs_t addrstart, offs_t addrend); - // private state - const address_space_config &m_config; // configuration of this space device_t & m_device; // reference to the owning device std::unique_ptr m_map; // original memory map - offs_t m_addrmask; // physical address mask - offs_t m_logaddrmask; // logical address mask u64 m_unmap; // unmapped value int m_spacenum; // address space index bool m_log_unmap; // log unmapped accesses in this space? const char * m_name; // friendly name of the address space - u8 m_addrchars; // number of characters to use for physical addresses - u8 m_logaddrchars; // number of characters to use for logical addresses handler_entry *m_unmap_r; handler_entry *m_unmap_w; @@ -1631,7 +1683,6 @@ class address_space std::vector m_notifiers; // notifier list for address map change int m_notifier_id; // next notifier id u32 m_in_notification; // notification(s) currently being done - memory_manager & m_manager; // reference to the owning manager }; @@ -1748,6 +1799,79 @@ class memory_region +// ======================> memory_view + +// a memory view allows switching between submaps in the map +class memory_view +{ + template friend class address_space_specific; + template friend class memory_view_entry_specific; + template friend class handler_entry_write_dispatch; + template friend class handler_entry_read_dispatch; + friend class memory_view_entry; + friend class address_map_entry; + friend class address_map; + + DISABLE_COPYING(memory_view); + +public: + class memory_view_entry : public address_space_installer { + public: + virtual ~memory_view_entry() = default; + + address_map_entry &operator()(offs_t start, offs_t end); + + virtual void populate_from_map(address_map *map = nullptr) = 0; + + std::string key() const; + + protected: + memory_view &m_view; + std::unique_ptr m_map; + int m_id; + + memory_view_entry(const address_space_config &config, memory_manager &manager, memory_view &view, int id); + + void check_range_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth); + void check_range_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror); + void check_range_address(const char *function, offs_t addrstart, offs_t addrend); + }; + + memory_view(device_t &device, std::string name); + + memory_view_entry &operator[](int slot); + + void select(int entry); + void disable(); + + const std::string &name() const { return m_name; } + +private: + + device_t & m_device; + std::string m_name; + std::map m_entry_mapping; + std::vector> m_entries; + const address_space_config * m_config; + offs_t m_addrstart; + offs_t m_addrend; + address_space * m_space; + handler_entry * m_handler_read; + handler_entry * m_handler_write; + std::function m_select_a; + std::function m_select_u; + int m_cur_id; + int m_cur_slot; + std::string m_context; + + void initialize_from_address_map(offs_t addrstart, offs_t addrend, const address_space_config &config); + std::pair make_handlers(address_space &space, offs_t addrstart, offs_t addrend); + void make_subdispatch(std::string context); + int id_to_slot(int id) const; +}; + + + // ======================> memory_manager // holds internal state for the memory system @@ -1772,7 +1896,7 @@ class memory_manager const std::unordered_map> &shares() const { return m_sharelist; } // anonymous memory zones - void *anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end); + void *anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end, const std::string &key = ""); // shares memory_share *share_alloc(device_t &dev, std::string name, u8 width, size_t bytes, endianness_t endianness); diff --git a/src/emu/emumem_aspace.cpp b/src/emu/emumem_aspace.cpp new file mode 100644 index 0000000000000..f9029b9422f68 --- /dev/null +++ b/src/emu/emumem_aspace.cpp @@ -0,0 +1,1200 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,Olivier Galibert +/*************************************************************************** + + emumem.cpp + + Functions which handle device memory access. + Address-space related functions + +***************************************************************************/ + +#include "emu.h" +#include +#include +#include "emuopts.h" +#include "debug/debugcpu.h" + +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_hem.h" +#include "emumem_hedp.h" +#include "emumem_heun.h" +#include "emumem_heu.h" +#include "emumem_hedr.h" +#include "emumem_hedw.h" +#include "emumem_hep.h" +#include "emumem_het.h" + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE 0 + +#if VERBOSE +template static void VPRINTF(Format &&fmt, Params &&...args) +{ + util::stream_format(std::cerr, std::forward(fmt), std::forward(args)...); +} +#else +template static void VPRINTF(Format &&, Params &&...) {} +#endif + +#define VALIDATE_REFCOUNTS 0 + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +namespace { + +template struct handler_width; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +} // anonymous namespace + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> address_space_specific + +// this is a derived class of address_space with specific width, endianness, and table size +template +class address_space_specific : public address_space +{ + using uX = typename emu::detail::handler_entry_size::uX; + using NativeType = uX; + using this_type = address_space_specific; + + // constants describing the native size + static constexpr u32 NATIVE_BYTES = 1 << Width; + static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; + static constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; + + static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } + +public: + const handler_entry_read *const *m_dispatch_read; + const handler_entry_write *const *m_dispatch_write; + + std::string get_handler_string(read_or_write readorwrite, offs_t byteaddress) const override; + void dump_maps(std::vector &read_map, std::vector &write_map) const override; + + void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) override; + void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) override; + void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) override; + void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) override; + void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask = 0, int cswidth = 0) override; + void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) override; + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + using address_space::install_read_tap; + using address_space::install_write_tap; + using address_space::install_readwrite_tap; + + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) override; + + // construction/destruction + address_space_specific(memory_manager &manager, device_memory_interface &memory, int spacenum, int address_width) + : address_space(manager, memory, spacenum) + { + m_unmap_r = new handler_entry_read_unmapped (this); + m_unmap_w = new handler_entry_write_unmapped(this); + m_nop_r = new handler_entry_read_nop (this); + m_nop_w = new handler_entry_write_nop(this); + + handler_entry::range r{ 0, 0xffffffff >> (32 - address_width) }; + + switch (address_width) { + case 1: m_root_read = new handler_entry_read_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(1, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 2: m_root_read = new handler_entry_read_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(2, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 3: m_root_read = new handler_entry_read_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< std::max(3, Width), Width, AddrShift, Endian>(this, r, nullptr); break; + case 4: m_root_read = new handler_entry_read_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 4, Width, AddrShift, Endian>(this, r, nullptr); break; + case 5: m_root_read = new handler_entry_read_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 5, Width, AddrShift, Endian>(this, r, nullptr); break; + case 6: m_root_read = new handler_entry_read_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 6, Width, AddrShift, Endian>(this, r, nullptr); break; + case 7: m_root_read = new handler_entry_read_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 7, Width, AddrShift, Endian>(this, r, nullptr); break; + case 8: m_root_read = new handler_entry_read_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 8, Width, AddrShift, Endian>(this, r, nullptr); break; + case 9: m_root_read = new handler_entry_read_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch< 9, Width, AddrShift, Endian>(this, r, nullptr); break; + case 10: m_root_read = new handler_entry_read_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<10, Width, AddrShift, Endian>(this, r, nullptr); break; + case 11: m_root_read = new handler_entry_read_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<11, Width, AddrShift, Endian>(this, r, nullptr); break; + case 12: m_root_read = new handler_entry_read_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<12, Width, AddrShift, Endian>(this, r, nullptr); break; + case 13: m_root_read = new handler_entry_read_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<13, Width, AddrShift, Endian>(this, r, nullptr); break; + case 14: m_root_read = new handler_entry_read_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<14, Width, AddrShift, Endian>(this, r, nullptr); break; + case 15: m_root_read = new handler_entry_read_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<15, Width, AddrShift, Endian>(this, r, nullptr); break; + case 16: m_root_read = new handler_entry_read_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<16, Width, AddrShift, Endian>(this, r, nullptr); break; + case 17: m_root_read = new handler_entry_read_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<17, Width, AddrShift, Endian>(this, r, nullptr); break; + case 18: m_root_read = new handler_entry_read_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<18, Width, AddrShift, Endian>(this, r, nullptr); break; + case 19: m_root_read = new handler_entry_read_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<19, Width, AddrShift, Endian>(this, r, nullptr); break; + case 20: m_root_read = new handler_entry_read_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<20, Width, AddrShift, Endian>(this, r, nullptr); break; + case 21: m_root_read = new handler_entry_read_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<21, Width, AddrShift, Endian>(this, r, nullptr); break; + case 22: m_root_read = new handler_entry_read_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<22, Width, AddrShift, Endian>(this, r, nullptr); break; + case 23: m_root_read = new handler_entry_read_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<23, Width, AddrShift, Endian>(this, r, nullptr); break; + case 24: m_root_read = new handler_entry_read_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<24, Width, AddrShift, Endian>(this, r, nullptr); break; + case 25: m_root_read = new handler_entry_read_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<25, Width, AddrShift, Endian>(this, r, nullptr); break; + case 26: m_root_read = new handler_entry_read_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<26, Width, AddrShift, Endian>(this, r, nullptr); break; + case 27: m_root_read = new handler_entry_read_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<27, Width, AddrShift, Endian>(this, r, nullptr); break; + case 28: m_root_read = new handler_entry_read_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<28, Width, AddrShift, Endian>(this, r, nullptr); break; + case 29: m_root_read = new handler_entry_read_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<29, Width, AddrShift, Endian>(this, r, nullptr); break; + case 30: m_root_read = new handler_entry_read_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<30, Width, AddrShift, Endian>(this, r, nullptr); break; + case 31: m_root_read = new handler_entry_read_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<31, Width, AddrShift, Endian>(this, r, nullptr); break; + case 32: m_root_read = new handler_entry_read_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); m_root_write = new handler_entry_write_dispatch<32, Width, AddrShift, Endian>(this, r, nullptr); break; + default: fatalerror("Unhandled address bus width %d\n", address_width); + } + + m_dispatch_read = m_root_read ->get_dispatch(); + m_dispatch_write = m_root_write->get_dispatch(); + } + + std::pair get_cache_info() override { + std::pair rw; + rw.first = m_root_read; + rw.second = m_root_write; + return rw; + } + + std::pair get_specific_info() override { + std::pair rw; + rw.first = m_dispatch_read; + rw.second = m_dispatch_write; + return rw; + } + + void delayed_ref(handler_entry *e) { + e->ref(); + m_delayed_unrefs.insert(e); + } + + void delayed_unref(handler_entry *e) { + m_delayed_unrefs.erase(m_delayed_unrefs.find(e)); + e->unref(); + } + + void validate_reference_counts() const override { + handler_entry::reflist refs; + refs.add(m_root_read); + refs.add(m_root_write); + refs.add(m_unmap_r); + refs.add(m_unmap_w); + refs.add(m_nop_r); + refs.add(m_nop_w); + for(handler_entry *e : m_delayed_unrefs) + refs.add(e); + refs.propagate(); + refs.check(); + } + + virtual void remove_passthrough(std::unordered_set &handlers) override { + invalidate_caches(read_or_write::READWRITE); + m_root_read->detach(handlers); + m_root_write->detach(handlers); + } + + // generate accessor table + virtual void accessors(data_accessors &accessors) const override + { + accessors.read_byte = reinterpret_cast(&read_byte_static); + accessors.read_word = reinterpret_cast(&read_word_static); + accessors.read_word_masked = reinterpret_cast(&read_word_masked_static); + accessors.read_dword = reinterpret_cast(&read_dword_static); + accessors.read_dword_masked = reinterpret_cast(&read_dword_masked_static); + accessors.read_qword = reinterpret_cast(&read_qword_static); + accessors.read_qword_masked = reinterpret_cast(&read_qword_masked_static); + accessors.write_byte = reinterpret_cast(&write_byte_static); + accessors.write_word = reinterpret_cast(&write_word_static); + accessors.write_word_masked = reinterpret_cast(&write_word_masked_static); + accessors.write_dword = reinterpret_cast(&write_dword_static); + accessors.write_dword_masked = reinterpret_cast(&write_dword_masked_static); + accessors.write_qword = reinterpret_cast(&write_qword_static); + accessors.write_qword_masked = reinterpret_cast(&write_qword_masked_static); + } + + // return a pointer to the read bank, or nullptr if none + virtual void *get_read_ptr(offs_t address) const override + { + return m_root_read->get_ptr(address); + } + + // return a pointer to the write bank, or nullptr if none + virtual void *get_write_ptr(offs_t address) const override + { + return m_root_write->get_ptr(address); + } + + // native read + NativeType read_native(offs_t offset, NativeType mask) + { + return dispatch_read(offs_t(-1), offset & m_addrmask, mask, m_dispatch_read); + } + + // mask-less native read + NativeType read_native(offs_t offset) + { + return dispatch_read(offs_t(-1), offset & m_addrmask, uX(0xffffffffffffffffU), m_dispatch_read); + } + + // native write + void write_native(offs_t offset, NativeType data, NativeType mask) + { + dispatch_write(offs_t(-1), offset & m_addrmask, data, mask, m_dispatch_write); + } + + // mask-less native write + void write_native(offs_t offset, NativeType data) + { + dispatch_write(offs_t(-1), offset & m_addrmask, data, uX(0xffffffffffffffffU), m_dispatch_write); + } + + // virtual access to these functions + u8 read_byte(offs_t address) override { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); } + u16 read_word(offs_t address) override { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u16 read_word_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); } + u16 read_word_unaligned(offs_t address, u16 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword(offs_t address) override { return Width == 2 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u32 read_dword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffff); } + u32 read_dword_unaligned(offs_t address, u32 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword(offs_t address) override { return Width == 3 ? read_native(address & ~NATIVE_MASK) : memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + u64 read_qword_unaligned(offs_t address) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffffffffffffffffU); } + u64 read_qword_unaligned(offs_t address, u64 mask) override { return memory_read_generic([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, mask); } + + void write_byte(offs_t address, u8 data) override { if (Width == 0) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xff); } + void write_word(offs_t address, u16 data) override { if (Width == 1) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_word_unaligned(offs_t address, u16 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffff); } + void write_word_unaligned(offs_t address, u16 data, u16 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword(offs_t address, u32 data) override { if (Width == 2) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_dword_unaligned(offs_t address, u32 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffff); } + void write_dword_unaligned(offs_t address, u32 data, u32 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword(offs_t address, u64 data) override { if (Width == 3) write_native(address & ~NATIVE_MASK, data); else memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + void write_qword_unaligned(offs_t address, u64 data) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + void write_qword_unaligned(offs_t address, u64 data, u64 mask) override { memory_write_generic([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); } + + // static access to these functions + static u8 read_byte_static(this_type &space, offs_t address) { return Width == 0 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xff); } + static u16 read_word_static(this_type &space, offs_t address) { return Width == 1 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffff); } + static u16 read_word_masked_static(this_type &space, offs_t address, u16 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static u32 read_dword_static(this_type &space, offs_t address) { return Width == 2 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffff); } + static u32 read_dword_masked_static(this_type &space, offs_t address, u32 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static u64 read_qword_static(this_type &space, offs_t address) { return Width == 3 ? space.read_native(address & ~NATIVE_MASK) : memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, 0xffffffffffffffffU); } + static u64 read_qword_masked_static(this_type &space, offs_t address, u64 mask) { return memory_read_generic([&space](offs_t offset, NativeType mask) -> NativeType { return space.read_native(offset, mask); }, address, mask); } + static void write_byte_static(this_type &space, offs_t address, u8 data) { if (Width == 0) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xff); } + static void write_word_static(this_type &space, offs_t address, u16 data) { if (Width == 1) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffff); } + static void write_word_masked_static(this_type &space, offs_t address, u16 data, u16 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + static void write_dword_static(this_type &space, offs_t address, u32 data) { if (Width == 2) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffff); } + static void write_dword_masked_static(this_type &space, offs_t address, u32 data, u32 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + static void write_qword_static(this_type &space, offs_t address, u64 data) { if (Width == 3) space.write_native(address & ~NATIVE_MASK, data); else memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, 0xffffffffffffffffU); } + static void write_qword_masked_static(this_type &space, offs_t address, u64 data, u64 mask) { memory_write_generic([&space](offs_t offset, NativeType data, NativeType mask) { space.write_native(offset, data, mask); }, address, data, mask); } + + handler_entry_read *m_root_read; + handler_entry_write *m_root_write; + + std::unordered_set m_delayed_unrefs; + +private: + template + void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r) + { + try { handler_r.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_read_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r); + } + + template + void install_write_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, WRITE &handler_w) + { + try { handler_w.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_write_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_w); + } + + template + void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r, WRITE &handler_w) + { + static_assert(handler_width::value == handler_width::value, "handler widths do not match"); + try { handler_r.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + try { handler_w.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_readwrite_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r, handler_w); + } + + template + void install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const READ &handler_r) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("address_space::install_read_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_r.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_read_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_r = new handler_entry_read_delegate(this, handler_r); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); + } else { + auto hand_r = new handler_entry_read_delegate(this, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_read->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); + } + invalidate_caches(read_or_write::READ); + } + } + + template + void install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + const WRITE &handler_w) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("address_space::install_write_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_w.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_write_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_w = new handler_entry_write_delegate(this, handler_w); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); + } else { + auto hand_w = new handler_entry_write_delegate(this, handler_w); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_w, nstart, nend, nmask, nunitmask, ncswidth); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); + } + invalidate_caches(read_or_write::WRITE); + } + } + + template + void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + const READ &handler_r, + const WRITE &handler_w) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("address_space::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_r.name(), handler_w.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_r = new handler_entry_read_delegate (this, handler_r); + hand_r->set_address_info(nstart, nmask); + m_root_read ->populate(nstart, nend, nmirror, hand_r); + + auto hand_w = new handler_entry_write_delegate(this, handler_w); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); + } else { + auto hand_r = new handler_entry_read_delegate (this, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_read ->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); + + auto hand_w = new handler_entry_write_delegate(this, handler_w); + descriptor.set_subunit_handler(hand_w); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + m_root_write->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); + } + invalidate_caches(read_or_write::READWRITE); + } + } +}; + + + +//------------------------------------------------- +// allocate - allocate memory spaces +//------------------------------------------------- + +void memory_manager::allocate(device_memory_interface &memory) +{ + for (int spacenum = 0; spacenum < memory.max_space_count(); ++spacenum) + { + // if there is a configuration for this space, we need an address space + address_space_config const *const spaceconfig = memory.space_config(spacenum); + if (spaceconfig) + { + int level = emu::detail::handler_entry_dispatch_level(spaceconfig->addr_width()); + // allocate one of the appropriate type + switch ((level << 8) | (spaceconfig->endianness() == ENDIANNESS_BIG ? 0x1000 : 0) |spaceconfig->data_width() | (spaceconfig->addr_shift() + 4)) + { + case 0x0000|0x000| 8|(4+1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000| 8|(4+1): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100| 8|(4+1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100| 8|(4+1): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000| 8|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000| 8|(4-0): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100| 8|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100| 8|(4-0): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|16|(4+3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|16|(4+3): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|16|(4+3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|16|(4+3): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|16|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|16|(4-0): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|16|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|16|(4-0): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|16|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|16|(4-1): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|16|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|16|(4-1): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|32|(4+3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|32|(4+3): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|32|(4+3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|32|(4+3): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|32|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|32|(4-0): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|32|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|32|(4-0): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|32|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|32|(4-1): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|32|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|32|(4-1): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|32|(4-2): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|32|(4-2): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|32|(4-2): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|32|(4-2): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|64|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|64|(4-0): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|64|(4-0): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|64|(4-0): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|64|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|64|(4-1): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|64|(4-1): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|64|(4-1): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|64|(4-2): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|64|(4-2): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|64|(4-2): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|64|(4-2): memory.allocate>(*this, spacenum); break; + + case 0x0000|0x000|64|(4-3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x000|64|(4-3): memory.allocate>(*this, spacenum); break; + case 0x0000|0x100|64|(4-3): memory.allocate>(*this, spacenum); break; + case 0x1000|0x100|64|(4-3): memory.allocate>(*this, spacenum); break; + + default: + throw emu_fatalerror("Invalid width %d/shift %d specified for address_space::allocate", spaceconfig->data_width(), spaceconfig->addr_shift()); + } + } + } +} + +//************************************************************************** +// ADDRESS SPACE +//************************************************************************** + +//------------------------------------------------- +// address_space - constructor +//------------------------------------------------- + +address_space::address_space(memory_manager &manager, device_memory_interface &memory, int spacenum) + : address_space_installer(*memory.space_config(spacenum), manager), + m_device(memory.device()), + m_unmap(0), + m_spacenum(spacenum), + m_log_unmap(true), + m_name(memory.space_config(spacenum)->name()), + m_notifier_id(0), + m_in_notification(0) +{ +} + + +//------------------------------------------------- +// ~address_space - destructor +//------------------------------------------------- + +address_space::~address_space() +{ + m_unmap_r->unref(); + m_unmap_w->unref(); + m_nop_r->unref(); + m_nop_w->unref(); +} + + +//------------------------------------------------- +// prepare_map - allocate the address map and +// walk through it to find implicit memory regions +// and identify shared regions +//------------------------------------------------- + +void address_space::prepare_map() +{ + memory_region *devregion = (m_spacenum == 0) ? m_device.memregion(DEVICE_SELF) : nullptr; + u32 devregionsize = (devregion != nullptr) ? devregion->bytes() : 0; + + // allocate the address map + m_map = std::make_unique(m_device, m_spacenum); + + // merge in the submaps + m_map->import_submaps(m_manager.machine(), m_device.owner() ? *m_device.owner() : m_device, data_width(), endianness(), addr_shift()); + + // extract global parameters specified by the map + m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0; + if (m_map->m_globalmask != 0) + { + if (m_map->m_globalmask & ~m_addrmask) + fatalerror("Can't set a global address mask of %08x on a %d-bits address width bus.\n", m_map->m_globalmask, addr_width()); + + m_addrmask = m_map->m_globalmask; + } + + // make a pass over the address map, adjusting for the device and getting memory pointers + for (address_map_entry &entry : m_map->m_entrylist) + { + // computed adjusted addresses first + adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror); + + // if we have a share entry, add it to our map + if (entry.m_share != nullptr) + { + // if we can't find it, add it to our map + std::string fulltag = entry.m_devbase.subtag(entry.m_share); + memory_share *share = m_manager.share_find(fulltag); + if (!share) + { + VPRINTF("Creating share '%s' of length 0x%X\n", fulltag, entry.m_addrend + 1 - entry.m_addrstart); + share = m_manager.share_alloc(m_device, fulltag, m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); + } + else + { + std::string result = share->compare(m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); + if (!result.empty()) + fatalerror("%s\n", result); + } + entry.m_memory = share->ptr(); + } + + // if this is a ROM handler without a specified region and not shared, attach it to the implicit region + if (m_spacenum == AS_PROGRAM && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && entry.m_share == nullptr) + { + // make sure it fits within the memory region before doing so, however + if (entry.m_addrend < devregionsize) + { + entry.m_region = m_device.tag(); + entry.m_rgnoffs = address_to_byte(entry.m_addrstart); + } + } + + // validate adjusted addresses against implicit regions + if (entry.m_region != nullptr) + { + // determine full tag + std::string fulltag = entry.m_devbase.subtag(entry.m_region); + + // find the region + memory_region *region = m_manager.machine().root_device().memregion(fulltag); + if (region == nullptr) + fatalerror("device '%s' %s space memory map entry %X-%X references nonexistent region \"%s\"\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); + + // validate the region + if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes()) + fatalerror("device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes()); + + if (entry.m_share != nullptr) + fatalerror("device '%s' %s space memory map entry %X-%X has both .region() and .share()\n", m_device.tag(), m_name, entry.m_addrstart, entry.m_addrend); + } + + // convert any region-relative entries to their memory pointers + if (entry.m_region != nullptr) + { + // determine full tag + std::string fulltag = entry.m_devbase.subtag(entry.m_region); + + // set the memory address + entry.m_memory = m_manager.machine().root_device().memregion(fulltag)->base() + entry.m_rgnoffs; + } + + // allocate anonymous ram when needed + if (!entry.m_memory && (entry.m_read.m_type == AMH_RAM || entry.m_write.m_type == AMH_RAM)) + entry.m_memory = m_manager.anonymous_alloc(*this, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend); + } +} + + +//------------------------------------------------- +// populate_from_map - walk the map in reverse +// order and install the appropriate handler for +// each case +//------------------------------------------------- + +void address_space::populate_from_map(address_map *map) +{ + // no map specified, use the space-specific one + if (map == nullptr) + map = m_map.get(); + + // no map, nothing to do + if (map == nullptr) + return; + + // install the handlers, using the original, unadjusted memory map + for (const address_map_entry &entry : map->m_entrylist) { + // map both read and write halves + populate_map_entry(entry, read_or_write::READ); + populate_map_entry(entry, read_or_write::WRITE); + } + + if (VALIDATE_REFCOUNTS) + validate_reference_counts(); +} + +//------------------------------------------------- +// get_handler_string - return a string +// describing the handler at a particular offset +//------------------------------------------------- + +template std::string address_space_specific::get_handler_string(read_or_write readorwrite, offs_t address) const +{ + if (readorwrite == read_or_write::READ) { + offs_t start, end; + handler_entry_read *handler; + m_root_read->lookup(address, start, end, handler); + return handler->name(); + } else { + offs_t start, end; + handler_entry_write *handler; + m_root_write->lookup(address, start, end, handler); + return handler->name(); + } +} + +template void address_space_specific::dump_maps(std::vector &read_map, std::vector &write_map) const +{ + read_map.clear(); + write_map.clear(); + m_root_read->dump_map(read_map); + m_root_write->dump_map(write_map); +} + + +//************************************************************************** +// DYNAMIC ADDRESS SPACE MAPPING +//************************************************************************** + +//------------------------------------------------- +// unmap - unmap a section of address space +//------------------------------------------------- + +template void address_space_specific::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) +{ + VPRINTF("address_space::unmap(%*x-%*x mirror=%*x, %s, %s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", + quiet ? "quiet" : "normal"); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("unmap_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + // read space + if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_nop_r : m_unmap_r); + handler->ref(); + m_root_read->populate(nstart, nend, nmirror, handler); + } + + // write space + if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_nop_w : m_unmap_w); + handler->ref(); + m_root_write->populate(nstart, nend, nmirror, handler); + } + + invalidate_caches(readorwrite); +} + +//------------------------------------------------- +// install_view - install a view on the bus +//------------------------------------------------- +template void address_space_specific::install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_view", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + auto handlers = view.make_handlers(*this, addrstart, addrend); + m_root_read ->populate(nstart, nend, nmirror, static_cast *>(handlers.first)); + m_root_write->populate(nstart, nend, nmirror, static_cast *>(handlers.second)); + view.make_subdispatch(""); // Must be called after populate +} + +memory_passthrough_handler *address_space::make_mph() +{ + m_mphs.emplace_back(std::make_unique(*this)); + return m_mphs.back().get(); +} + +//------------------------------------------------- +// install_read_tap - install a read tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = make_mph(); + + auto handler = new handler_entry_read_tap(this, *mph, name, tap); + m_root_read->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::READ); + + return mph; +} + +//------------------------------------------------- +// install_write_tap - install a write tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = make_mph(); + + auto handler = new handler_entry_write_tap(this, *mph, name, tap); + m_root_write->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::WRITE); + + return mph; +} +//------------------------------------------------- +// install_write_tap - install a read and a write tap on the bus +//------------------------------------------------- + +template memory_passthrough_handler *address_space_specific::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = make_mph(); + + auto rhandler = new handler_entry_read_tap (this, *mph, name, tapr); + m_root_read ->populate_passthrough(nstart, nend, nmirror, rhandler); + rhandler->unref(); + + auto whandler = new handler_entry_write_tap(this, *mph, name, tapw); + m_root_write->populate_passthrough(nstart, nend, nmirror, whandler); + whandler->unref(); + + invalidate_caches(read_or_write::READWRITE); + + return mph; +} + + + + + +//------------------------------------------------- +// install_device_delegate - install the memory map +// of a live device into this address space +//------------------------------------------------- + +template void address_space_specific::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth) +{ + check_address("install_device_delegate", addrstart, addrend); + address_map map(*this, addrstart, addrend, unitmask, cswidth, m_device, delegate); + map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift()); + populate_from_map(&map); +} + + + +//------------------------------------------------- +// install_readwrite_port - install a new I/O port +// handler into this address space +//------------------------------------------------- + +template void address_space_specific::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) +{ + VPRINTF("address_space::install_readwrite_port(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + rtag.empty() ? "(none)" : rtag, wtag.empty() ? "(none)" : wtag); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_readwrite_port", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + // read handler + if (rtag != "") + { + // find the port + ioport_port *port = device().owner()->ioport(rtag); + if (port == nullptr) + throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, m_name, m_device.tag()); + + // map the range and set the ioport + auto hand_r = new handler_entry_read_ioport(this, port); + m_root_read->populate(nstart, nend, nmirror, hand_r); + } + + if (wtag != "") + { + // find the port + ioport_port *port = device().owner()->ioport(wtag); + if (port == nullptr) + fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, m_name, m_device.tag()); + + // map the range and set the ioport + auto hand_w = new handler_entry_write_ioport(this, port); + m_root_write->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); +} + + +//------------------------------------------------- +// install_bank_generic - install a range as +// mapping to a particular bank +//------------------------------------------------- + +template void address_space_specific::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) +{ + VPRINTF("address_space::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)"); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + // map the read bank + if (rbank != nullptr) + { + auto hand_r = new handler_entry_read_memory_bank(this, *rbank); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); + } + + // map the write bank + if (wbank != nullptr) + { + auto hand_w = new handler_entry_write_memory_bank(this, *wbank); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); +} + + +//------------------------------------------------- +// install_ram_generic - install a simple fixed +// RAM region into the given address space +//------------------------------------------------- + +template void address_space_specific::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) +{ + VPRINTF("address_space::install_ram_generic(%s-%s mirror=%s, %s, %p)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", + baseptr); + + offs_t nstart, nend, nmask, nmirror; + check_optimize_mirror("install_ram_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + // map for read + if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) + { + auto hand_r = new handler_entry_read_memory(this, baseptr); + hand_r->set_address_info(nstart, nmask); + m_root_read->populate(nstart, nend, nmirror, hand_r); + } + + // map for write + if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) + { + auto hand_w = new handler_entry_write_memory(this, baseptr); + hand_w->set_address_info(nstart, nmask); + m_root_write->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(readorwrite); +} + +//************************************************************************** +// MEMORY MAPPING HELPERS +//************************************************************************** + +int address_space::add_change_notifier(std::function n) +{ + int id = m_notifier_id++; + m_notifiers.emplace_back(notifier_t{ std::move(n), id }); + return id; +} + +void address_space::remove_change_notifier(int id) +{ + for(auto i = m_notifiers.begin(); i != m_notifiers.end(); i++) + if (i->m_id == id) { + m_notifiers.erase(i); + return; + } + fatalerror("Unknown notifier id %d, double remove?\n", id); +} diff --git a/src/emu/emumem_hedr.h b/src/emu/emumem_hedr.h index 30e819bd99063..0ef50471e8f65 100644 --- a/src/emu/emumem_hedr.h +++ b/src/emu/emumem_hedr.h @@ -3,7 +3,8 @@ // handler_entry_read_dispatch -// dispatches an access among multiple handlers indexed on part of the address +// dispatches an access among multiple handlers indexed on part of the +// address and when appropriate a selected view template class handler_entry_read_dispatch : public handler_entry_read { @@ -13,6 +14,8 @@ template class hand using mapping = typename inh::mapping; handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read *handler); + handler_entry_read_dispatch(address_space *space, memory_view &view); + handler_entry_read_dispatch(handler_entry_read_dispatch *src); ~handler_entry_read_dispatch(); uX read(offs_t offset, uX mem_mask) const override; @@ -35,9 +38,13 @@ template class hand void enumerate_references(handler_entry::reflist &refs) const override; - virtual const handler_entry_read *const *get_dispatch() const override; + const handler_entry_read *const *get_dispatch() const override; + void select_a(int slot) override; + void select_u(int slot) override; + void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read **dispatch, handler_entry::range *ranges) override; + handler_entry_read *dup() override; -protected: +private: static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits); static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_lowbits(HighBits, Width, AddrShift); static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0; @@ -47,10 +54,17 @@ template class hand static constexpr offs_t HIGHMASK = make_bitmask(HighBits) ^ LOWMASK; static constexpr offs_t UPMASK = ~make_bitmask(HighBits); - handler_entry_read *m_dispatch[COUNT]; - handler_entry::range m_ranges[COUNT]; + memory_view *m_view; + + std::vector *, COUNT>> m_dispatch_array; + std::vector> m_ranges_array; + + handler_entry_read **m_a_dispatch; + handler_entry::range *m_a_ranges; + + handler_entry_read **m_u_dispatch; + handler_entry::range *m_u_ranges; -private: void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *handler); void populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *handler); diff --git a/src/emu/emumem_hedr.ipp b/src/emu/emumem_hedr.ipp index 844cae6dd9097..41a209f75ece2 100644 --- a/src/emu/emumem_hedr.ipp +++ b/src/emu/emumem_hedr.ipp @@ -11,71 +11,125 @@ template const handler_entry_read *const *handler_entry_read_dispatch::get_dispatch() const { - return m_dispatch; + return m_a_dispatch; } -template handler_entry_read_dispatch::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read *handler) : handler_entry_read(space, handler_entry::F_DISPATCH) +template handler_entry_read_dispatch::handler_entry_read_dispatch(address_space *space, const handler_entry::range &init, handler_entry_read *handler) : handler_entry_read(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(); 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 handler_entry_read_dispatch::handler_entry_read_dispatch(address_space *space, memory_view &view) : handler_entry_read(space, handler_entry::F_VIEW), m_view(&view), m_a_dispatch(nullptr), m_a_ranges(nullptr), m_u_dispatch(nullptr), m_u_ranges(nullptr) +{ +} + +template handler_entry_read_dispatch::handler_entry_read_dispatch(handler_entry_read_dispatch *src) : handler_entry_read(src->m_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(); + + for(unsigned int i=0; i != COUNT; i++) { + m_u_dispatch[i] = src->m_u_dispatch[i]; + m_u_ranges[i] = src->m_u_ranges[i]; } } + template handler_entry_read_dispatch::~handler_entry_read_dispatch() { - for(unsigned int i=0; i != COUNT; i++) - m_dispatch[i]->unref(); + for(auto &d : m_dispatch_array) + for(auto p : d) + if(p) + p->unref(); } template void handler_entry_read_dispatch::enumerate_references(handler_entry::reflist &refs) const { - for(unsigned int i=0; i != COUNT; i++) - refs.add(m_dispatch[i]); + for(auto &d : m_dispatch_array) + for(auto p : d) + if(p) + refs.add(p); } template void handler_entry_read_dispatch::dump_map(std::vector &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)); - + 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 typename emu::detail::handler_entry_size::uX handler_entry_read_dispatch::read(offs_t offset, uX mem_mask) const { - return dispatch_read(HIGHMASK, offset, mem_mask, m_dispatch); + return dispatch_read(HIGHMASK, offset, mem_mask, m_a_dispatch); } template void *handler_entry_read_dispatch::get_ptr(offs_t offset) const { - return m_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); + return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); } template std::string handler_entry_read_dispatch::name() const { - return "dispatch"; + return m_view ? "view" : "dispatch"; } template void handler_entry_read_dispatch::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read *&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; } } @@ -83,62 +137,66 @@ template void handl template void handler_entry_read_dispatch::range_cut_before(offs_t address, int start) { while(--start >= 0) { - if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { - static_cast *>(m_dispatch[start])->range_cut_before(address); + if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) { + static_cast *>(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 void handler_entry_read_dispatch::range_cut_after(offs_t address, int start) { while(++start < COUNT) { - if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { - static_cast *>(m_dispatch[start])->range_cut_after(address); + if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) { + static_cast *>(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 void handler_entry_read_dispatch::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } template void handler_entry_read_dispatch::populate_nomirror(offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read *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(handler->is_view()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); 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()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); + 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); @@ -157,24 +215,26 @@ template void handl } if(start_entry <= end_entry) { + if(handler->is_view()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); 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 void handler_entry_read_dispatch::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_read *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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } @@ -236,13 +296,13 @@ template void handl template void handler_entry_read_dispatch::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } @@ -261,17 +321,17 @@ template void handl 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 & 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); + 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); @@ -295,11 +355,11 @@ template void handl 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); + if(m_u_dispatch[ent]->is_dispatch()) + m_u_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); + mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]); + m_u_ranges[ent].set(ostart, oend); } } } @@ -308,13 +368,13 @@ template void handl template void handler_entry_read_dispatch::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 &descriptor, std::vector &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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } @@ -367,13 +427,13 @@ template void handl template void handler_entry_read_dispatch::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_read_passthrough *handler, std::vector &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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } @@ -387,14 +447,14 @@ template void handl if(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); + 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); @@ -410,11 +470,11 @@ template void handl 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); + if(m_u_dispatch[ent]->is_dispatch()) + m_u_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); + passthrough_patch(handler, mappings, m_u_dispatch[ent]); + m_u_ranges[ent].intersect(ostart, oend); } } } @@ -423,13 +483,13 @@ template void handl template void handler_entry_read_dispatch::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 *handler, std::vector &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(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_read_dispatch(handler_entry::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); } } @@ -464,22 +524,108 @@ template void handl template void handler_entry_read_dispatch::detach(const std::unordered_set &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 *>(m_dispatch[i]); + auto np = static_cast *>(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 void handler_entry_read_dispatch::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_read **dispatch, handler_entry::range *ranges) +{ + if(!m_view) + fatalerror("init_handlers called on non-view handler_entry_read_dispatch."); + if(!m_dispatch_array.empty()) + fatalerror("init_handlers called twice on handler_entry_read_dispatch."); + + 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 filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) { + r.intersect(s, e); + return r; + }; + + if(lowbits != LowBits) { + u32 dt = lowbits - LowBits; + u32 ne = 1 << dt; + for(offs_t entry = start_entry; entry <= end_entry; entry++) { + m_u_dispatch[entry]->ref(ne); + u32 e0 = (entry << dt) & BITMASK; + for(offs_t e = 0; e != ne; e++) { + m_u_dispatch[e0 | e] = dispatch[entry]; + m_u_ranges[e0 | e] = filter(ranges[entry]); + } + } + + } else { + for(offs_t entry = start_entry; entry <= end_entry; entry++) { + m_u_dispatch[entry & BITMASK] = dispatch[entry]; + m_u_ranges[entry & BITMASK] = filter(ranges[entry]); + dispatch[entry]->ref(); + } + } +} + +template void handler_entry_read_dispatch::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 void handler_entry_read_dispatch::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 = (std::array *, COUNT> *)(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++) { + 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 handler_entry_read *handler_entry_read_dispatch::dup() +{ + if(m_view) { + handler_entry::ref(); + return this; + } + + return new handler_entry_read_dispatch(this); +} diff --git a/src/emu/emumem_hedr0.cpp b/src/emu/emumem_hedr0.cpp index 536c64e6274bd..0dbd929412e91 100644 --- a/src/emu/emumem_hedr0.cpp +++ b/src/emu/emumem_hedr0.cpp @@ -5,6 +5,8 @@ #include "emumem_hedr.ipp" +template class handler_entry_read_dispatch< 0, 0, 1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 0, 1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 1, 0, 1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 1, 0, 1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 0, 1, ENDIANNESS_LITTLE>; @@ -22,6 +24,8 @@ template class handler_entry_read_dispatch< 7, 0, 1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 0, 1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 0, 1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 0, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 0, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 1, 0, 0, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 1, 0, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 0, 0, ENDIANNESS_LITTLE>; @@ -39,6 +43,8 @@ template class handler_entry_read_dispatch< 7, 0, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 0, 0, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 0, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 1, 3, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 1, 1, 3, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 1, 1, 3, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 1, 3, ENDIANNESS_LITTLE>; @@ -73,6 +79,8 @@ template class handler_entry_read_dispatch< 7, 1, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 1, 0, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 0, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 1, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 1, 1, -1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 1, 1, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 1, -1, ENDIANNESS_LITTLE>; @@ -120,6 +128,8 @@ template class handler_entry_read_dispatch< 7, 2, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 2, 0, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 1, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 2, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 2, -1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 2, 2, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 3, 2, -1, ENDIANNESS_LITTLE>; @@ -135,6 +145,10 @@ template class handler_entry_read_dispatch< 7, 2, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 2, -1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 0, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 1, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 2, -2, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 2, 2, -2, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 2, 2, -2, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 3, 2, -2, ENDIANNESS_LITTLE>; @@ -163,6 +177,8 @@ template class handler_entry_read_dispatch< 7, 3, 0, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 3, 0, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 3, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 3, 3, -1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 3, 3, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 4, 3, -1, ENDIANNESS_LITTLE>; @@ -176,6 +192,10 @@ template class handler_entry_read_dispatch< 7, 3, -1, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 3, -1, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 1, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 3, -2, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 3, 3, -2, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 3, 3, -2, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 4, 3, -2, ENDIANNESS_LITTLE>; @@ -189,6 +209,12 @@ template class handler_entry_read_dispatch< 7, 3, -2, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 8, 3, -2, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 8, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 0, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 0, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 1, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 1, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_read_dispatch< 2, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_read_dispatch< 2, 3, -3, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 3, 3, -3, ENDIANNESS_LITTLE>; template class handler_entry_read_dispatch< 3, 3, -3, ENDIANNESS_BIG>; template class handler_entry_read_dispatch< 4, 3, -3, ENDIANNESS_LITTLE>; diff --git a/src/emu/emumem_hedw.h b/src/emu/emumem_hedw.h index 219b51d89f73b..bb591e3bff8a0 100644 --- a/src/emu/emumem_hedw.h +++ b/src/emu/emumem_hedw.h @@ -3,7 +3,8 @@ // handler_entry_write_dispatch -// dispatches an access among multiple handlers indexed on part of the address +// dispatches an access among multiple handlers indexed on part of the +// address and when appropriate a selected view template class handler_entry_write_dispatch : public handler_entry_write { @@ -13,6 +14,8 @@ template class hand using mapping = typename inh::mapping; handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write *handler); + handler_entry_write_dispatch(address_space *space, memory_view &view); + handler_entry_write_dispatch(handler_entry_write_dispatch *src); ~handler_entry_write_dispatch(); void write(offs_t offset, uX data, uX mem_mask) const override; @@ -35,9 +38,13 @@ template class hand void enumerate_references(handler_entry::reflist &refs) const override; - virtual const handler_entry_write *const *get_dispatch() const override; + const handler_entry_write *const *get_dispatch() const override; + void select_a(int slot) override; + void select_u(int slot) override; + void init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write **dispatch, handler_entry::range *ranges) override; + handler_entry_write *dup() override; -protected: +private: static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits); static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_lowbits(HighBits, Width, AddrShift); static constexpr u32 BITCOUNT = HighBits > LowBits ? HighBits - LowBits : 0; @@ -47,10 +54,17 @@ template class hand static constexpr offs_t HIGHMASK = make_bitmask(HighBits) ^ LOWMASK; static constexpr offs_t UPMASK = ~make_bitmask(HighBits); - handler_entry_write *m_dispatch[COUNT]; - handler_entry::range m_ranges[COUNT]; + memory_view *m_view; + + std::vector *, COUNT>> m_dispatch_array; + std::vector> m_ranges_array; + + handler_entry_write **m_a_dispatch; + handler_entry::range *m_a_ranges; + + handler_entry_write **m_u_dispatch; + handler_entry::range *m_u_ranges; -private: void populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *handler); void populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *handler); diff --git a/src/emu/emumem_hedw.ipp b/src/emu/emumem_hedw.ipp index 3e12c702864e6..f63072b3bfb7e 100644 --- a/src/emu/emumem_hedw.ipp +++ b/src/emu/emumem_hedw.ipp @@ -12,70 +12,126 @@ template const handler_entry_write *const *handler_entry_write_dispatch::get_dispatch() const { - return m_dispatch; + return m_a_dispatch; } -template handler_entry_write_dispatch::handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write *handler) : handler_entry_write(space, handler_entry::F_DISPATCH) +template handler_entry_write_dispatch::handler_entry_write_dispatch(address_space *space, const handler_entry::range &init, handler_entry_write *handler) : handler_entry_write(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_w(); 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 handler_entry_write_dispatch::handler_entry_write_dispatch(address_space *space, memory_view &view) : handler_entry_write(space, handler_entry::F_VIEW), m_view(&view), m_a_dispatch(nullptr), m_a_ranges(nullptr), m_u_dispatch(nullptr), m_u_ranges(nullptr) +{ +} + + +template handler_entry_write_dispatch::handler_entry_write_dispatch(handler_entry_write_dispatch *src) : handler_entry_write(src->m_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(); + + for(unsigned int i=0; i != COUNT; i++) { + m_u_dispatch[i] = src->m_u_dispatch[i]; + m_u_ranges[i] = src->m_u_ranges[i]; } } + template handler_entry_write_dispatch::~handler_entry_write_dispatch() { - for(unsigned int i=0; i != COUNT; i++) - m_dispatch[i]->unref(); + for(auto &d : m_dispatch_array) + for(auto p : d) + if(p) + p->unref(); } template void handler_entry_write_dispatch::enumerate_references(handler_entry::reflist &refs) const { - for(unsigned int i=0; i != COUNT; i++) - refs.add(m_dispatch[i]); + for(auto &d : m_dispatch_array) + for(auto p : d) + if(p) + refs.add(p); } template void handler_entry_write_dispatch::dump_map(std::vector &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)); + 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 void handler_entry_write_dispatch::write(offs_t offset, uX data, uX mem_mask) const { - dispatch_write(HIGHMASK, offset, data, mem_mask, m_dispatch); + dispatch_write(HIGHMASK, offset, data, mem_mask, m_a_dispatch); } template void *handler_entry_write_dispatch::get_ptr(offs_t offset) const { - return m_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); + return m_a_dispatch[(offset & HIGHMASK) >> LowBits]->get_ptr(offset); } template std::string handler_entry_write_dispatch::name() const { - return "dispatch"; + return m_view ? "view" :"dispatch"; } template void handler_entry_write_dispatch::lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write *&handler) const { offs_t slot = (address >> LowBits) & BITMASK; - auto h = m_dispatch[slot]; + auto h = m_a_dispatch[slot]; if(h->is_dispatch()) 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; } } @@ -83,38 +139,38 @@ template void handl template void handler_entry_write_dispatch::range_cut_before(offs_t address, int start) { while(--start >= 0) { - if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { - static_cast *>(m_dispatch[start])->range_cut_before(address); + if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) { + static_cast *>(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 void handler_entry_write_dispatch::range_cut_after(offs_t address, int start) { while(++start < COUNT) { - if(int(LowBits) > -AddrShift && m_dispatch[start]->is_dispatch()) { - static_cast *>(m_dispatch[start])->range_cut_after(address); + if(int(LowBits) > -AddrShift && m_u_dispatch[start]->is_dispatch()) { + static_cast *>(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 void handler_entry_write_dispatch::populate_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write *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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -127,18 +183,22 @@ template void handl range_cut_after(oend+1, end_entry); if(LowBits <= Width + AddrShift) { + if(handler->is_view()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); 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()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); + 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); @@ -157,11 +217,13 @@ template void handl } if(start_entry <= end_entry) { + if(handler->is_view()) + handler->init_handlers(start_entry, end_entry, LowBits, m_u_dispatch, m_u_ranges); 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); } } } @@ -169,13 +231,13 @@ template void handl template void handler_entry_write_dispatch::populate_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write *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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -236,13 +298,13 @@ template void handl template void handler_entry_write_dispatch::populate_mismatched_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, const memory_units_descriptor &descriptor, u8 rkey, std::vector &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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -261,17 +323,17 @@ template void handl rkey1 &= ~handler_entry::START; if(ent != end_entry) rkey1 &= ~handler_entry::END; - mismatched_patch(descriptor, rkey1, mappings, m_dispatch[ent]); - m_ranges[ent].intersect(ostart, oend); + mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]); + m_u_ranges[ent].intersect(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 & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); else { - mismatched_patch(descriptor, rkey, mappings, m_dispatch[start_entry]); - m_ranges[start_entry].intersect(ostart, oend); + mismatched_patch(descriptor, rkey, mappings, m_u_dispatch[start_entry]); + m_u_ranges[start_entry].intersect(ostart, oend); } } else populate_mismatched_nomirror_subdispatch(start_entry, start & LOWMASK, end & LOWMASK, ostart, oend, descriptor, rkey, mappings); @@ -295,11 +357,11 @@ template void handl 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); + if(m_u_dispatch[ent]->is_dispatch()) + m_u_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].intersect(ostart, oend); + mismatched_patch(descriptor, rkey1, mappings, m_u_dispatch[ent]); + m_u_ranges[ent].intersect(ostart, oend); } } } @@ -308,13 +370,13 @@ template void handl template void handler_entry_write_dispatch::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 &descriptor, std::vector &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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -367,13 +429,13 @@ template void handl template void handler_entry_write_dispatch::populate_passthrough_nomirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, handler_entry_write_passthrough *handler, std::vector &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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -387,17 +449,17 @@ template void handl if(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) { - if(m_dispatch[start_entry]->is_dispatch()) - m_dispatch[start_entry]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); + if(m_u_dispatch[start_entry]->is_dispatch()) + m_u_dispatch[start_entry]->populate_passthrough_nomirror(start & LOWMASK, end & LOWMASK, ostart, oend, handler, mappings); else { - passthrough_patch(handler, mappings, m_dispatch[start_entry]); - m_ranges[start_entry].intersect(ostart, oend); + 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); @@ -414,11 +476,11 @@ template void handl 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); + if(m_u_dispatch[ent]->is_dispatch()) + m_u_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); + passthrough_patch(handler, mappings, m_u_dispatch[ent]); + m_u_ranges[ent].intersect(ostart, oend); } } } @@ -427,13 +489,13 @@ template void handl template void handler_entry_write_dispatch::populate_passthrough_mirror_subdispatch(offs_t entry, offs_t start, offs_t end, offs_t ostart, offs_t oend, offs_t mirror, handler_entry_write_passthrough *handler, std::vector &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_write_dispatch(handler_entry::m_space, m_ranges[entry], cur); + auto subdispatch = new handler_entry_write_dispatch(handler_entry::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); } } @@ -468,22 +530,108 @@ template void handl template void handler_entry_write_dispatch::detach(const std::unordered_set &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 *>(m_dispatch[i]); + auto np = static_cast *>(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 void handler_entry_write_dispatch::init_handlers(offs_t start_entry, offs_t end_entry, u32 lowbits, handler_entry_write **dispatch, handler_entry::range *ranges) +{ + if(!m_view) + fatalerror("init_handlers called on non-view handler_entry_write_dispatch."); + if(!m_dispatch_array.empty()) + fatalerror("init_handlers called twice on handler_entry_write_dispatch."); + + 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 filter = [s = m_view->m_addrstart, e = m_view->m_addrend] (handler_entry::range r) { + r.intersect(s, e); + return r; + }; + + if(lowbits != LowBits) { + u32 dt = lowbits - LowBits; + u32 ne = 1 << dt; + for(offs_t entry = start_entry; entry <= end_entry; entry++) { + m_u_dispatch[entry]->ref(ne); + u32 e0 = (entry << dt) & BITMASK; + for(offs_t e = 0; e != ne; e++) { + m_u_dispatch[e0 | e] = dispatch[entry]; + m_u_ranges[e0 | e] = filter(ranges[entry]); + } + } + + } else { + for(offs_t entry = start_entry; entry <= end_entry; entry++) { + m_u_dispatch[entry & BITMASK] = dispatch[entry]; + m_u_ranges[entry & BITMASK] = filter(ranges[entry]); + dispatch[entry]->ref(); + } + } +} + +template void handler_entry_write_dispatch::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 void handler_entry_write_dispatch::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 = (std::array *, COUNT> *)(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++) { + 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 handler_entry_write *handler_entry_write_dispatch::dup() +{ + if(m_view) { + handler_entry::ref(); + return this; + } + + return new handler_entry_write_dispatch(this); +} diff --git a/src/emu/emumem_hedw0.cpp b/src/emu/emumem_hedw0.cpp index 593a42d741762..67244fc3044a3 100644 --- a/src/emu/emumem_hedw0.cpp +++ b/src/emu/emumem_hedw0.cpp @@ -5,6 +5,8 @@ #include "emumem_hedw.ipp" +template class handler_entry_write_dispatch< 0, 0, 1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 0, 1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 1, 0, 1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 1, 0, 1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 0, 1, ENDIANNESS_LITTLE>; @@ -22,6 +24,8 @@ template class handler_entry_write_dispatch< 7, 0, 1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 0, 1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 0, 1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 0, 0, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 0, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 1, 0, 0, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 1, 0, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 0, 0, ENDIANNESS_LITTLE>; @@ -39,6 +43,8 @@ template class handler_entry_write_dispatch< 7, 0, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 0, 0, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 0, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 1, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 1, 3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 1, 1, 3, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 1, 1, 3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 1, 3, ENDIANNESS_LITTLE>; @@ -73,6 +79,8 @@ template class handler_entry_write_dispatch< 7, 1, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 1, 0, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 1, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 1, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 1, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 1, 1, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 1, 1, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 1, -1, ENDIANNESS_LITTLE>; @@ -90,6 +98,10 @@ template class handler_entry_write_dispatch< 7, 1, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 1, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 1, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 2, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 2, 3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 1, 2, 3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 2, 3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 2, 3, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 2, 2, 3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 2, 3, ENDIANNESS_LITTLE>; @@ -120,6 +132,8 @@ template class handler_entry_write_dispatch< 7, 2, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 2, 0, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 2, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 1, 2, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 2, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 2, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 2, 2, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 2, -1, ENDIANNESS_LITTLE>; @@ -135,6 +149,10 @@ template class handler_entry_write_dispatch< 7, 2, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 2, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 2, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 2, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 1, 2, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 2, -2, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 2, 2, -2, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 2, 2, -2, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 2, -2, ENDIANNESS_LITTLE>; @@ -163,6 +181,8 @@ template class handler_entry_write_dispatch< 7, 3, 0, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 3, 0, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 3, 0, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 3, -1, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 3, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 3, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 3, 3, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 4, 3, -1, ENDIANNESS_LITTLE>; @@ -176,6 +196,10 @@ template class handler_entry_write_dispatch< 7, 3, -1, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 3, -1, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 3, -1, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 1, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 3, -2, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 3, -2, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 3, -2, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 3, 3, -2, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 4, 3, -2, ENDIANNESS_LITTLE>; @@ -189,6 +213,12 @@ template class handler_entry_write_dispatch< 7, 3, -2, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 8, 3, -2, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 8, 3, -2, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 0, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 0, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 1, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 1, 3, -3, ENDIANNESS_BIG>; +template class handler_entry_write_dispatch< 2, 3, -3, ENDIANNESS_LITTLE>; +template class handler_entry_write_dispatch< 2, 3, -3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 3, 3, -3, ENDIANNESS_LITTLE>; template class handler_entry_write_dispatch< 3, 3, -3, ENDIANNESS_BIG>; template class handler_entry_write_dispatch< 4, 3, -3, ENDIANNESS_LITTLE>; diff --git a/src/emu/emumem_heu.cpp b/src/emu/emumem_heu.cpp index e556a39bd313a..aba5a28f9c2ea 100644 --- a/src/emu/emumem_heu.cpp +++ b/src/emu/emumem_heu.cpp @@ -36,12 +36,27 @@ template handler_entry_read_units std::sort(m_subunit_infos, m_subunit_infos + m_subunits, [](const subunit_info &a, const subunit_info &b) { return a.m_offset < b.m_offset; }); } +template handler_entry_read_units::handler_entry_read_units(const handler_entry_read_units *src) : + handler_entry_read(src->m_space, inh::F_UNITS), + m_subunits(src->m_subunits) +{ + for(u32 i=0; i != src->m_subunits; i++) { + m_subunit_infos[i] = src->m_subunit_infos[i]; + m_subunit_infos[i].m_handler = static_cast *>(m_subunit_infos[i].m_handler)->dup(); + } +} + template handler_entry_read_units::~handler_entry_read_units() { for(u32 i=0; i != m_subunits; i++) m_subunit_infos[i].m_handler->unref(); } +template handler_entry_read *handler_entry_read_units::dup() +{ + return new handler_entry_read_units(this); +} + template void handler_entry_read_units::enumerate_references(handler_entry::reflist &refs) const { for(u32 i=0; i != m_subunits; i++) @@ -155,12 +170,27 @@ template handler_entry_write_unit std::sort(m_subunit_infos, m_subunit_infos + m_subunits, [](const subunit_info &a, const subunit_info &b) { return a.m_offset < b.m_offset; }); } +template handler_entry_write_units::handler_entry_write_units(const handler_entry_write_units *src) : + handler_entry_write(src->m_space, inh::F_UNITS), + m_subunits(src->m_subunits) +{ + for(u32 i=0; i != src->m_subunits; i++) { + m_subunit_infos[i] = src->m_subunit_infos[i]; + m_subunit_infos[i].m_handler = static_cast *>(m_subunit_infos[i].m_handler)->dup(); + } +} + template handler_entry_write_units::~handler_entry_write_units() { for(u32 i=0; i != m_subunits; i++) m_subunit_infos[i].m_handler->unref(); } +template handler_entry_write *handler_entry_write_units::dup() +{ + return new handler_entry_write_units(this); +} + template void handler_entry_write_units::enumerate_references(handler_entry::reflist &refs) const { for(u32 i=0; i != m_subunits; i++) diff --git a/src/emu/emumem_heu.h b/src/emu/emumem_heu.h index d084fddfe9816..670d489d00ad8 100644 --- a/src/emu/emumem_heu.h +++ b/src/emu/emumem_heu.h @@ -13,6 +13,7 @@ template class handler_entry_read handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space); handler_entry_read_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_read_units *src); + handler_entry_read_units(const handler_entry_read_units *src); ~handler_entry_read_units(); uX read(offs_t offset, uX mem_mask) const override; @@ -20,6 +21,7 @@ template class handler_entry_read std::string name() const override; void enumerate_references(handler_entry::reflist &refs) const override; + handler_entry_read *dup() override; private: static constexpr u32 SUBUNIT_COUNT = 1 << Width; @@ -54,6 +56,7 @@ template class handler_entry_writ handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, address_space *space); handler_entry_write_units(const memory_units_descriptor &descriptor, u8 ukey, const handler_entry_write_units *src); + handler_entry_write_units(const handler_entry_write_units *src); ~handler_entry_write_units(); void write(offs_t offset, uX data, uX mem_mask) const override; @@ -61,6 +64,7 @@ template class handler_entry_writ std::string name() const override; void enumerate_references(handler_entry::reflist &refs) const override; + handler_entry_write *dup() override; private: static constexpr u32 SUBUNIT_COUNT = 1 << Width; diff --git a/src/emu/emumem_mview.cpp b/src/emu/emumem_mview.cpp new file mode 100644 index 0000000000000..f4f92e1a7b897 --- /dev/null +++ b/src/emu/emumem_mview.cpp @@ -0,0 +1,995 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,Olivier Galibert +/*************************************************************************** + + emumem.cpp + + Functions which handle device memory access. + Memory view specific functions + +***************************************************************************/ + +#include "emu.h" +#include +#include +#include "emuopts.h" +#include "debug/debugcpu.h" + +#include "emumem_mud.h" +#include "emumem_hea.h" +#include "emumem_hem.h" +#include "emumem_hedp.h" +#include "emumem_heun.h" +#include "emumem_heu.h" +#include "emumem_hedr.h" +#include "emumem_hedw.h" +#include "emumem_hep.h" +#include "emumem_het.h" + +#define VERBOSE 0 + +#if VERBOSE +template static void VPRINTF(Format &&fmt, Params &&...args) +{ + util::stream_format(std::cerr, std::forward(fmt), std::forward(args)...); +} +#else +template static void VPRINTF(Format &&, Params &&...) {} +#endif + +namespace { + +template struct handler_width; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 0; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 1; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 2; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +template <> struct handler_width { static constexpr int value = 3; }; +} // anonymous namespace + +address_map_entry &memory_view::memory_view_entry::operator()(offs_t start, offs_t end) +{ + return (*m_map)(start, end); +} + +template +class memory_view_entry_specific : public memory_view::memory_view_entry +{ + using uX = typename emu::detail::handler_entry_size::uX; + using NativeType = uX; + + // constants describing the native size + static constexpr u32 NATIVE_BYTES = 1 << Width; + static constexpr u32 NATIVE_STEP = AddrShift >= 0 ? NATIVE_BYTES << iabs(AddrShift) : NATIVE_BYTES >> iabs(AddrShift); + static constexpr u32 NATIVE_MASK = NATIVE_STEP - 1; + static constexpr u32 NATIVE_BITS = 8 * NATIVE_BYTES; + + static constexpr offs_t offset_to_byte(offs_t offset) { return AddrShift < 0 ? offset << iabs(AddrShift) : offset >> iabs(AddrShift); } + +public: + memory_view_entry_specific(const address_space_config &config, memory_manager &manager, memory_view &view, int id) : memory_view_entry(config, manager, view, id) { + } + + virtual ~memory_view_entry_specific() = default; + + handler_entry_read *r() { return static_cast *>(m_view.m_handler_read); } + handler_entry_write *w() { return static_cast *>(m_view.m_handler_write); } + + void invalidate_caches(read_or_write readorwrite) { return m_view.m_space->invalidate_caches(readorwrite); } + + virtual void populate_from_map(address_map *map = nullptr) override; + + using address_space_installer::install_read_tap; + using address_space_installer::install_write_tap; + using address_space_installer::install_readwrite_tap; + + virtual memory_passthrough_handler *install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) override; + virtual memory_passthrough_handler *install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) override; + + virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) override; + virtual void install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) override; + virtual void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) override; + virtual void install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) override; + virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) override; + virtual void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &map, u64 unitmask, int cswidth) override; + + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8_delegate rhandler, write8_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16_delegate rhandler, write16_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32_delegate rhandler, write32_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64_delegate rhandler, write64_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8m_delegate rhandler, write8m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16m_delegate rhandler, write16m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32m_delegate rhandler, write32m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64m_delegate rhandler, write64m_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8s_delegate rhandler, write8s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16s_delegate rhandler, write16s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32s_delegate rhandler, write32s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64s_delegate rhandler, write64s_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8sm_delegate rhandler, write8sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16sm_delegate rhandler, write16sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32sm_delegate rhandler, write32sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64sm_delegate rhandler, write64sm_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8mo_delegate rhandler, write8mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16mo_delegate rhandler, write16mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32mo_delegate rhandler, write32mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64mo_delegate rhandler, write64mo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read8smo_delegate rhandler, write8smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read16smo_delegate rhandler, write16smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read32smo_delegate rhandler, write32smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + void install_read_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, u64 unitmask = 0, int cswidth = 0) override + { install_read_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler); } + void install_write_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_write_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, whandler); } + void install_readwrite_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, read64smo_delegate rhandler, write64smo_delegate whandler, u64 unitmask = 0, int cswidth = 0) override + { install_readwrite_handler_impl(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, rhandler, whandler); } + + template + void install_read_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r) + { + try { handler_r.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_read_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r); + } + + template + void install_write_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, WRITE &handler_w) + { + try { handler_w.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_write_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_w); + } + + template + void install_readwrite_handler_impl(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, READ &handler_r, WRITE &handler_w) + { + static_assert(handler_width::value == handler_width::value, "handler widths do not match"); + try { handler_r.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing read handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_r.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + try { handler_w.resolve(); } + catch (const binding_type_exception &) { + osd_printf_error("Binding error while installing write handler %s for range 0x%X-0x%X mask 0x%X mirror 0x%X select 0x%X umask 0x%X\n", handler_w.name(), addrstart, addrend, addrmask, addrmirror, addrselect, unitmask); + throw; + } + install_readwrite_handler_helper::value>(addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, handler_r, handler_w); + } + + template + void install_read_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, const READ &handler_r) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_read_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("memory_view::install_read_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_r.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_read_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_r = new handler_entry_read_delegate(m_view.m_space, handler_r); + hand_r->set_address_info(nstart, nmask); + r()->populate(nstart, nend, nmirror, hand_r); + } else { + auto hand_r = new handler_entry_read_delegate(m_view.m_space, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + r()->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); + } + invalidate_caches(read_or_write::READ); + } + } + + template + void install_write_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + const WRITE &handler_w) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_write_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("memory_view::install_write_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_w.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_write_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_w = new handler_entry_write_delegate(m_view.m_space, handler_w); + hand_w->set_address_info(nstart, nmask); + w()->populate(nstart, nend, nmirror, hand_w); + } else { + auto hand_w = new handler_entry_write_delegate(m_view.m_space, handler_w); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_w, nstart, nend, nmask, nunitmask, ncswidth); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + w()->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); + } + invalidate_caches(read_or_write::WRITE); + } + } + + template + void install_readwrite_handler_helper(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, + const READ &handler_r, + const WRITE &handler_w) + { + if constexpr (Width < AccessWidth) { + fatalerror("install_readwrite_handler: cannot install a %d-wide handler in a %d-wide bus", 8 << AccessWidth, 8 << Width); + } else { + VPRINTF("memory_view::install_readwrite_handler(%*x-%*x mask=%*x mirror=%*x, space width=%d, handler width=%d, %s, %s, %*x)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmask, m_addrchars, addrmirror, + 8 << Width, 8 << AccessWidth, + handler_r.name(), handler_w.name(), data_width() / 4, unitmask); + + offs_t nstart, nend, nmask, nmirror; + u64 nunitmask; + int ncswidth; + check_optimize_all("install_readwrite_handler", 8 << AccessWidth, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + + if constexpr (Width == AccessWidth) { + auto hand_r = new handler_entry_read_delegate (m_view.m_space, handler_r); + hand_r->set_address_info(nstart, nmask); + r() ->populate(nstart, nend, nmirror, hand_r); + + auto hand_w = new handler_entry_write_delegate(m_view.m_space, handler_w); + hand_w->set_address_info(nstart, nmask); + w()->populate(nstart, nend, nmirror, hand_w); + } else { + auto hand_r = new handler_entry_read_delegate (m_view.m_space, handler_r); + memory_units_descriptor descriptor(AccessWidth, Endian, hand_r, nstart, nend, nmask, nunitmask, ncswidth); + hand_r->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + r() ->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_r->unref(); + + auto hand_w = new handler_entry_write_delegate(m_view.m_space, handler_w); + descriptor.set_subunit_handler(hand_w); + hand_w->set_address_info(descriptor.get_handler_start(), descriptor.get_handler_mask()); + w()->populate_mismatched(nstart, nend, nmirror, descriptor); + hand_w->unref(); + } + invalidate_caches(read_or_write::READWRITE); + } + } +}; + +namespace { + template memory_view::memory_view_entry *mve_make_1(const address_space_config &config, memory_manager &manager, memory_view &view, int id) { + return new memory_view_entry_specific(config, manager, view, id); + } + + template memory_view::memory_view_entry *mve_make_2(int Level, const address_space_config &config, memory_manager &manager, memory_view &view, int id) { + switch(Level) { + case 0: return mve_make_1<0, Width, AddrShift, Endian>(config, manager, view, id); + case 1: return mve_make_1<1, Width, AddrShift, Endian>(config, manager, view, id); + default: abort(); + } + } + + template memory_view::memory_view_entry *mve_make_3(int Level, endianness_t Endian, const address_space_config &config, memory_manager &manager, memory_view &view, int id) { + switch(Endian) { + case ENDIANNESS_LITTLE: return mve_make_2(Level, config, manager, view, id); + case ENDIANNESS_BIG: return mve_make_2 (Level, config, manager, view, id); + default: abort(); + } + } + + memory_view::memory_view_entry *mve_make(int Level, int Width, int AddrShift, endianness_t Endian, const address_space_config &config, memory_manager &manager, memory_view &view, int id) { + switch (Width | (AddrShift + 4)) { + case 8|(4+1): return mve_make_3<0, 1>(Level, Endian, config, manager, view, id); + case 8|(4-0): return mve_make_3<0, 0>(Level, Endian, config, manager, view, id); + case 16|(4+3): return mve_make_3<1, 3>(Level, Endian, config, manager, view, id); + case 16|(4-0): return mve_make_3<1, 0>(Level, Endian, config, manager, view, id); + case 16|(4-1): return mve_make_3<1, -1>(Level, Endian, config, manager, view, id); + case 32|(4+3): return mve_make_3<2, 3>(Level, Endian, config, manager, view, id); + case 32|(4-0): return mve_make_3<2, 0>(Level, Endian, config, manager, view, id); + case 32|(4-1): return mve_make_3<2, -1>(Level, Endian, config, manager, view, id); + case 32|(4-2): return mve_make_3<2, -2>(Level, Endian, config, manager, view, id); + case 64|(4-0): return mve_make_3<3, 0>(Level, Endian, config, manager, view, id); + case 64|(4-1): return mve_make_3<3, -1>(Level, Endian, config, manager, view, id); + case 64|(4-2): return mve_make_3<3, -2>(Level, Endian, config, manager, view, id); + case 64|(4-3): return mve_make_3<3, -3>(Level, Endian, config, manager, view, id); + default: abort(); + } + } +} + +memory_view::memory_view_entry &memory_view::operator[](int slot) +{ + if (!m_config) + fatalerror("A view must be in a map or a space before it can be setup."); + + auto i = m_entry_mapping.find(slot); + if (i == m_entry_mapping.end()) { + memory_view_entry *e; + int id = m_entries.size(); + e = mve_make(emu::detail::handler_entry_dispatch_level(m_config->addr_width()), m_config->data_width(), m_config->addr_shift(), m_config->endianness(), + *m_config, m_device.machine().memory(), *this, id); + m_entries.resize(id+1); + m_entries[id].reset(e); + m_entry_mapping[slot] = id; + return *e; + + } else + return *m_entries[i->second]; +} + +memory_view::memory_view_entry::memory_view_entry(const address_space_config &config, memory_manager &manager, memory_view &view, int id) : address_space_installer(config, manager), m_view(view), m_id(id) +{ + m_map = std::make_unique(m_view); +} + +template void memory_view_entry_specific::populate_from_map(address_map *map) +{ + // no map specified, use the space-specific one + if (map == nullptr) + map = m_map.get(); + + memory_region *devregion = (m_view.m_space->spacenum() == 0) ? m_view.m_device.memregion(DEVICE_SELF) : nullptr; + u32 devregionsize = (devregion != nullptr) ? devregion->bytes() : 0; + + // merge in the submaps + map->import_submaps(m_manager.machine(), m_view.m_device.owner() ? *m_view.m_device.owner() : m_view.m_device, data_width(), endianness(), addr_shift()); + + // make a pass over the address map, adjusting for the device and getting memory pointers + for (address_map_entry &entry : map->m_entrylist) + { + // computed adjusted addresses first + adjust_addresses(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror); + + // if we have a share entry, add it to our map + if (entry.m_share != nullptr) + { + // if we can't find it, add it to our map + std::string fulltag = entry.m_devbase.subtag(entry.m_share); + memory_share *share = m_manager.share_find(fulltag); + if (!share) + { + VPRINTF("Creating share '%s' of length 0x%X\n", fulltag, entry.m_addrend + 1 - entry.m_addrstart); + share = m_manager.share_alloc(m_view.m_device, fulltag, data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); + } + else + { + std::string result = share->compare(data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness()); + if (!result.empty()) + fatalerror("%s\n", result); + } + entry.m_memory = share->ptr(); + } + + // if this is a ROM handler without a specified region and not shared, attach it to the implicit region + if (m_view.m_space->spacenum() == AS_PROGRAM && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && entry.m_share == nullptr) + { + // make sure it fits within the memory region before doing so, however + if (entry.m_addrend < devregionsize) + { + entry.m_region = m_view.m_device.tag(); + entry.m_rgnoffs = address_to_byte(entry.m_addrstart); + } + } + + // validate adjusted addresses against implicit regions + if (entry.m_region != nullptr) + { + // determine full tag + std::string fulltag = entry.m_devbase.subtag(entry.m_region); + + // find the region + memory_region *region = m_manager.machine().root_device().memregion(fulltag); + if (region == nullptr) + fatalerror("device '%s' %s view memory map entry %X-%X references nonexistent region \"%s\"\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); + + // validate the region + if (entry.m_rgnoffs + m_config.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > region->bytes()) + fatalerror("device '%s' %s view memory map entry %X-%X extends beyond region \"%s\" size (%X)\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, region->bytes()); + + if (entry.m_share != nullptr) + fatalerror("device '%s' %s view memory map entry %X-%X has both .region() and .share()\n", m_view.m_device.tag(), m_view.m_name, entry.m_addrstart, entry.m_addrend); + } + + // convert any region-relative entries to their memory pointers + if (entry.m_region != nullptr) + { + // determine full tag + std::string fulltag = entry.m_devbase.subtag(entry.m_region); + + // set the memory address + entry.m_memory = m_manager.machine().root_device().memregion(fulltag)->base() + entry.m_rgnoffs; + } + + // allocate anonymous ram when needed + if (!entry.m_memory && (entry.m_read.m_type == AMH_RAM || entry.m_write.m_type == AMH_RAM)) + entry.m_memory = m_manager.anonymous_alloc(*m_view.m_space, address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), m_config.data_width(), entry.m_addrstart, entry.m_addrend, key()); + } + + // Force the slot to exist, in case the map is empty + m_view.m_select_u(m_id); + + // install the handlers, using the original, unadjusted memory map + for(const address_map_entry &entry : map->m_entrylist) { + // map both read and write halves + populate_map_entry(entry, read_or_write::READ); + populate_map_entry(entry, read_or_write::WRITE); + } +} + +std::string memory_view::memory_view_entry::key() const +{ + std::string key = m_view.m_context; + if (m_id != -1) + key += util::string_format("%s[%d].", m_view.m_name, m_view.id_to_slot(m_id)); + return key; +} + + +memory_view::memory_view(device_t &device, std::string name) : m_device(device), m_name(name), m_config(nullptr), m_addrstart(0), m_addrend(0), m_space(nullptr), m_handler_read(nullptr), m_handler_write(nullptr), m_cur_id(-1), m_cur_slot(-1) +{ +} + +void memory_view::disable() +{ + m_cur_slot = -1; + m_cur_id = -1; + m_select_a(-1); +} + +void memory_view::select(int slot) +{ + auto i = m_entry_mapping.find(slot); + if (i == m_entry_mapping.end()) + fatalerror("memory_view %s: select of unknown slot %d", m_name, slot); + + m_cur_slot = slot; + m_cur_id = i->second; + m_select_a(m_cur_id); +} + +int memory_view::id_to_slot(int id) const +{ + for(const auto &p : m_entry_mapping) + if (p.second == id) + return p.first; + fatalerror("memory_view::id_to_slot on unknown id %d\n", id); +} + +void memory_view::initialize_from_address_map(offs_t addrstart, offs_t addrend, const address_space_config &config) +{ + if (m_config) + fatalerror("A memory_view can be present in only one address map."); + + m_config = &config; + m_addrstart = addrstart; + m_addrend = addrend; +} + +namespace { + template void h_make_1(address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function &sa, std::function &su) { + auto rx = new handler_entry_read_dispatch (&space, view); + auto wx = new handler_entry_write_dispatch(&space, view); + r = rx; + w = wx; + + sa = [rx, wx](int s) { rx->select_a(s); wx->select_a(s); }; + su = [rx, wx](int s) { rx->select_u(s); wx->select_u(s); }; + } + + template void h_make_2(int HighBits, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function &sa, std::function &su) { + switch(HighBits) { + case 0: h_make_1(space, view, r, w, sa, su); break; + case 1: h_make_1(space, view, r, w, sa, su); break; + case 2: h_make_1(space, view, r, w, sa, su); break; + case 3: h_make_1(space, view, r, w, sa, su); break; + case 4: h_make_1< 4, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 5: h_make_1< 5, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 6: h_make_1< 6, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 7: h_make_1< 7, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 8: h_make_1< 8, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 9: h_make_1< 9, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 10: h_make_1<10, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 11: h_make_1<11, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 12: h_make_1<12, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 13: h_make_1<13, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 14: h_make_1<14, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 15: h_make_1<15, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 16: h_make_1<16, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 17: h_make_1<17, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 18: h_make_1<18, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 19: h_make_1<19, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 20: h_make_1<20, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 21: h_make_1<21, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 22: h_make_1<22, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 23: h_make_1<23, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 24: h_make_1<24, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 25: h_make_1<25, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 26: h_make_1<26, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 27: h_make_1<27, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 28: h_make_1<28, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 29: h_make_1<29, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 30: h_make_1<20, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 31: h_make_1<31, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + case 32: h_make_1<32, Width, AddrShift, Endian>(space, view, r, w, sa, su); break; + default: abort(); + } + } + + template void h_make_3(int HighBits, endianness_t Endian, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function &sa, std::function &su) { + switch(Endian) { + case ENDIANNESS_LITTLE: h_make_2(HighBits, space, view, r, w, sa, su); break; + case ENDIANNESS_BIG: h_make_2 (HighBits, space, view, r, w, sa, su); break; + default: abort(); + } + } + + void h_make(int HighBits, int Width, int AddrShift, endianness_t Endian, address_space &space, memory_view &view, handler_entry *&r, handler_entry *&w, std::function &sa, std::function &su) { + switch (Width | (AddrShift + 4)) { + case 8|(4+1): h_make_3<0, 1>(HighBits, Endian, space, view, r, w, sa, su); break; + case 8|(4-0): h_make_3<0, 0>(HighBits, Endian, space, view, r, w, sa, su); break; + case 16|(4+3): h_make_3<1, 3>(HighBits, Endian, space, view, r, w, sa, su); break; + case 16|(4-0): h_make_3<1, 0>(HighBits, Endian, space, view, r, w, sa, su); break; + case 16|(4-1): h_make_3<1, -1>(HighBits, Endian, space, view, r, w, sa, su); break; + case 32|(4+3): h_make_3<2, 3>(HighBits, Endian, space, view, r, w, sa, su); break; + case 32|(4-0): h_make_3<2, 0>(HighBits, Endian, space, view, r, w, sa, su); break; + case 32|(4-1): h_make_3<2, -1>(HighBits, Endian, space, view, r, w, sa, su); break; + case 32|(4-2): h_make_3<2, -2>(HighBits, Endian, space, view, r, w, sa, su); break; + case 64|(4-0): h_make_3<3, 0>(HighBits, Endian, space, view, r, w, sa, su); break; + case 64|(4-1): h_make_3<3, -1>(HighBits, Endian, space, view, r, w, sa, su); break; + case 64|(4-2): h_make_3<3, -2>(HighBits, Endian, space, view, r, w, sa, su); break; + case 64|(4-3): h_make_3<3, -3>(HighBits, Endian, space, view, r, w, sa, su); break; + default: abort(); + } + } +} + +std::pair memory_view::make_handlers(address_space &space, offs_t addrstart, offs_t addrend) +{ + if (m_space != &space || m_addrstart != addrstart || m_addrend != addrend) { + if (m_space) + fatalerror("A memory_view can be installed only once."); + + if (m_config) { + if (m_addrstart != addrstart || m_addrend != addrend) + fatalerror("A memory_view must be installed at its configuration address."); + } else { + m_config = &space.space_config(); + m_addrstart = addrstart; + m_addrend = addrend; + } + + m_space = &space; + + offs_t span = addrstart ^ addrend; + u32 awidth = 0; + if (span) { + for(awidth = 1; awidth != 32; awidth++) + if ((1 << awidth) >= span) + break; + } + + h_make(awidth, m_config->data_width(), m_config->addr_shift(), m_config->endianness(), space, *this, m_handler_read, m_handler_write, m_select_a, m_select_u); + } + + return std::make_pair(m_handler_read, m_handler_write); +} + +void memory_view::make_subdispatch(std::string context) +{ + m_context = context; + for(auto &e : m_entries) + e->populate_from_map(); +} + +void memory_view::memory_view_entry::check_range_optimize_mirror(const char *function, offs_t addrstart, offs_t addrend, offs_t addrmirror, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror) +{ + check_optimize_mirror(function, addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (nstart < m_view.m_addrstart || (nend | nmirror) > m_view.m_addrend) + fatalerror("%s: The range %x-%x mirror %x, exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, addrmirror, m_view.m_addrstart, m_view.m_addrend); +} + +void memory_view::memory_view_entry::check_range_optimize_all(const char *function, int width, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, offs_t addrselect, u64 unitmask, int cswidth, offs_t &nstart, offs_t &nend, offs_t &nmask, offs_t &nmirror, u64 &nunitmask, int &ncswidth) +{ + check_optimize_all(function, width, addrstart, addrend, addrmask, addrmirror, addrselect, unitmask, cswidth, nstart, nend, nmask, nmirror, nunitmask, ncswidth); + if (nstart < m_view.m_addrstart || (nend | nmirror | addrselect) > m_view.m_addrend) + fatalerror("%s: The range %x-%x mirror %x select %x, exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, addrmirror, addrselect, m_view.m_addrstart, m_view.m_addrend); +} + +void memory_view::memory_view_entry::check_range_address(const char *function, offs_t addrstart, offs_t addrend) +{ + check_address(function, addrstart, addrend); + if (addrstart < m_view.m_addrstart || addrend > m_view.m_addrend) + fatalerror("%s: The range %x-%x exceeds the view window boundaries %x-%x.\n", function, addrstart, addrend, m_view.m_addrstart, m_view.m_addrend); +} + +template void memory_view_entry_specific::install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, void *baseptr) +{ + VPRINTF("memory_view::install_ram_generic(%s-%s mirror=%s, %s, %p)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", + baseptr); + + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_ram_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + m_view.m_select_u(m_id); + + // map for read + if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) + { + auto hand_r = new handler_entry_read_memory(m_view.m_space, baseptr); + hand_r->set_address_info(nstart, nmask); + r()->populate(nstart, nend, nmirror, hand_r); + } + + // map for write + if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) + { + auto hand_w = new handler_entry_write_memory(m_view.m_space, baseptr); + hand_w->set_address_info(nstart, nmask); + w()->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(readorwrite); +} + +template void memory_view_entry_specific::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) +{ + VPRINTF("memory_view::unmap(%*x-%*x mirror=%*x, %s, %s)\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", + quiet ? "quiet" : "normal"); + + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("unmap_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + m_view.m_select_u(m_id); + + // read space + if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_view.m_space->nop_r() : m_view.m_space->unmap_r()); + handler->ref(); + r()->populate(nstart, nend, nmirror, handler); + } + + // write space + if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) { + auto handler = static_cast *>(quiet ? m_view.m_space->nop_w() : m_view.m_space->unmap_w()); + handler->ref(); + w()->populate(nstart, nend, nmirror, handler); + } + + invalidate_caches(readorwrite); +} + +template void memory_view_entry_specific::install_view(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_view &view) +{ + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_view", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + m_view.m_select_u(m_id); + + auto handlers = view.make_handlers(*m_view.m_space, addrstart, addrend); + r()->populate(nstart, nend, nmirror, static_cast *>(handlers.first)); + w()->populate(nstart, nend, nmirror, static_cast *>(handlers.second)); + view.make_subdispatch(key()); // Must be called after populate +} + +template memory_passthrough_handler *memory_view_entry_specific::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_read_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = m_view.m_space->make_mph(); + + m_view.m_select_u(m_id); + + auto handler = new handler_entry_read_tap(m_view.m_space, *mph, name, tap); + r()->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::READ); + + return mph; +} + +template memory_passthrough_handler *memory_view_entry_specific::install_write_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tap, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_write_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = m_view.m_space->make_mph(); + + m_view.m_select_u(m_id); + + auto handler = new handler_entry_write_tap(m_view.m_space, *mph, name, tap); + w()->populate_passthrough(nstart, nend, nmirror, handler); + handler->unref(); + + invalidate_caches(read_or_write::WRITE); + + return mph; +} + +template memory_passthrough_handler *memory_view_entry_specific::install_readwrite_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function tapr, std::function tapw, memory_passthrough_handler *mph) +{ + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_readwrite_tap", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + if (!mph) + mph = m_view.m_space->make_mph(); + + m_view.m_select_u(m_id); + + auto rhandler = new handler_entry_read_tap (m_view.m_space, *mph, name, tapr); + r() ->populate_passthrough(nstart, nend, nmirror, rhandler); + rhandler->unref(); + + auto whandler = new handler_entry_write_tap(m_view.m_space, *mph, name, tapw); + w()->populate_passthrough(nstart, nend, nmirror, whandler); + whandler->unref(); + + invalidate_caches(read_or_write::READWRITE); + + return mph; +} + +template void memory_view_entry_specific::install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_constructor &delegate, u64 unitmask, int cswidth) +{ + check_range_address("install_device_delegate", addrstart, addrend); + address_map map(*m_view.m_space, addrstart, addrend, unitmask, cswidth, m_view.m_device, delegate); + map.import_submaps(m_manager.machine(), device, data_width(), endianness(), addr_shift()); + populate_from_map(&map); +} + +template void memory_view_entry_specific::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) +{ + VPRINTF("memory_view::install_readwrite_port(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + rtag.empty() ? "(none)" : rtag, wtag.empty() ? "(none)" : wtag); + + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_readwrite_port", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + m_view.m_select_u(m_id); + + // read handler + if (rtag != "") + { + // find the port + ioport_port *port = m_view.m_device.owner()->ioport(rtag); + if (port == nullptr) + throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, m_view.m_name, m_view.m_device.tag()); + + // map the range and set the ioport + auto hand_r = new handler_entry_read_ioport(m_view.m_space, port); + r()->populate(nstart, nend, nmirror, hand_r); + } + + if (wtag != "") + { + // find the port + ioport_port *port = m_view.m_device.owner()->ioport(wtag); + if (port == nullptr) + fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, m_view.m_name, m_view.m_device.tag()); + + // map the range and set the ioport + auto hand_w = new handler_entry_write_ioport(m_view.m_space, port); + w()->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(rtag != "" ? wtag != "" ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); +} +template void memory_view_entry_specific::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) +{ + VPRINTF("memory_view::install_readwrite_bank(%*x-%*x mirror=%*x, read=\"%s\" / write=\"%s\")\n", + m_addrchars, addrstart, m_addrchars, addrend, + m_addrchars, addrmirror, + (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)"); + + offs_t nstart, nend, nmask, nmirror; + check_range_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); + + m_view.m_select_u(m_id); + + // map the read bank + if (rbank != nullptr) + { + auto hand_r = new handler_entry_read_memory_bank(m_view.m_space, *rbank); + hand_r->set_address_info(nstart, nmask); + r()->populate(nstart, nend, nmirror, hand_r); + } + + // map the write bank + if (wbank != nullptr) + { + auto hand_w = new handler_entry_write_memory_bank(m_view.m_space, *wbank); + hand_w->set_address_info(nstart, nmask); + w()->populate(nstart, nend, nmirror, hand_w); + } + + invalidate_caches(rbank ? wbank ? read_or_write::READWRITE : read_or_write::READ : read_or_write::WRITE); +} diff --git a/src/mame/drivers/simpsons.cpp b/src/mame/drivers/simpsons.cpp index 86fb6c95c783b..356baeda1f981 100644 --- a/src/mame/drivers/simpsons.cpp +++ b/src/mame/drivers/simpsons.cpp @@ -118,8 +118,8 @@ GX072 PWB352346B void simpsons_state::main_map(address_map &map) { map(0x0000, 0x1fff).rw(m_k052109, FUNC(k052109_device::read), FUNC(k052109_device::write)); - map(0x0000, 0x0fff).m(m_bank0000, FUNC(address_map_bank_device::amap8)); - map(0x2000, 0x3fff).m(m_bank2000, FUNC(address_map_bank_device::amap8)); + map(0x0000, 0x0fff).view(m_palette_view); + m_palette_view[0](0x0000, 0x0fff).ram().w("palette", FUNC(palette_device::write8)).share("palette"); map(0x1f80, 0x1f80).portr("COIN"); map(0x1f81, 0x1f81).portr("TEST"); map(0x1f90, 0x1f90).portr("P1"); @@ -134,24 +134,15 @@ void simpsons_state::main_map(address_map &map) map(0x1fc6, 0x1fc7).rw("k053260", FUNC(k053260_device::main_read), FUNC(k053260_device::main_write)); map(0x1fc8, 0x1fc9).r(m_k053246, FUNC(k053247_device::k053246_r)); map(0x1fca, 0x1fca).r("watchdog", FUNC(watchdog_timer_device::reset_r)); + map(0x2000, 0x3fff).view(m_video_view); + m_video_view[0](0x2000, 0x3fff).rw(FUNC(simpsons_state::simpsons_k052109_r), FUNC(simpsons_state::simpsons_k052109_w)); + m_video_view[1](0x2000, 0x2fff).rw(FUNC(simpsons_state::simpsons_k053247_r), FUNC(simpsons_state::simpsons_k053247_w)); + m_video_view[1](0x3000, 0x3fff).ram(); map(0x4000, 0x5fff).ram(); map(0x6000, 0x7fff).bankr("bank1"); map(0x8000, 0xffff).rom().region("maincpu", 0x78000); } -void simpsons_state::bank0000_map(address_map &map) -{ - map(0x0000, 0x0fff).rw(m_k052109, FUNC(k052109_device::read), FUNC(k052109_device::write)); - map(0x1000, 0x1fff).ram().w("palette", FUNC(palette_device::write8)).share("palette"); -} - -void simpsons_state::bank2000_map(address_map &map) -{ - map(0x0000, 0x1fff).rw(FUNC(simpsons_state::simpsons_k052109_r), FUNC(simpsons_state::simpsons_k052109_w)); - map(0x2000, 0x2fff).rw(FUNC(simpsons_state::simpsons_k053247_r), FUNC(simpsons_state::simpsons_k053247_w)); - map(0x3000, 0x3fff).ram(); -} - void simpsons_state::z80_bankswitch_w(uint8_t data) { membank("bank2")->set_entry(data & 7); @@ -331,9 +322,6 @@ void simpsons_state::simpsons(machine_config &config) Z80(config, m_audiocpu, XTAL(3'579'545)); /* verified on pcb */ m_audiocpu->set_addrmap(AS_PROGRAM, &simpsons_state::z80_map); /* NMIs are generated by the 053260 */ - ADDRESS_MAP_BANK(config, "bank0000").set_map(&simpsons_state::bank0000_map).set_options(ENDIANNESS_BIG, 8, 13, 0x1000); - ADDRESS_MAP_BANK(config, "bank2000").set_map(&simpsons_state::bank2000_map).set_options(ENDIANNESS_BIG, 8, 14, 0x2000); - EEPROM_ER5911_8BIT(config, "eeprom"); WATCHDOG_TIMER(config, "watchdog"); diff --git a/src/mame/includes/simpsons.h b/src/mame/includes/simpsons.h index 69a9dbfa98c27..7a7669653788a 100644 --- a/src/mame/includes/simpsons.h +++ b/src/mame/includes/simpsons.h @@ -17,10 +17,10 @@ class simpsons_state : public driver_device public: simpsons_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), + m_palette_view(*this, "palette_view"), + m_video_view(*this, "video_view"), m_maincpu(*this, "maincpu"), m_audiocpu(*this, "audiocpu"), - m_bank0000(*this, "bank0000"), - m_bank2000(*this, "bank2000"), m_k052109(*this, "k052109"), m_k053246(*this, "k053246"), m_k053251(*this, "k053251") @@ -47,11 +47,13 @@ class simpsons_state : public driver_device int m_firq_enabled; u64 m_nmi_enabled; + /* views */ + memory_view m_palette_view; + memory_view m_video_view; + /* devices */ required_device m_maincpu; required_device m_audiocpu; - required_device m_bank0000; - required_device m_bank2000; required_device m_k052109; required_device m_k053246; required_device m_k053251; diff --git a/src/mame/video/simpsons.cpp b/src/mame/video/simpsons.cpp index 2caafb9bac054..1c43114823d9e 100644 --- a/src/mame/video/simpsons.cpp +++ b/src/mame/video/simpsons.cpp @@ -77,8 +77,11 @@ void simpsons_state::simpsons_k053247_w(offs_t offset, uint8_t data) void simpsons_state::simpsons_video_banking( int bank ) { - m_bank0000->set_bank(bank & 1); - m_bank2000->set_bank((bank >> 1) & 1); + if(bank & 1) + m_palette_view.select(0); + else + m_palette_view.disable(); + m_video_view.select((bank >> 1) & 1); }