summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
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
commitb8c338858a101d14308c64c87b0f714db4f05326 (patch)
treea34dca21d603b98f5450d31868ce33a7e4c103b0 /src/emu
parentf4172ded3ec6f3b877ab813f6453d6d1907c1c00 (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.cpp23
-rw-r--r--src/emu/devfind.cpp96
-rw-r--r--src/emu/devfind.h124
-rw-r--r--src/emu/diimage.cpp7
-rw-r--r--src/emu/diimage.h6
-rw-r--r--src/emu/dimemory.h2
-rw-r--r--src/emu/dirom.h2
-rw-r--r--src/emu/dirom.ipp6
-rw-r--r--src/emu/emufwd.h1
-rw-r--r--src/emu/emumem.cpp787
-rw-r--r--src/emu/emumem.h172
-rw-r--r--src/emu/emumem_hem.h8
-rw-r--r--src/emu/romload.cpp4
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 &region : 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>> &regions() 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