diff options
author | Olivier Galibert <galibert@pobox.com> | 2020-11-02 12:11:43 +0100 |
---|---|---|
committer | Olivier Galibert <galibert@pobox.com> | 2020-11-02 12:12:11 +0100 |
commit | b8c338858a101d14308c64c87b0f714db4f05326 (patch) | |
tree | a34dca21d603b98f5450d31868ce33a7e4c103b0 /src/emu | |
parent | f4172ded3ec6f3b877ab813f6453d6d1907c1c00 (diff) |
emumem: Simplify memory management. [O. Galibert]
API impact:
- install_ram/rom/writeonly now requires a non-null pointer. If you want
automatically managed ram, add it to a memory map, not in machine_start
- install_*_bank now requires a memory_bank *, not a string
- one can create memory banks outside of memory maps with memory_bank_creator
- one can create memory shares outside of memory maps with memory_share_creator
Memory maps impact:
- ram ranges with overlapping addresses are not shared anymore. Use .share()
- ram ranges touching each other are not merged anymore. Stay in your range
Extra note:
- there is no need to create a bank just to dynamically map some memory/rom.
Just use install_rom/ram/writeonly
Diffstat (limited to 'src/emu')
-rw-r--r-- | src/emu/addrmap.cpp | 23 | ||||
-rw-r--r-- | src/emu/devfind.cpp | 96 | ||||
-rw-r--r-- | src/emu/devfind.h | 124 | ||||
-rw-r--r-- | src/emu/diimage.cpp | 7 | ||||
-rw-r--r-- | src/emu/diimage.h | 6 | ||||
-rw-r--r-- | src/emu/dimemory.h | 2 | ||||
-rw-r--r-- | src/emu/dirom.h | 2 | ||||
-rw-r--r-- | src/emu/dirom.ipp | 6 | ||||
-rw-r--r-- | src/emu/emufwd.h | 1 | ||||
-rw-r--r-- | src/emu/emumem.cpp | 787 | ||||
-rw-r--r-- | src/emu/emumem.h | 172 | ||||
-rw-r--r-- | src/emu/emumem_hem.h | 8 | ||||
-rw-r--r-- | src/emu/romload.cpp | 4 |
13 files changed, 452 insertions, 786 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp index 604e05ab864..ebc0331a767 100644 --- a/src/emu/addrmap.cpp +++ b/src/emu/addrmap.cpp @@ -1148,18 +1148,33 @@ void address_map::map_validity_check(validity_checker &valid, int spacenum) cons osd_printf_error("In %s memory range %x-%x, mirror %x touches a select bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & entry.m_addrselect); // if this is a program space, auto-assign implicit ROM entries - if (entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr) + if (entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr && spacenum == AS_PROGRAM && entry.m_share == nullptr) { entry.m_region = m_device->tag(); entry.m_rgnoffs = entry.m_addrstart; } + // detect conflicts between region and share + if (entry.m_region && entry.m_share) + osd_printf_error("%s space memory map entry %X-%X has both .region() and .share()\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend); + + + // Detect inaccesible memory. Region automapping is handled before + if (entry.m_read.m_type == AMH_ROM && entry.m_write.m_type != AMH_RAM && + !entry.m_share && !entry.m_region) + osd_printf_error("%s space memory map entry %X-%X has .rom() but no .region() or .share()\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend); + if (entry.m_read.m_type != AMH_RAM && entry.m_write.m_type == AMH_RAM && + !entry.m_share) + osd_printf_error("%s space memory map entry %X-%X has .writeonly() but no .share()\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend); + // if this entry references a memory region, validate it - if (entry.m_region != nullptr && entry.m_share == nullptr) + if (entry.m_region != nullptr) { // address map entries that reference regions but are NOPs are pointless - if (entry.m_read.m_type == AMH_NONE && entry.m_write.m_type == AMH_NONE) - osd_printf_error("%s space references memory region %s, but is noprw()\n", spaceconfig.m_name, entry.m_region); + if (entry.m_read.m_type != AMH_ROM && entry.m_read.m_type != AMH_RAM) + osd_printf_error("%s space memory map entry %X-%X references memory region %s, but can't read it\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); + if (entry.m_write.m_type == AMH_RAM) + osd_printf_error("%s space memory map entry %X-%X references memory region %s, but wants to write to it\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region); // make sure we can resolve the full path to the region bool found = false; diff --git a/src/emu/devfind.cpp b/src/emu/devfind.cpp index b2506e2fce3..a2f9551051a 100644 --- a/src/emu/devfind.cpp +++ b/src/emu/devfind.cpp @@ -78,18 +78,8 @@ void *finder_base::find_memregion(u8 width, size_t &length, bool required) const return nullptr; } - // check the length and warn if other than specified - size_t const length_found = region->bytes() / width; - if (length != 0 && length != length_found) - { - if (required) - osd_printf_warning("Region '%s' found but has %d bytes, not %d as requested\n", m_tag, region->bytes(), length * width); - length = 0; - return nullptr; - } - // return results - length = length_found; + length = region->bytes()/width; return region->base(); } @@ -98,7 +88,7 @@ void *finder_base::find_memregion(u8 width, size_t &length, bool required) const // validate_memregion - find memory region //------------------------------------------------- -bool finder_base::validate_memregion(size_t bytes, bool required) const +bool finder_base::validate_memregion(bool required) const { // make sure we can resolve the full path to the region size_t bytes_found = 0; @@ -119,13 +109,6 @@ bool finder_base::validate_memregion(size_t bytes, bool required) const break; } - // check the length and warn if other than specified - if ((bytes_found != 0) && (bytes != 0) && (bytes != bytes_found)) - { - osd_printf_warning("Region '%s' found but has %d bytes, not %d as requested\n", m_tag, bytes_found, bytes); - bytes_found = 0; - } - return report_missing(bytes_found != 0, "memory region", required); } @@ -274,7 +257,7 @@ template <bool Required> bool memory_region_finder<Required>::findit(validity_checker *valid) { if (valid) - return this->validate_memregion(0, Required); + return this->validate_memregion(Required); assert(!this->m_resolved); this->m_resolved = true; @@ -333,7 +316,6 @@ bool ioport_finder<Required>::findit(validity_checker *valid) } - //************************************************************************** // ADDRESS SPACE FINDER //************************************************************************** @@ -360,6 +342,74 @@ bool address_space_finder<Required>::findit(validity_checker *valid) } +//************************************************************************** +// MEMORY BANK CREATOR +//************************************************************************** + +bool memory_bank_creator::findit(validity_checker *valid) +{ + if (valid) + return true; + + device_t &dev = m_base.get(); + memory_manager &manager = dev.machine().memory(); + std::string tag = dev.subtag(m_tag); + memory_bank *bank = manager.bank_find(tag); + if (bank) + m_target = bank; + else + m_target = manager.bank_alloc(dev, tag); + return true; +} + +void memory_bank_creator::end_configuration() +{ + m_target = nullptr; +} + + +//************************************************************************** +// MEMORY SHARE CREATOR +//************************************************************************** + +template<typename uX> memory_share_creator<uX>::memory_share_creator(device_t &base, char const *tag, size_t bytes, endianness_t endianness) + : finder_base(base, tag) + , m_width(sizeof(uX)*8) + , m_bytes(bytes) + , m_endianness(endianness) +{ +} + +template<typename uX> bool memory_share_creator<uX>::findit(validity_checker *valid) +{ + if (valid) + return true; + + device_t &dev = m_base.get(); + memory_manager &manager = dev.machine().memory(); + std::string tag = dev.subtag(m_tag); + memory_share *share = manager.share_find(tag); + if (share) + { + m_target = share; + std::string result = share->compare(m_width, m_bytes, m_endianness); + if (!result.empty()) + { + osd_printf_error("%s\n", result); + return false; + } + } + else + m_target = manager.share_alloc(dev, tag, m_width, m_bytes, m_endianness); + return true; +} + +template<typename uX> void memory_share_creator<uX>::end_configuration() +{ + m_target = nullptr; +} + + //************************************************************************** // EXPLICIT TEMPLATE INSTANTIATIONS @@ -439,3 +489,7 @@ template class shared_ptr_finder<s32, false>; template class shared_ptr_finder<s32, true>; template class shared_ptr_finder<s64, false>; template class shared_ptr_finder<s64, true>; +template class memory_share_creator<u8>; +template class memory_share_creator<u16>; +template class memory_share_creator<u32>; +template class memory_share_creator<u64>; diff --git a/src/emu/devfind.h b/src/emu/devfind.h index 958ae16c3bc..d9e2e95df21 100644 --- a/src/emu/devfind.h +++ b/src/emu/devfind.h @@ -356,7 +356,7 @@ protected: /// it is optional. /// \return True if the region is optional, or if the region is /// required and a matching region is found, or false otherwise. - bool validate_memregion(size_t bytes, bool required) const; + bool validate_memregion(bool required) const; /// \brief Find a memory share /// @@ -753,6 +753,94 @@ template <unsigned Count, bool Required> using memory_bank_array_finder = object template <unsigned Count> using optional_memory_bank_array = memory_bank_array_finder<Count, false>; template <unsigned Count> using required_memory_bank_array = memory_bank_array_finder<Count, true>; +/// \brief Memory bank creator +/// +/// Creates a memory bank or picks up an existing one. +class memory_bank_creator : finder_base +{ +public: + memory_bank_creator(device_t &base, char const *tag) : finder_base(base, tag) { } + virtual ~memory_bank_creator() = default; + + /// \brief Get pointer to target bank object + /// \return Pointer to target bank object if found, or nullptr otherwise. + memory_bank *target() const { return m_target; } + + /// \brief Cast-to-pointer operator + /// + /// Allows implicit casting to a pointer to the target bank object. + /// \return Pointer to target bank object + operator memory_bank *() const { return m_target; } + + /// \brief Pointer member access operator + /// + /// Allows pointer-member-style access to members of the target + /// bank object. + /// \return Pointer to target bank object + memory_bank *operator->() const { return m_target; } + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; + + /// \brief Pointer to target object + /// + /// Pointer to target object, or nullptr if the creation has not been + /// attempted yet. + memory_bank *m_target = nullptr; +}; + +template <unsigned Count> using memory_bank_array_creator = object_array_finder<memory_bank_creator, Count>; + +/// \brief Memory share creator +/// +/// Creates a memory share or picks up an existing one. +template<typename uX> class memory_share_creator : finder_base +{ +public: + memory_share_creator(device_t &base, char const *tag, size_t bytes, endianness_t endianness); + virtual ~memory_share_creator() = default; + + /// \brief Get pointer to the share object + /// \return Pointer to share object. + memory_share *share() const { return m_target; } + + /// \brief Get pointer to the share object backing ram + /// \return Pointer to the ram. + uX *ptr() const { return reinterpret_cast<uX *>(m_target->ptr()); } + + /// \brief Cast-to-pointer operator + /// + /// Allows implicit casting to a pointer to the target bank object. + /// \return Pointer to target bank object + operator uX *() const { return reinterpret_cast<uX *>(m_target->ptr()); } + + /// \brief Pointer member access operator + /// + /// Allows pointer-member-style access to members of the target + /// bank object. + /// \return Pointer to target bank object + memory_share *operator->() const { return m_target; } + + size_t bytes() const { return m_target->bytes(); } + endianness_t endianness() const { return m_target->endianness(); } + u8 bitwidth() const { return m_target->bitwidth(); } + u8 bytewidth() const { return m_target->bytewidth(); } + +protected: + virtual bool findit(validity_checker *valid) override; + virtual void end_configuration() override; + + /// \brief Pointer to target object + /// + /// Pointer to target object, or nullptr if the creation has not been + /// attempted yet. + memory_share *m_target = nullptr; + + const u8 m_width; // width of the shared region in bits + const size_t m_bytes; // size of the shared region in bytes + const endianness_t m_endianness; // endianness of the memory +}; /// \brief I/O port finder template /// @@ -939,9 +1027,8 @@ public: /// pointer remains valid until resolution time. /// \param [in] length Desired memory region length in units of the /// size of the element type, or zero to match any region length. - region_ptr_finder(device_t &base, char const *tag, size_t length = 0) + region_ptr_finder(device_t &base, char const *tag) : object_finder_base<PointerType, Required>(base, tag) - , m_desired_length(length) , m_length(0) { } @@ -990,21 +1077,15 @@ private: virtual bool findit(validity_checker *valid) override { if (valid) - return this->validate_memregion(sizeof(PointerType) * m_desired_length, Required); + return this->validate_memregion(Required); assert(!this->m_resolved); this->m_resolved = true; - m_length = m_desired_length; this->m_target = reinterpret_cast<PointerType *>(this->find_memregion(sizeof(PointerType), m_length, Required)); return this->report_missing("memory region"); } - /// \brief Desired region length - /// - /// Desired region length in units of elements. - size_t const m_desired_length; - - /// \brief Matched region length + /// \brief Region length /// /// Actual length of the region that was found in units of /// elements, or zero if no matching region has been found. @@ -1043,11 +1124,9 @@ class shared_ptr_finder : public object_finder_base<PointerType, Required> { public: // construction/destruction - shared_ptr_finder(device_t &base, char const *tag, u8 width = sizeof(PointerType) * 8) + shared_ptr_finder(device_t &base, char const *tag) : object_finder_base<PointerType, Required>(base, tag) - , m_width(width) , m_bytes(0) - , m_allocated(0) { } @@ -1058,19 +1137,6 @@ public: u32 bytes() const { return m_bytes; } u32 mask() const { return m_bytes - 1; } // FIXME: wrong when sizeof(PointerType) != 1 - // setter for setting the object - void set_target(PointerType *target, size_t bytes) { this->m_target = target; m_bytes = bytes; } - - // dynamic allocation of a shared pointer - void allocate(u32 entries) - { - assert(!m_allocated); - m_allocated = std::make_unique<PointerType []>(entries); - this->m_target = m_allocated.get(); - m_bytes = entries * sizeof(PointerType); - this->m_base.get().save_pointer(m_allocated, this->m_tag, entries); - } - private: // finder virtual bool findit(validity_checker *valid) override @@ -1080,14 +1146,12 @@ private: assert(!this->m_resolved); this->m_resolved = true; - this->m_target = reinterpret_cast<PointerType *>(this->find_memshare(m_width, m_bytes, Required)); + this->m_target = reinterpret_cast<PointerType *>(this->find_memshare(sizeof(PointerType)*8, m_bytes, Required)); return this->report_missing("shared pointer"); } // internal state - u8 const m_width; size_t m_bytes; - std::unique_ptr<PointerType []> m_allocated; }; template <typename PointerType> using optional_shared_ptr = shared_ptr_finder<PointerType, false>; diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 548281062a3..db890ad3d8c 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -479,15 +479,14 @@ const char *device_image_interface::get_feature(const char *feature_name) const // load_software_region - //------------------------------------------------- -bool device_image_interface::load_software_region(const char *tag, optional_shared_ptr<u8> &ptr) +bool device_image_interface::load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr) { size_t size = get_software_region_length(tag); if (size) { - ptr.allocate(size); - - memcpy(ptr, get_software_region(tag), size); + ptr = std::make_unique<u8[]>(size); + memcpy(ptr.get(), get_software_region(tag), size); } return size > 0; diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 2f9421bcf4d..9f67530383f 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -164,8 +164,8 @@ public: u64 length() { check_for_file(); return m_file->size(); } bool is_readonly() const noexcept { return m_readonly; } u32 fread(void *buffer, u32 length) { check_for_file(); return m_file->read(buffer, length); } - u32 fread(optional_shared_ptr<u8> &ptr, u32 length) { ptr.allocate(length); return fread(ptr.target(), length); } - u32 fread(optional_shared_ptr<u8> &ptr, u32 length, offs_t offset) { ptr.allocate(length); return fread(ptr + offset, length - offset); } + u32 fread(std::unique_ptr<u8[]> &ptr, u32 length) { ptr = std::make_unique<u8[]>(length); return fread(ptr.get(), length); } + u32 fread(std::unique_ptr<u8[]> &ptr, u32 length, offs_t offset) { ptr = std::make_unique<u8[]>(length); return fread(ptr.get() + offset, length - offset); } u32 fwrite(const void *buffer, u32 length) { check_for_file(); return m_file->write(buffer, length); } int fseek(s64 offset, int whence) { check_for_file(); return m_file->seek(offset, whence); } u64 ftell() { check_for_file(); return m_file->tell(); } @@ -191,7 +191,7 @@ public: u8 *get_software_region(const char *tag); u32 get_software_region_length(const char *tag); const char *get_feature(const char *feature_name) const; - bool load_software_region(const char *tag, optional_shared_ptr<u8> &ptr); + bool load_software_region(const char *tag, std::unique_ptr<u8[]> &ptr); u32 crc(); util::hash_collection& hash() { return m_hash; } diff --git a/src/emu/dimemory.h b/src/emu/dimemory.h index 3d43c6a6a4d..ed177882d37 100644 --- a/src/emu/dimemory.h +++ b/src/emu/dimemory.h @@ -103,8 +103,6 @@ public: } void prepare_maps() { for (auto const &space : m_addrspace) { if (space) { space->prepare_map(); } } } void populate_from_maps() { for (auto const &space : m_addrspace) { if (space) { space->populate_from_map(); } } } - void allocate_memory() { for (auto const &space : m_addrspace) { if (space) { space->allocate_memory(); } } } - void locate_memory() { for (auto const &space : m_addrspace) { if (space) { space->locate_memory(); } } } void set_log_unmap(bool log) { for (auto const &space : m_addrspace) { if (space) { space->set_log_unmap(log); } } } protected: diff --git a/src/emu/dirom.h b/src/emu/dirom.h index 62566f433d3..c5dd94fedae 100644 --- a/src/emu/dirom.h +++ b/src/emu/dirom.h @@ -41,7 +41,7 @@ private: address_space_config m_rom_config; typename memory_access<AddrWidth, DataWidth, AddrShift, Endian>::cache m_rom_cache; - memory_bank *m_bank; + memory_bank_creator m_bank; int m_cur_bank, m_bank_count; virtual void interface_pre_start() override; diff --git a/src/emu/dirom.ipp b/src/emu/dirom.ipp index e552ff87e22..42904bf27fd 100644 --- a/src/emu/dirom.ipp +++ b/src/emu/dirom.ipp @@ -6,7 +6,7 @@ device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::device_rom_interf device_memory_interface(mconfig, device), m_rom_tag(device.basetag()), m_rom_config("rom", Endian, 8 << DataWidth, AddrWidth, AddrShift), - m_bank(nullptr), + m_bank(device, "bank"), m_cur_bank(-1) { } @@ -64,9 +64,9 @@ void device_rom_interface<AddrWidth, DataWidth, AddrShift, Endian>::set_rom(cons m_bank_count = 1; if(rend >= mend) { - space().install_read_bank(0, mend, device().tag()); - m_bank = device().machine().memory().banks().find(device().tag())->second.get(); + space().install_read_bank(0, mend, m_bank); m_bank->configure_entries(0, m_bank_count, const_cast<void *>(base), mend+1); + m_bank->set_entry(0); m_cur_bank = 0; } else { diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h index bd7d2235a15..b09eb098221 100644 --- a/src/emu/emufwd.h +++ b/src/emu/emufwd.h @@ -146,7 +146,6 @@ class driver_device; // declared in emumem.h class address_space; class memory_bank; -class memory_block; class memory_manager; class memory_region; class memory_share; diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp index a245c39fd3f..8fb0f0bbe28 100644 --- a/src/emu/emumem.cpp +++ b/src/emu/emumem.cpp @@ -30,9 +30,16 @@ // DEBUGGING //************************************************************************** -#define VERBOSE (0) +#define VERBOSE 0 -#define VPRINTF(x) do { if (VERBOSE) printf x; } while (0) +#if VERBOSE +template <typename Format, typename... Params> static void VPRINTF(Format &&fmt, Params &&...args) +{ + util::stream_format(std::cerr, std::forward<Format>(fmt), std::forward<Params>(args)...); +} +#else +template <typename Format, typename... Params> static void VPRINTF(Format &&, Params &&...) {} +#endif #define VALIDATE_REFCOUNTS 0 @@ -269,10 +276,6 @@ template <> struct handler_width<write64s_delegate> { static constexpr int value template <> struct handler_width<write64sm_delegate> { static constexpr int value = 3; }; template <> struct handler_width<write64mo_delegate> { static constexpr int value = 3; }; template <> struct handler_width<write64smo_delegate> { static constexpr int value = 3; }; - -// other address map constants -const int MEMORY_BLOCK_CHUNK = 65536; // minimum chunk size of allocated memory blocks - } // anonymous namespace @@ -307,7 +310,6 @@ public: 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, std::string rtag, std::string wtag) 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; @@ -713,11 +715,11 @@ private: template<int AccessWidth, typename READ> std::enable_if_t<(Width == AccessWidth)> 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) { - VPRINTF(("address_space::install_read_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_r.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -734,11 +736,11 @@ private: 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) { - VPRINTF(("address_space::install_read_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_r.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -765,11 +767,11 @@ private: 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) { - VPRINTF(("address_space::install_write_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -786,11 +788,11 @@ private: 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) { - VPRINTF(("address_space::install_write_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -820,11 +822,11 @@ private: const READ &handler_r, const WRITE &handler_w) { - VPRINTF(("address_space::install_readwrite_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_r.name(), handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -847,11 +849,11 @@ private: const READ &handler_r, const WRITE &handler_w) { - VPRINTF(("address_space::install_readwrite_handler(%s-%s mask=%s mirror=%s, space width=%d, handler width=%d, %s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars), - 8 << Width, 8 << AccessWidth, - handler_r.name(), handler_w.name(), core_i64_hex_format(unitmask, data_width() / 4))); + 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; @@ -894,9 +896,18 @@ private: //------------------------------------------------- memory_manager::memory_manager(running_machine &machine) - : m_machine(machine), - m_initialized(false) + : m_machine(machine) +{ +} + +//------------------------------------------------- +// ~memory_manager - free the allocated memory banks +//------------------------------------------------- + +memory_manager::~memory_manager() { + for(void *ptr : m_datablocks) + free(ptr); } //------------------------------------------------- @@ -1012,38 +1023,51 @@ void memory_manager::initialize() for (auto const memory : memories) memory->populate_from_maps(); - // allocate memory needed to back each address space - for (auto const memory : memories) - memory->allocate_memory(); - - // find all the allocated pointers - for (auto const memory : memories) - memory->locate_memory(); - // disable logging of unmapped access when no one receives it if (!machine().options().log() && !machine().options().oslog() && !(machine().debug_flags & DEBUG_FLAG_ENABLED)) for (auto const memory : memories) memory->set_log_unmap(false); +} - // we are now initialized - m_initialized = true; + +//------------------------------------------------- +// allocate_memory - allocate some ram and register it for saving +//------------------------------------------------- + +void *memory_manager::allocate_memory(device_t &dev, int spacenum, std::string name, u8 width, size_t bytes) +{ + void *ptr = malloc(bytes); + memset(ptr, 0, bytes); + m_datablocks.push_back(ptr); + machine().save().save_memory(&dev, "memory", dev.tag(), spacenum, name.c_str(), ptr, width/8, (u32)bytes / (width/8)); + return ptr; } + //------------------------------------------------- // region_alloc - allocates memory for a region //------------------------------------------------- -memory_region *memory_manager::region_alloc(const char *name, u32 length, u8 width, endianness_t endian) +memory_region *memory_manager::region_alloc(std::string name, u32 length, u8 width, endianness_t endian) { - osd_printf_verbose("Region '%s' created\n", name); // make sure we don't have a region of the same name; also find the end of the list if (m_regionlist.find(name) != m_regionlist.end()) fatalerror("region_alloc called with duplicate region name \"%s\"\n", name); // allocate the region - m_regionlist.emplace(name, std::make_unique<memory_region>(machine(), name, length, width, endian)); - return m_regionlist.find(name)->second.get(); + return m_regionlist.emplace(name, std::make_unique<memory_region>(machine(), name, length, width, endian)).first->second.get(); +} + + +//------------------------------------------------- +// region_find - find a region by name +//------------------------------------------------- + +memory_region *memory_manager::region_find(std::string name) +{ + auto i = m_regionlist.find(name); + return i != m_regionlist.end() ? i->second.get() : nullptr; } @@ -1051,61 +1075,82 @@ memory_region *memory_manager::region_alloc(const char *name, u32 length, u8 wid // region_free - releases memory for a region //------------------------------------------------- -void memory_manager::region_free(const char *name) +void memory_manager::region_free(std::string name) { m_regionlist.erase(name); } //------------------------------------------------- -// region_containing - helper to determine if -// a block of memory is part of a region +// anonymous_alloc - allocates a anonymousd memory zone //------------------------------------------------- -memory_region *memory_manager::region_containing(const void *memory, offs_t bytes) const +void *memory_manager::anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end) { - const u8 *data = reinterpret_cast<const u8 *>(memory); + std::string name = util::string_format("%x-%x", start, end); + return allocate_memory(space.device(), space.spacenum(), name, width, bytes); +} - // look through the region list and return the first match - for (auto ®ion : m_regionlist) - if (data >= region.second->base() && (data + bytes) <= region.second->end()) - return region.second.get(); - // didn't find one - return nullptr; +//------------------------------------------------- +// share_alloc - allocates a shared memory zone +//------------------------------------------------- + +memory_share *memory_manager::share_alloc(device_t &dev, std::string name, u8 width, size_t bytes, endianness_t endianness) +{ + // make sure we don't have a share of the same name; also find the end of the list + if (m_sharelist.find(name) != m_sharelist.end()) + fatalerror("share_alloc called with duplicate share name \"%s\"\n", name); + + // allocate and register the memory + void *ptr = allocate_memory(dev, 0, name, width, bytes); + + // allocate the region + return m_sharelist.emplace(name, std::make_unique<memory_share>(name, width, bytes, endianness, ptr)).first->second.get(); } -memory_bank *memory_manager::find(const char *tag) const + +//------------------------------------------------- +// share_find - find a share by name +//------------------------------------------------- + +memory_share *memory_manager::share_find(std::string name) { - auto bank = m_banklist.find(tag); - if (bank != m_banklist.end()) - return bank->second.get(); - return nullptr; + auto i = m_sharelist.find(name); + return i != m_sharelist.end() ? i->second.get() : nullptr; } -memory_bank *memory_manager::find(address_space &space, offs_t addrstart, offs_t addrend) const + + +//------------------------------------------------- +// share_alloc - allocates a banking zone +//------------------------------------------------- + +memory_bank *memory_manager::bank_alloc(device_t &device, std::string name) { - // try to find an exact match - for (auto &bank : m_banklist) - if (bank.second->anonymous() && bank.second->references_space(space, read_or_write::READWRITE) && bank.second->matches_exactly(addrstart, addrend)) - return bank.second.get(); + // allocate the bank + auto const ins = m_banklist.emplace(name, std::make_unique<memory_bank>(device, name)); - // not found - return nullptr; + // make sure we don't have a bank of the same name + if (!ins.second) + fatalerror("bank_alloc called with duplicate bank name \"%s\"\n", name); + + return ins.first->second.get(); } -memory_bank *memory_manager::allocate(address_space &space, offs_t addrstart, offs_t addrend, const char *tag) + +//------------------------------------------------- +// bank_find - find a bank by name +//------------------------------------------------- + +memory_bank *memory_manager::bank_find(std::string name) { - auto bank = std::make_unique<memory_bank>(space, m_banklist.size(), addrstart, addrend, tag); - std::string temptag; - if (tag == nullptr) { - temptag = string_format("anon_%p", bank.get()); - tag = temptag.c_str(); - } - m_banklist.emplace(tag, std::move(bank)); - return m_banklist.find(tag)->second.get(); + auto i = m_banklist.find(name); + return i != m_banklist.end() ? i->second.get() : nullptr; } + + //************************************************************************** // ADDRESS SPACE CONFIG //************************************************************************** @@ -1412,15 +1457,23 @@ void address_space::prepare_map() { // if we can't find it, add it to our map std::string fulltag = entry.m_devbase.subtag(entry.m_share); - if (m_manager.m_sharelist.find(fulltag) == m_manager.m_sharelist.end()) + 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)); - m_manager.m_sharelist.emplace(fulltag.c_str(), std::make_unique<memory_share>(m_config.data_width(), address_to_byte(entry.m_addrend + 1 - entry.m_addrstart), endianness())); + 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, attach it to the implicit region - if (m_spacenum == 0 && entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr) + // 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) @@ -1431,7 +1484,7 @@ void address_space::prepare_map() } // validate adjusted addresses against implicit regions - if (entry.m_region != nullptr && entry.m_share == nullptr) + if (entry.m_region != nullptr) { // determine full tag std::string fulltag = entry.m_devbase.subtag(entry.m_region); @@ -1444,6 +1497,9 @@ void address_space::prepare_map() // 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 @@ -1455,6 +1511,10 @@ void address_space::prepare_map() // 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); } } @@ -1509,7 +1569,7 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w // fall through to the RAM case otherwise case AMH_RAM: - install_ram_generic(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, readorwrite, nullptr); + install_ram_generic(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, readorwrite, entry.m_memory); break; case AMH_NOP: @@ -1641,167 +1701,22 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w break; case AMH_BANK: - install_bank_generic(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, - (readorwrite == read_or_write::READ) ? entry.m_devbase.subtag(data.m_tag) : "", - (readorwrite == read_or_write::WRITE) ? entry.m_devbase.subtag(data.m_tag) : ""); + { + std::string tag = entry.m_devbase.subtag(data.m_tag); + memory_bank *bank = m_manager.bank_find(tag); + if (!bank) + bank = m_manager.bank_alloc(entry.m_devbase, tag); + install_bank_generic(entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, + (readorwrite == read_or_write::READ) ? bank : nullptr, + (readorwrite == read_or_write::WRITE) ? bank : nullptr); break; + } case AMH_DEVICE_SUBMAP: throw emu_fatalerror("Internal mapping error: leftover mapping of '%s'.\n", data.m_tag); } } -//------------------------------------------------- -// allocate_memory - determine all neighboring -// address ranges and allocate memory to back -// them -//------------------------------------------------- - -void address_space::allocate_memory() -{ - auto &blocklist = m_manager.m_blocklist; - - // make a first pass over the memory map and track blocks with hardcoded pointers - // we do this to make sure they are found by space_find_backing_memory first - // do it back-to-front so that overrides work correctly - int tail = blocklist.size(); - for (address_map_entry &entry : m_map->m_entrylist) - if (entry.m_memory != nullptr) - blocklist.insert(blocklist.begin() + tail, std::make_unique<memory_block>(*this, entry.m_addrstart, entry.m_addrend, entry.m_memory)); - - // loop over all blocks just allocated and assign pointers from them - address_map_entry *unassigned = nullptr; - - for (auto memblock = blocklist.begin() + tail; memblock != blocklist.end(); ++memblock) - unassigned = block_assign_intersecting(memblock->get()->addrstart(), memblock->get()->addrend(), memblock->get()->data()); - - // if we don't have an unassigned pointer yet, try to find one - if (unassigned == nullptr) - unassigned = block_assign_intersecting(~0, 0, nullptr); - - // loop until we've assigned all memory in this space - while (unassigned != nullptr) - { - // work in MEMORY_BLOCK_CHUNK-sized chunks - offs_t curblockstart = unassigned->m_addrstart / MEMORY_BLOCK_CHUNK; - offs_t curblockend = unassigned->m_addrend / MEMORY_BLOCK_CHUNK; - - // loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_CHUNK chunks - bool changed; - do - { - changed = false; - - // scan for unmapped blocks in the adjusted map - for (address_map_entry &entry : m_map->m_entrylist) - if (entry.m_memory == nullptr && &entry != unassigned && needs_backing_store(entry)) - { - // get block start/end blocks for this block - offs_t blockstart = entry.m_addrstart / MEMORY_BLOCK_CHUNK; - offs_t blockend = entry.m_addrend / MEMORY_BLOCK_CHUNK; - - // if we intersect or are adjacent, adjust the start/end - if (blockstart <= curblockend + 1 && blockend >= curblockstart - 1) - { - if (blockstart < curblockstart) - curblockstart = blockstart, changed = true; - if (blockend > curblockend) - curblockend = blockend, changed = true; - } - } - } while (changed); - - // we now have a block to allocate; do it - offs_t curaddrstart = curblockstart * MEMORY_BLOCK_CHUNK; - offs_t curaddrend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1); - auto block = std::make_unique<memory_block>(*this, curaddrstart, curaddrend); - - // assign memory that intersected the new block - unassigned = block_assign_intersecting(curaddrstart, curaddrend, block.get()->data()); - blocklist.push_back(std::move(block)); - } -} - - -//------------------------------------------------- -// locate_memory - find all the requested -// pointers into the final allocated memory -//------------------------------------------------- - -void address_space::locate_memory() -{ - // once this is done, find the starting bases for the banks - for (auto &bank : m_manager.banks()) - if (bank.second->base() == nullptr && bank.second->references_space(*this, read_or_write::READWRITE)) - { - // set the initial bank pointer - for (address_map_entry &entry : m_map->m_entrylist) - if (entry.m_addrstart == bank.second->addrstart() && entry.m_memory != nullptr) - { - bank.second->set_base(entry.m_memory); - VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank.second->tag(), entry.m_addrstart, entry.m_addrend, entry.m_memory)); - break; - } - } -} - - - - -//------------------------------------------------- -// block_assign_intersecting - find all -// intersecting blocks and assign their pointers -//------------------------------------------------- - -address_map_entry *address_space::block_assign_intersecting(offs_t addrstart, offs_t addrend, u8 *base) -{ - address_map_entry *unassigned = nullptr; - - // loop over the adjusted map and assign memory to any blocks we can - for (address_map_entry &entry : m_map->m_entrylist) - { - // if we haven't assigned this block yet, see if we have a mapped shared pointer for it - if (entry.m_memory == nullptr && entry.m_share != nullptr) - { - std::string fulltag = entry.m_devbase.subtag(entry.m_share); - auto share = m_manager.shares().find(fulltag); - if (share != m_manager.shares().end() && share->second->ptr() != nullptr) - { - entry.m_memory = share->second->ptr(); - VPRINTF(("memory range %08X-%08X -> shared_ptr '%s' [%p]\n", entry.m_addrstart, entry.m_addrend, entry.m_share, entry.m_memory)); - } - else - { - VPRINTF(("memory range %08X-%08X -> shared_ptr '%s' but not found\n", entry.m_addrstart, entry.m_addrend, entry.m_share)); - } - } - - // otherwise, look for a match in this block - if (entry.m_memory == nullptr && entry.m_addrstart >= addrstart && entry.m_addrend <= addrend) - { - entry.m_memory = base + m_config.addr2byte(entry.m_addrstart - addrstart); - VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, addrstart, addrend, entry.m_memory)); - } - - // if we're the first match on a shared pointer, assign it now - if (entry.m_memory != nullptr && entry.m_share != nullptr) - { - std::string fulltag = entry.m_devbase.subtag(entry.m_share); - auto share = m_manager.shares().find(fulltag); - if (share != m_manager.shares().end() && share->second->ptr() == nullptr) - { - share->second->set_ptr(entry.m_memory); - VPRINTF(("setting shared_ptr '%s' = %p\n", entry.m_share, entry.m_memory)); - } - } - - // keep track of the first unassigned entry - if (entry.m_memory == nullptr && unassigned == nullptr && needs_backing_store(entry)) - unassigned = &entry; - } - - return unassigned; -} memory_passthrough_handler *address_space::install_read_tap(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string name, std::function<void (offs_t offset, u8 &data, u8 mem_mask)> tap, memory_passthrough_handler *mph) @@ -1905,11 +1820,11 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) { - VPRINTF(("address_space::unmap(%s-%s mirror=%s, %s, %s)\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmirror, m_addrchars), - (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", - quiet ? "quiet" : "normal")); + 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); @@ -2026,10 +1941,10 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) { - VPRINTF(("address_space::install_readwrite_port(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmirror, m_addrchars), - rtag.empty() ? "(none)" : rtag.c_str(), wtag.empty() ? "(none)" : wtag.c_str())); + 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); @@ -2068,48 +1983,12 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ // mapping to a particular bank //------------------------------------------------- -template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) -{ - VPRINTF(("address_space::install_readwrite_bank(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmirror, m_addrchars), - rtag.empty() ? "(none)" : rtag.c_str(), wtag.empty() ? "(none)" : wtag.c_str())); - - offs_t nstart, nend, nmask, nmirror; - check_optimize_mirror("install_bank_generic", addrstart, addrend, addrmirror, nstart, nend, nmask, nmirror); - - // map the read bank - if (rtag != "") - { - std::string fulltag = device().siblingtag(rtag); - memory_bank &bank = bank_find_or_allocate(fulltag.c_str(), addrstart, addrend, addrmirror, read_or_write::READ); - - auto hand_r = new handler_entry_read_memory_bank<Width, AddrShift, Endian>(this, bank); - hand_r->set_address_info(nstart, nmask); - m_root_read->populate(nstart, nend, nmirror, hand_r); - } - - // map the write bank - if (wtag != "") - { - std::string fulltag = device().siblingtag(wtag); - memory_bank &bank = bank_find_or_allocate(fulltag.c_str(), addrstart, addrend, addrmirror, read_or_write::WRITE); - - auto hand_w = new handler_entry_write_memory_bank<Width, AddrShift, Endian>(this, bank); - hand_w->set_address_info(nstart, nmask); - 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); -} - - template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *rbank, memory_bank *wbank) { - VPRINTF(("address_space::install_readwrite_bank(%s-%s mirror=%s, read=\"%s\" / write=\"%s\")\n", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmirror, m_addrchars), - (rbank != nullptr) ? rbank->tag() : "(none)", (wbank != nullptr) ? wbank->tag() : "(none)")); + 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); @@ -2141,11 +2020,11 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_space_specific<Level, Width, AddrShift, Endian>::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", - core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars), - core_i64_hex_format(addrmirror, m_addrchars), - (readorwrite == read_or_write::READ) ? "read" : (readorwrite == read_or_write::WRITE) ? "write" : (readorwrite == read_or_write::READWRITE) ? "read/write" : "??", - 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); @@ -2153,39 +2032,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ // map for read if (readorwrite == read_or_write::READ || readorwrite == read_or_write::READWRITE) { - // find a bank and map it - memory_bank &bank = bank_find_or_allocate(nullptr, addrstart, addrend, addrmirror, read_or_write::READ); - - // if we are provided a pointer, set it - if (baseptr != nullptr) - bank.set_base(baseptr); - - // if we don't have a bank pointer yet, try to find one - if (bank.base() == nullptr) - { - void *backing = find_backing_memory(addrstart, addrend); - if (backing != nullptr) - bank.set_base(backing); - } - - // if we still don't have a pointer, and we're past the initialization phase, allocate a new block - if (bank.base() == nullptr && m_manager.m_initialized) - { - if (m_manager.machine().phase() >= machine_phase::RESET) - fatalerror("Attempted to call install_ram_generic() after initialization time without a baseptr!\n"); - auto block = std::make_unique<memory_block>(*this, addrstart, addrend); - bank.set_base(block.get()->data()); - m_manager.m_blocklist.push_back(std::move(block)); - } - - auto hand_r = new handler_entry_read_memory<Width, AddrShift, Endian>(this); - if (bank.base()) - hand_r->set_base(static_cast<uX *>(bank.base())); - else { - delayed_ref(hand_r); - bank.add_notifier([this, hand_r](void *base) { hand_r->set_base(static_cast<uX *>(base)); delayed_unref(hand_r); }); - } - + auto hand_r = new handler_entry_read_memory<Width, AddrShift, Endian>(this, baseptr); hand_r->set_address_info(nstart, nmask); m_root_read->populate(nstart, nend, nmirror, hand_r); } @@ -2193,39 +2040,7 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ // map for write if (readorwrite == read_or_write::WRITE || readorwrite == read_or_write::READWRITE) { - // find a bank and map it - memory_bank &bank = bank_find_or_allocate(nullptr, addrstart, addrend, addrmirror, read_or_write::WRITE); - - // if we are provided a pointer, set it - if (baseptr != nullptr) - bank.set_base(baseptr); - - // if we don't have a bank pointer yet, try to find one - if (bank.base() == nullptr) - { - void *backing = find_backing_memory(addrstart, addrend); - if (backing != nullptr) - bank.set_base(backing); - } - - // if we still don't have a pointer, and we're past the initialization phase, allocate a new block - if (bank.base() == nullptr && m_manager.m_initialized) - { - if (m_manager.machine().phase() >= machine_phase::RESET) - fatalerror("Attempted to call install_ram_generic() after initialization time without a baseptr!\n"); - auto block = std::make_unique<memory_block>(*this, address_to_byte(addrstart), address_to_byte_end(addrend)); - bank.set_base(block.get()->data()); - m_manager.m_blocklist.push_back(std::move(block)); - } - - auto hand_w = new handler_entry_write_memory<Width, AddrShift, Endian>(this); - if (bank.base()) - hand_w->set_base(static_cast<uX *>(bank.base())); - else { - delayed_ref(hand_w); - bank.add_notifier([this, hand_w](void *base) { hand_w->set_base(static_cast<uX *>(base)); delayed_unref(hand_w); }); - } - + auto hand_w = new handler_entry_write_memory<Width, AddrShift, Endian>(this, baseptr); hand_w->set_address_info(nstart, nmask); m_root_write->populate(nstart, nend, nmirror, hand_w); } @@ -2238,76 +2053,6 @@ template<int Level, int Width, int AddrShift, endianness_t Endian> void address_ // MEMORY MAPPING HELPERS //************************************************************************** -//------------------------------------------------- -// find_backing_memory - return a pointer to -// the base of RAM associated with the given -// device and offset -//------------------------------------------------- - -void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend) -{ - VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, addrstart, addrend)); - - if (m_map == nullptr) - return nullptr; - - // look in the address map first, last winning for overrides - void *result = nullptr; - for (address_map_entry &entry : m_map->m_entrylist) - { - if (entry.m_memory != nullptr && addrstart >= entry.m_addrstart && addrend <= entry.m_addrend) - { - VPRINTF(("found in entry %08X-%08X [%p]\n", entry.m_addrstart, entry.m_addrend, (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart))); - result = (u8 *)entry.m_memory + address_to_byte(addrstart - entry.m_addrstart); - } - } - if (result) - return result; - - // if not found there, look in the allocated blocks - for (auto &block : m_manager.m_blocklist) - if (block->contains(*this, addrstart, addrend)) - { - VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->addrstart(), block->addrend(), block->data() + address_to_byte(addrstart - block->addrstart()))); - return block->data() + address_to_byte(addrstart - block->addrstart()); - } - - VPRINTF(("did not find\n")); - return nullptr; -} - - -//------------------------------------------------- -// space_needs_backing_store - return whether a -// given memory map entry implies the need of -// allocating and registering memory -//------------------------------------------------- - -bool address_space::needs_backing_store(const address_map_entry &entry) -{ - // if we are sharing, and we don't have a pointer yet, create one - if (entry.m_share != nullptr) - { - std::string fulltag = entry.m_devbase.subtag(entry.m_share); - auto share = m_manager.shares().find(fulltag); - if (share != m_manager.shares().end() && share->second->ptr() == nullptr) - return true; - } - - // if we're writing to any sort of bank or RAM, then yes, we do need backing - if (entry.m_write.m_type == AMH_BANK || entry.m_write.m_type == AMH_RAM) - return true; - - // if we're reading from RAM or from ROM outside of address space 0 or its region, then yes, we do need backing - memory_region *region = m_manager.machine().root_device().memregion(m_device.tag()); - if (entry.m_read.m_type == AMH_RAM || - (entry.m_read.m_type == AMH_ROM && (m_spacenum != 0 || region == nullptr || entry.m_addrstart >= region->bytes()))) - return true; - - // all other cases don't need backing - return false; -} - int address_space::add_change_notifier(std::function<void (read_or_write)> n) { int id = m_notifier_id++; @@ -2327,92 +2072,6 @@ void address_space::remove_change_notifier(int id) //************************************************************************** -// BANKING HELPERS -//************************************************************************** - -//------------------------------------------------- -// bank_find_or_allocate - allocate a new -// bank, or find an existing one, and return the -// read/write handler -//------------------------------------------------- - -memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite) -{ - // adjust the addresses, handling mirrors and such - offs_t addrmask = ~addrmirror; - adjust_addresses(addrstart, addrend, addrmask, addrmirror); - - // look up the bank by name, or else by byte range - memory_bank *membank = tag ? m_manager.find(tag) : m_manager.find(*this, addrstart, addrend); - - // if we don't have a bank yet, create a new one - if (!membank) - membank = m_manager.allocate(*this, addrstart, addrend, tag); - - // add a reference for this space - membank->add_reference(*this, readorwrite); - return *membank; -} - - -//************************************************************************** -// MEMORY BLOCK -//************************************************************************** - -//------------------------------------------------- -// memory_block - constructor -//------------------------------------------------- - -memory_block::memory_block(address_space &space, offs_t addrstart, offs_t addrend, void *memory) - : m_machine(space.m_manager.machine()), - m_space(space), - m_addrstart(addrstart), - m_addrend(addrend), - m_data(reinterpret_cast<u8 *>(memory)) -{ - offs_t const length = space.address_to_byte(addrend + 1 - addrstart); - VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), addrstart, addrend, memory)); - - // allocate a block if needed - if (m_data == nullptr) - { - if (length < 4096) - { - m_allocated.resize(length); - memset(&m_allocated[0], 0, length); - m_data = &m_allocated[0]; - } - else - { - m_allocated.resize(length + 0xfff); - memset(&m_allocated[0], 0, length + 0xfff); - m_data = reinterpret_cast<u8 *>((reinterpret_cast<uintptr_t>(&m_allocated[0]) + 0xfff) & ~0xfff); - } - } - - // register for saving, but only if we're not part of a memory region - if (space.m_manager.region_containing(m_data, length) != nullptr) - VPRINTF(("skipping save of this memory block as it is covered by a memory region\n")); - else - { - int bytes_per_element = space.data_width() / 8; - std::string name = string_format("%08x-%08x", addrstart, addrend); - machine().save().save_memory(&space.device(), "memory", space.device().tag(), space.spacenum(), name.c_str(), m_data, bytes_per_element, (u32)length / bytes_per_element); - } -} - - -//------------------------------------------------- -// memory_block - destructor -//------------------------------------------------- - -memory_block::~memory_block() -{ -} - - - -//************************************************************************** // MEMORY BANK //************************************************************************** @@ -2420,27 +2079,13 @@ memory_block::~memory_block() // memory_bank - constructor //------------------------------------------------- -memory_bank::memory_bank(address_space &space, int index, offs_t addrstart, offs_t addrend, const char *tag) - : m_machine(space.m_manager.machine()), - m_anonymous(tag == nullptr), - m_addrstart(addrstart), - m_addrend(addrend), +memory_bank::memory_bank(device_t &device, std::string tag) + : m_machine(device.machine()), m_curentry(0) { - // generate an internal tag if we don't have one - if (tag == nullptr) - { - m_tag = string_format("~%d~", index); - m_name = string_format("Internal bank #%d", index); - } - else - { - m_tag = tag; - m_name = string_format("Bank '%s'", tag); - } - - if (!m_anonymous && machine().save().registration_allowed()) - machine().save().save_item(&space.device(), "memory", m_tag.c_str(), 0, NAME(m_curentry)); + m_tag = std::move(tag); + m_name = string_format("Bank '%s'", m_tag); + machine().save().save_item(&device, "memory", m_tag.c_str(), 0, NAME(m_curentry)); } @@ -2454,35 +2099,6 @@ memory_bank::~memory_bank() //------------------------------------------------- -// references_space - walk the list of references -// to find a match against the provided space -// and read/write -//------------------------------------------------- - -bool memory_bank::references_space(const address_space &space, read_or_write readorwrite) const -{ - for (auto &ref : m_reflist) - if (ref->matches(space, readorwrite)) - return true; - return false; -} - - -//------------------------------------------------- -// add_reference - add a new reference to the -// given space -//------------------------------------------------- - -void memory_bank::add_reference(address_space &space, read_or_write readorwrite) -{ - // if we already have a reference, skip it - if (references_space(space, readorwrite)) - return; - m_reflist.push_back(std::make_unique<bank_reference>(space, readorwrite)); -} - - -//------------------------------------------------- // set_base - set the bank base explicitly //------------------------------------------------- @@ -2498,21 +2114,10 @@ void memory_bank::set_base(void *base) m_curentry = 0; } m_entries[m_curentry] = reinterpret_cast<u8 *>(base); - for(const auto &cb : m_alloc_notifier) - cb(base); - m_alloc_notifier.clear(); } //------------------------------------------------- -// add_notifier - add a function used to notify when the allocation is done -//------------------------------------------------- -void memory_bank::add_notifier(std::function<void (void *)> cb) -{ - m_alloc_notifier.emplace_back(std::move(cb)); -} - -//------------------------------------------------- // set_entry - set the base to a pre-configured // entry //------------------------------------------------- @@ -2520,8 +2125,6 @@ void memory_bank::add_notifier(std::function<void (void *)> cb) void memory_bank::set_entry(int entrynum) { // validate - if (m_anonymous) - throw emu_fatalerror("memory_bank::set_entry called for anonymous bank"); if (entrynum < 0 || entrynum >= int(m_entries.size())) throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum); if (m_entries[entrynum] == nullptr) @@ -2573,9 +2176,9 @@ void memory_bank::configure_entries(int startentry, int numentries, void *base, // memory_region - constructor //------------------------------------------------- -memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian) +memory_region::memory_region(running_machine &machine, std::string name, u32 length, u8 width, endianness_t endian) : m_machine(machine), - m_name(name), + m_name(std::move(name)), m_buffer(length), m_endianness(endian), m_bitwidth(width * 8), @@ -2583,3 +2186,17 @@ memory_region::memory_region(running_machine &machine, const char *name, u32 len { assert(width == 1 || width == 2 || width == 4 || width == 8); } + +std::string memory_share::compare(u8 width, size_t bytes, endianness_t endianness) const +{ + if (width != m_bitwidth) + return util::string_format("share %s found with unexpected width (expected %d, found %d)", m_name, width, m_bitwidth); + if (bytes != m_bytes) + return util::string_format("share %s found with unexpected size (expected %x, found %x)", m_name, bytes, m_bytes); + if (endianness != m_endianness && m_bitwidth != 8) + return util::string_format("share %s found with unexpected endianness (expected %s, found %s)", m_name, + endianness == ENDIANNESS_LITTLE ? "little" : "big", + m_endianness == ENDIANNESS_LITTLE ? "little" : "big"); + return ""; +} + diff --git a/src/emu/emumem.h b/src/emu/emumem.h index 1adfb0332eb..ed8897a2992 100644 --- a/src/emu/emumem.h +++ b/src/emu/emumem.h @@ -1372,29 +1372,23 @@ public: void install_read_port(offs_t addrstart, offs_t addrend, const char *rtag) { install_read_port(addrstart, addrend, 0, rtag); } void install_write_port(offs_t addrstart, offs_t addrend, const char *wtag) { install_write_port(addrstart, addrend, 0, wtag); } void install_readwrite_port(offs_t addrstart, offs_t addrend, const char *rtag, const char *wtag) { install_readwrite_port(addrstart, addrend, 0, rtag, wtag); } - void install_read_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_read_bank(addrstart, addrend, 0, tag); } - void install_write_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_write_bank(addrstart, addrend, 0, tag); } - void install_readwrite_bank(offs_t addrstart, offs_t addrend, const char *tag) { install_readwrite_bank(addrstart, addrend, 0, tag); } void install_read_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_read_bank(addrstart, addrend, 0, bank); } void install_write_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_write_bank(addrstart, addrend, 0, bank); } void install_readwrite_bank(offs_t addrstart, offs_t addrend, memory_bank *bank) { install_readwrite_bank(addrstart, addrend, 0, bank); } - void install_rom(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_rom(addrstart, addrend, 0, baseptr); } - void install_writeonly(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_writeonly(addrstart, addrend, 0, baseptr); } - void install_ram(offs_t addrstart, offs_t addrend, void *baseptr = nullptr) { install_ram(addrstart, addrend, 0, baseptr); } + void install_rom(offs_t addrstart, offs_t addrend, void *baseptr) { install_rom(addrstart, addrend, 0, baseptr); } + void install_writeonly(offs_t addrstart, offs_t addrend, void *baseptr) { install_writeonly(addrstart, addrend, 0, baseptr); } + void install_ram(offs_t addrstart, offs_t addrend, void *baseptr) { install_ram(addrstart, addrend, 0, baseptr); } // install ports, banks, RAM (with mirror/mask) void install_read_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *rtag) { install_readwrite_port(addrstart, addrend, addrmirror, rtag, ""); } void install_write_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *wtag) { install_readwrite_port(addrstart, addrend, addrmirror, "", wtag); } virtual void install_readwrite_port(offs_t addrstart, offs_t addrend, offs_t addrmirror, std::string rtag, std::string wtag) = 0; - void install_read_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, ""); } - void install_write_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, "", tag); } - void install_readwrite_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, const char *tag) { install_bank_generic(addrstart, addrend, addrmirror, tag, tag); } void install_read_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, bank, nullptr); } void install_write_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, nullptr, bank); } void install_readwrite_bank(offs_t addrstart, offs_t addrend, offs_t addrmirror, memory_bank *bank) { install_bank_generic(addrstart, addrend, addrmirror, bank, bank); } - void install_rom(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READ, baseptr); } - void install_writeonly(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, baseptr); } - void install_ram(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr = nullptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, baseptr); } + void install_rom(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READ, baseptr); } + void install_writeonly(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::WRITE, baseptr); } + void install_ram(offs_t addrstart, offs_t addrend, offs_t addrmirror, void *baseptr) { install_ram_generic(addrstart, addrend, addrmirror, read_or_write::READWRITE, baseptr); } // install device memory maps template <typename T> void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(address_map &map), u64 unitmask = 0, int cswidth = 0) { @@ -1594,8 +1588,6 @@ public: // setup void prepare_map(); void populate_from_map(address_map *map = nullptr); - void allocate_memory(); - void locate_memory(); template<int Width, int AddrShift, endianness_t Endian> handler_entry_read_unmapped <Width, AddrShift, Endian> *get_unmap_r() const { return static_cast<handler_entry_read_unmapped <Width, AddrShift, Endian> *>(m_unmap_r); } template<int Width, int AddrShift, endianness_t Endian> handler_entry_write_unmapped<Width, AddrShift, Endian> *get_unmap_w() const { return static_cast<handler_entry_write_unmapped<Width, AddrShift, Endian> *>(m_unmap_w); } @@ -1608,13 +1600,8 @@ protected: 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, std::string rtag, std::string wtag) = 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 *find_backing_memory(offs_t addrstart, offs_t addrend); - bool needs_backing_store(const address_map_entry &entry); - memory_bank &bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite); - address_map_entry *block_assign_intersecting(offs_t bytestart, offs_t byteend, u8 *base); 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); @@ -1647,93 +1634,22 @@ protected: }; -// ======================> memory_block - -// a memory block is a chunk of RAM associated with a range of memory in a device's address space -class memory_block -{ - DISABLE_COPYING(memory_block); - -public: - // construction/destruction - memory_block(address_space &space, offs_t start, offs_t end, void *memory = nullptr); - ~memory_block(); - - // getters - running_machine &machine() const { return m_machine; } - offs_t addrstart() const { return m_addrstart; } - offs_t addrend() const { return m_addrend; } - u8 *data() const { return m_data; } - - // is the given range contained by this memory block? - bool contains(address_space &space, offs_t addrstart, offs_t addrend) const - { - return (&space == &m_space && m_addrstart <= addrstart && m_addrend >= addrend); - } - -private: - // internal state - running_machine & m_machine; // need the machine to free our memory - address_space & m_space; // which address space are we associated with? - offs_t m_addrstart, m_addrend; // start/end for verifying a match - u8 * m_data; // pointer to the data for this block - std::vector<u8> m_allocated; // pointer to the actually allocated block -}; - - // ======================> memory_bank // a memory bank is a global pointer to memory that can be shared across devices and changed dynamically class memory_bank { - // a bank reference is an entry in a list of address spaces that reference a given bank - class bank_reference - { - public: - // construction/destruction - bank_reference(address_space &space, read_or_write readorwrite) - : m_space(space), - m_readorwrite(readorwrite) { } - - // getters - address_space &space() const { return m_space; } - - // does this reference match the space+read/write combination? - bool matches(const address_space &space, read_or_write readorwrite) const - { - return (&space == &m_space && (readorwrite == read_or_write::READWRITE || readorwrite == m_readorwrite)); - } - - private: - // internal state - address_space & m_space; // address space that references us - read_or_write m_readorwrite; // used for read or write? - - }; - public: // construction/destruction - memory_bank(address_space &space, int index, offs_t start, offs_t end, const char *tag = nullptr); + memory_bank(device_t &device, std::string tag); ~memory_bank(); // getters running_machine &machine() const { return m_machine; } int entry() const { return m_curentry; } - bool anonymous() const { return m_anonymous; } - offs_t addrstart() const { return m_addrstart; } void *base() const { return m_entries.empty() ? nullptr : m_entries[m_curentry]; } - const char *tag() const { return m_tag.c_str(); } - const char *name() const { return m_name.c_str(); } - - // compare a range against our range - bool matches_exactly(offs_t addrstart, offs_t addrend) const { return (m_addrstart == addrstart && m_addrend == addrend); } - bool fully_covers(offs_t addrstart, offs_t addrend) const { return (m_addrstart <= addrstart && m_addrend >= addrend); } - bool is_covered_by(offs_t addrstart, offs_t addrend) const { return (m_addrstart >= addrstart && m_addrend <= addrend); } - bool straddles(offs_t addrstart, offs_t addrend) const { return (m_addrstart < addrend && m_addrend > addrstart); } - - // track and verify address space references to this bank - bool references_space(const address_space &space, read_or_write readorwrite) const; - void add_reference(address_space &space, read_or_write readorwrite); + const std::string &tag() const { return m_tag; } + const std::string &name() const { return m_name; } // set the base explicitly void set_base(void *base); @@ -1742,20 +1658,14 @@ public: void configure_entry(int entrynum, void *base); void configure_entries(int startentry, int numentries, void *base, offs_t stride); void set_entry(int entrynum); - void add_notifier(std::function<void (void *)> cb); private: // internal state running_machine & m_machine; // need the machine to free our memory std::vector<u8 *> m_entries; // the entries - bool m_anonymous; // are we anonymous or explicit? - offs_t m_addrstart; // start offset - offs_t m_addrend; // end offset int m_curentry; // current entry std::string m_name; // friendly name for this bank std::string m_tag; // tag for this bank - std::vector<std::unique_ptr<bank_reference>> m_reflist; // list of address spaces referencing this bank - std::vector<std::function<void (void *)>> m_alloc_notifier; // list of notifier targets when allocating }; @@ -1766,26 +1676,28 @@ class memory_share { public: // construction/destruction - memory_share(u8 width, size_t bytes, endianness_t endianness, void *ptr = nullptr) - : m_ptr(ptr), - m_bytes(bytes), - m_endianness(endianness), - m_bitwidth(width), - m_bytewidth(width <= 8 ? 1 : width <= 16 ? 2 : width <= 32 ? 4 : 8) + memory_share(std::string name, u8 width, size_t bytes, endianness_t endianness, void *ptr) + : m_name(name), + m_ptr(ptr), + m_bytes(bytes), + m_endianness(endianness), + m_bitwidth(width), + m_bytewidth(width <= 8 ? 1 : width <= 16 ? 2 : width <= 32 ? 4 : 8) { } // getters + const std::string &name() const { return m_name; } void *ptr() const { return m_ptr; } size_t bytes() const { return m_bytes; } endianness_t endianness() const { return m_endianness; } u8 bitwidth() const { return m_bitwidth; } u8 bytewidth() const { return m_bytewidth; } - // setters - void set_ptr(void *ptr) { m_ptr = ptr; } + std::string compare(u8 width, size_t bytes, endianness_t endianness) const; private: // internal state + std::string m_name; // share name void * m_ptr; // pointer to the memory backing the region size_t m_bytes; // size of the shared region in bytes endianness_t m_endianness; // endianness of the memory @@ -1801,18 +1713,16 @@ private: class memory_region { DISABLE_COPYING(memory_region); - - friend class memory_manager; public: // construction/destruction - memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian); + memory_region(running_machine &machine, std::string name, u32 length, u8 width, endianness_t endian); // getters running_machine &machine() const { return m_machine; } u8 *base() { return (m_buffer.size() > 0) ? &m_buffer[0] : nullptr; } u8 *end() { return base() + m_buffer.size(); } u32 bytes() const { return m_buffer.size(); } - const char *name() const { return m_name.c_str(); } + const std::string &name() const { return m_name; } // flag expansion endianness_t endianness() const { return m_endianness; } @@ -1844,39 +1754,53 @@ class memory_manager { friend class address_space; template<int Level, int Width, int AddrShift, endianness_t Endian> friend class address_space_specific; - friend memory_region::memory_region(running_machine &machine, const char *name, u32 length, u8 width, endianness_t endian); public: // construction/destruction memory_manager(running_machine &machine); + ~memory_manager(); + + // initialize the memory spaces from the memory maps of the devices void initialize(); // getters running_machine &machine() const { return m_machine; } + + // used for the debugger interface memory views const std::unordered_map<std::string, std::unique_ptr<memory_bank>> &banks() const { return m_banklist; } const std::unordered_map<std::string, std::unique_ptr<memory_region>> ®ions() const { return m_regionlist; } const std::unordered_map<std::string, std::unique_ptr<memory_share>> &shares() const { return m_sharelist; } - // regions - memory_region *region_alloc(const char *name, u32 length, u8 width, endianness_t endian); - void region_free(const char *name); - memory_region *region_containing(const void *memory, offs_t bytes) const; + // anonymous memory zones + void *anonymous_alloc(address_space &space, size_t bytes, u8 width, offs_t start, offs_t end); - memory_bank *find(const char *tag) const; - memory_bank *find(address_space &space, offs_t addrstart, offs_t addrend) const; - memory_bank *allocate(address_space &space, offs_t addrstart, offs_t addrend, const char *tag = nullptr); + // shares + memory_share *share_alloc(device_t &dev, std::string name, u8 width, size_t bytes, endianness_t endianness); + memory_share *share_find(std::string name); -private: - void allocate(device_memory_interface &memory); + // banks + memory_bank *bank_alloc(device_t &device, std::string tag); + memory_bank *bank_find(std::string tag); + // regions + memory_region *region_alloc(std::string name, u32 length, u8 width, endianness_t endian); + memory_region *region_find(std::string name); + void region_free(std::string name); + +private: // internal state running_machine & m_machine; // reference to the machine - bool m_initialized; // have we completed initialization? - - std::vector<std::unique_ptr<memory_block>> m_blocklist; // head of the list of memory blocks + std::vector<void *> m_datablocks; // list of memory blocks to free on exit std::unordered_map<std::string, std::unique_ptr<memory_bank>> m_banklist; // data gathered for each bank std::unordered_map<std::string, std::unique_ptr<memory_share>> m_sharelist; // map for share lookups std::unordered_map<std::string, std::unique_ptr<memory_region>> m_regionlist; // list of memory regions + + + // Allocate the address spaces + void allocate(device_memory_interface &memory); + + // Allocate some ram and register it for saving + void *allocate_memory(device_t &dev, int spacenum, std::string name, u8 width, size_t bytes); }; diff --git a/src/emu/emumem_hem.h b/src/emu/emumem_hem.h index 1d076ebc51b..f3650328854 100644 --- a/src/emu/emumem_hem.h +++ b/src/emu/emumem_hem.h @@ -11,14 +11,12 @@ public: using uX = typename emu::detail::handler_entry_size<Width>::uX; using inh = handler_entry_read_address<Width, AddrShift, Endian>; - handler_entry_read_memory(address_space *space) : handler_entry_read_address<Width, AddrShift, Endian>(space, 0) {} + handler_entry_read_memory(address_space *space, void *base) : handler_entry_read_address<Width, AddrShift, Endian>(space, 0), m_base(reinterpret_cast<uX *>(base)) {} ~handler_entry_read_memory() = default; uX read(offs_t offset, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; - inline void set_base(uX *base) { m_base = base; } - std::string name() const override; private: @@ -31,14 +29,12 @@ public: using uX = typename emu::detail::handler_entry_size<Width>::uX; using inh = handler_entry_write_address<Width, AddrShift, Endian>; - handler_entry_write_memory(address_space *space) : handler_entry_write_address<Width, AddrShift, Endian>(space, 0) {} + handler_entry_write_memory(address_space *space, void *base) : handler_entry_write_address<Width, AddrShift, Endian>(space, 0), m_base(reinterpret_cast<uX *>(base)) {} ~handler_entry_write_memory() = default; void write(offs_t offset, uX data, uX mem_mask) const override; void *get_ptr(offs_t offset) const override; - inline void set_base(uX *base) { m_base = base; } - std::string name() const override; private: diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp index a728a6a7660..b3b90ebbcf7 100644 --- a/src/emu/romload.cpp +++ b/src/emu/romload.cpp @@ -1278,8 +1278,8 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list machine().memory().region_free(memregion->name()); } - // remember the base and length - m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness); + /* remember the base and length */ + m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness); LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base()); if (ROMREGION_ISERASE(region)) // clear the region if it's requested |