summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/emumem.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/emumem.h')
-rw-r--r--src/emu/emumem.h222
1 files changed, 153 insertions, 69 deletions
diff --git a/src/emu/emumem.h b/src/emu/emumem.h
index 995a09a1606..4554bea5ed6 100644
--- a/src/emu/emumem.h
+++ b/src/emu/emumem.h
@@ -438,6 +438,16 @@ template<> struct handler_entry_size<3> { using uX = u64; };
// =====================-> Address segmentation for the search tree
+constexpr int handler_entry_dispatch_level(int highbits)
+{
+ return (highbits > 48) ? 3 : (highbits > 32) ? 2 : (highbits > 14) ? 1 : 0;
+}
+
+constexpr int handler_entry_dispatch_level_to_lowbits(int level, int width, int ashift)
+{
+ return level == 3 ? 48 : level == 2 ? 32 : level == 1 ? 14 : width + ashift;
+}
+
constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift)
{
return (highbits > 48) ? 48 :
@@ -451,7 +461,7 @@ constexpr int handler_entry_dispatch_lowbits(int highbits, int width, int ashift
// ======================> memory_units_descritor forwards declaration
-template<int Width, int AddrShift, int Endian> class memory_units_descriptor;
+template<int Width, int AddrShift, endianness_t Endian> class memory_units_descriptor;
@@ -463,7 +473,7 @@ class handler_entry
{
DISABLE_COPYING(handler_entry);
- template<int Width, int AddrShift, endianness_t Endian> friend class address_space_specific;
+ template<int Level, int Width, int AddrShift, endianness_t Endian> friend class address_space_specific;
public:
// Typing flags
@@ -535,9 +545,9 @@ protected:
// Provides the populate/read/get_ptr/lookup API
-template<int Width, int AddrShift, int Endian> class handler_entry_read_passthrough;
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read_passthrough;
-template<int Width, int AddrShift, int Endian> class handler_entry_read : public handler_entry
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read : public handler_entry
{
public:
using uX = typename emu::detail::handler_entry_size<Width>::uX;
@@ -553,7 +563,7 @@ public:
handler_entry_read(address_space *space, u32 flags) : handler_entry(space, flags) {}
~handler_entry_read() {}
- virtual uX read(offs_t offset, uX mem_mask) = 0;
+ virtual uX read(offs_t offset, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_read<Width, AddrShift, Endian> *&handler) const;
@@ -599,16 +609,16 @@ public:
virtual void detach(const std::unordered_set<handler_entry *> &handlers);
// Return the internal structures of the root dispatch
- virtual void get_dispatch(handler_entry_read<Width, AddrShift, Endian> *const *&dispatch, u8 &shift) const;
+ virtual const handler_entry_read<Width, AddrShift, Endian> *const *get_dispatch() const;
};
// =====================-> The parent class of all write handlers
// Provides the populate/write/get_ptr/lookup API
-template<int Width, int AddrShift, int Endian> class handler_entry_write_passthrough;
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write_passthrough;
-template<int Width, int AddrShift, int Endian> class handler_entry_write : public handler_entry
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write : public handler_entry
{
public:
using uX = typename emu::detail::handler_entry_size<Width>::uX;
@@ -624,7 +634,7 @@ public:
handler_entry_write(address_space *space, u32 flags) : handler_entry(space, flags) {}
virtual ~handler_entry_write() {}
- virtual void write(offs_t offset, uX data, uX mem_mask) = 0;
+ virtual void write(offs_t offset, uX data, uX mem_mask) const = 0;
virtual void *get_ptr(offs_t offset) const;
virtual void lookup(offs_t address, offs_t &start, offs_t &end, handler_entry_write<Width, AddrShift, Endian> *&handler) const;
@@ -671,14 +681,14 @@ public:
virtual void detach(const std::unordered_set<handler_entry *> &handlers);
// Return the internal structures of the root dispatch
- virtual void get_dispatch(handler_entry_write<Width, AddrShift, Endian> *const *&dispatch, u8 &shift) const;
+ virtual const handler_entry_write<Width, AddrShift, Endian> *const *get_dispatch() const;
};
// =====================-> Passthrough handler management structure
class memory_passthrough_handler
{
- template<int Width, int AddrShift, int Endian> friend class handler_entry_read_passthrough;
- template<int Width, int AddrShift, int Endian> friend class handler_entry_write_passthrough;
+ template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_passthrough;
+ template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_passthrough;
public:
memory_passthrough_handler(address_space &space) : m_space(space) {}
@@ -695,8 +705,8 @@ private:
// =====================-> Forward declaration for address_space
-template<int Width, int AddrShift, int Endian> class handler_entry_read_unmapped;
-template<int Width, int AddrShift, int Endian> class handler_entry_write_unmapped;
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_read_unmapped;
+template<int Width, int AddrShift, endianness_t Endian> class handler_entry_write_unmapped;
// ======================> address offset -> byte offset
@@ -705,7 +715,7 @@ constexpr offs_t memory_offset_to_byte(offs_t offset, int AddrShift) { return Ad
// ======================> generic read/write decomposition routines
// generic direct read
-template<int Width, int AddrShift, int Endian, int TargetWidth, bool Aligned, typename T> typename emu::detail::handler_entry_size<TargetWidth>::uX memory_read_generic(T rop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> typename emu::detail::handler_entry_size<TargetWidth>::uX memory_read_generic(T rop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
{
using TargetType = typename emu::detail::handler_entry_size<TargetWidth>::uX;
using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
@@ -839,7 +849,7 @@ template<int Width, int AddrShift, int Endian, int TargetWidth, bool Aligned, ty
}
// generic direct write
-template<int Width, int AddrShift, int Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian, int TargetWidth, bool Aligned, typename T> void memory_write_generic(T wop, offs_t address, typename emu::detail::handler_entry_size<TargetWidth>::uX data, typename emu::detail::handler_entry_size<TargetWidth>::uX mask)
{
using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
@@ -964,15 +974,17 @@ template<int Width, int AddrShift, int Endian, int TargetWidth, bool Aligned, ty
// ======================> Direct dispatching
-template<int Width, int AddrShift, int Endian> typename emu::detail::handler_entry_size<Width>::uX dispatch_read(offs_t mask, u8 shift, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, handler_entry_read<Width, AddrShift, Endian> *const *dispatch)
+template<int Level, int Width, int AddrShift, endianness_t Endian> typename emu::detail::handler_entry_size<Width>::uX dispatch_read(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_read<Width, AddrShift, Endian> *const *dispatch)
{
- return dispatch[(offset >> shift) & mask]->read(offset, mem_mask);
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->read(offset, mem_mask);
}
-template<int Width, int AddrShift, int Endian> void dispatch_write(offs_t mask, u8 shift, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, handler_entry_write<Width, AddrShift, Endian> *const *dispatch)
+template<int Level, int Width, int AddrShift, endianness_t Endian> void dispatch_write(offs_t mask, offs_t offset, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mem_mask, const handler_entry_write<Width, AddrShift, Endian> *const *dispatch)
{
- return dispatch[(offset >> shift) & mask]->write(offset, data, mem_mask);
+ static constexpr u32 LowBits = emu::detail::handler_entry_dispatch_level_to_lowbits(Level, Width, AddrShift);
+ return dispatch[(offset & mask) >> LowBits]->write(offset, data, mem_mask);
}
@@ -980,21 +992,29 @@ template<int Width, int AddrShift, int Endian> void dispatch_write(offs_t mask,
// memory_access_specific does uncached but faster accesses by shortcutting the address_space virtual call
-template<int Width, int AddrShift, int Endian> class memory_access_specific
+namespace emu { namespace detail {
+
+template<int Level, int Width, int AddrShift, endianness_t Endian> class memory_access_specific
{
+ friend class ::address_space;
+
using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
static constexpr u32 NATIVE_BYTES = 1 << Width;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
public:
// construction/destruction
- memory_access_specific(address_space &space,
- handler_entry_read <Width, AddrShift, Endian> *const *dispatch_read, u8 shift_read,
- handler_entry_write<Width, AddrShift, Endian> *const *dispatch_write, u8 shift_write);
-
+ memory_access_specific()
+ : m_space(nullptr),
+ m_addrmask(0),
+ m_dispatch_read(nullptr),
+ m_dispatch_write(nullptr)
+ {
+ }
- // getters
- address_space &space() const { return m_space; }
+ inline address_space &space() const {
+ return *m_space;
+ }
u8 read_byte(offs_t address) { return Width == 0 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 0, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xff); }
u16 read_word(offs_t address) { return Width == 1 ? read_native(address & ~NATIVE_MASK) : memory_read_generic<Width, AddrShift, Endian, 1, true>([this](offs_t offset, NativeType mask) -> NativeType { return read_native(offset, mask); }, address, 0xffff); }
@@ -1025,22 +1045,22 @@ public:
void write_qword_unaligned(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); }
private:
- address_space & m_space;
+ address_space * m_space;
offs_t m_addrmask; // address mask
- handler_entry_read<Width, AddrShift, Endian> *const *m_dispatch_read;
- handler_entry_write<Width, AddrShift, Endian> *const *m_dispatch_write;
- u8 m_shift_read;
- u8 m_shift_write;
+ const handler_entry_read<Width, AddrShift, Endian> *const *m_dispatch_read;
+ const handler_entry_write<Width, AddrShift, Endian> *const *m_dispatch_write;
NativeType read_native(offs_t address, NativeType mask = ~NativeType(0)) {
- return dispatch_read<Width, AddrShift, Endian>(offs_t(-1), m_shift_read, address & m_addrmask, mask, m_dispatch_read);
+ return dispatch_read<Level, Width, AddrShift, Endian>(m_addrmask, address, mask, m_dispatch_read);;
}
void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0)) {
- dispatch_write<Width, AddrShift, Endian>(offs_t(-1), m_shift_write, address & m_addrmask, data, mask, m_dispatch_write);
+ dispatch_write<Level, Width, AddrShift, Endian>(m_addrmask, address, data, mask, m_dispatch_write);;
}
+
+ void set(address_space *space, std::pair<const void *, const void *> rw);
};
@@ -1048,23 +1068,32 @@ private:
// ======================> memory_access_cache
// memory_access_cache contains state data for cached access
-template<int Width, int AddrShift, int Endian> class memory_access_cache
+template<int Width, int AddrShift, endianness_t Endian> class memory_access_cache
{
+ friend class ::address_space;
+
using NativeType = typename emu::detail::handler_entry_size<Width>::uX;
static constexpr u32 NATIVE_BYTES = 1 << Width;
static constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? (1 << (Width + AddrShift)) - 1 : 0;
public:
// construction/destruction
- memory_access_cache(address_space &space,
- handler_entry_read <Width, AddrShift, Endian> *root_read,
- handler_entry_write<Width, AddrShift, Endian> *root_write);
+ memory_access_cache()
+ : m_space(nullptr),
+ m_addrmask(0),
+ m_addrstart_r(1),
+ m_addrend_r(0),
+ m_addrstart_w(1),
+ m_addrend_w(0),
+ m_cache_r(nullptr),
+ m_cache_w(nullptr),
+ m_root_read(nullptr),
+ m_root_write(nullptr)
+ {
+ }
~memory_access_cache();
- // getters
- address_space &space() const { return m_space; }
-
// see if an address is within bounds, update it if not
void check_address_r(offs_t address) {
if(address >= m_addrstart_r && address <= m_addrend_r)
@@ -1080,6 +1109,10 @@ public:
// accessor methods
+ inline address_space &space() const {
+ return *m_space;
+ }
+
void *read_ptr(offs_t address) {
address &= m_addrmask;
check_address_r(address);
@@ -1115,7 +1148,7 @@ public:
void write_qword_unaligned(offs_t address, u64 data, u64 mask) { memory_write_generic<Width, AddrShift, Endian, 3, false>([this](offs_t offset, NativeType data, NativeType mask) { write_native(offset, data, mask); }, address, data, mask); }
private:
- address_space & m_space;
+ address_space * m_space;
int m_notifier_id; // id to remove the notifier on destruction
@@ -1124,7 +1157,7 @@ private:
offs_t m_addrend_r; // maximum valid address for reading
offs_t m_addrstart_w; // minimum valid address for writing
offs_t m_addrend_w; // maximum valid address for writing
- handler_entry_read<Width, AddrShift, Endian> *m_cache_r; // read cache
+ handler_entry_read <Width, AddrShift, Endian> *m_cache_r; // read cache
handler_entry_write<Width, AddrShift, Endian> *m_cache_w; // write cache
handler_entry_read <Width, AddrShift, Endian> *m_root_read; // decode tree roots
@@ -1132,9 +1165,23 @@ private:
NativeType read_native(offs_t address, NativeType mask = ~NativeType(0));
void write_native(offs_t address, NativeType data, NativeType mask = ~NativeType(0));
+
+ void set(address_space *space, std::pair<void *, void *> rw);
+};
+}}
+
+
+// ======================> memory_access cache/specific type dispatcher
+
+template<int HighBits, int Width, int AddrShift, endianness_t Endian> struct memory_access {
+ static constexpr int Level = emu::detail::handler_entry_dispatch_level(HighBits);
+
+ using cache = emu::detail::memory_access_cache<Width, AddrShift, Endian>;
+ using specific = emu::detail::memory_access_specific<Level, Width, AddrShift, Endian>;
};
+
// ======================> address_space_config
// describes an address space and provides basic functions to map addresses to bytes
@@ -1190,9 +1237,8 @@ class address_space
{
friend class memory_bank;
friend class memory_block;
- template<int Width, int AddrShift, int Endian> friend class handler_entry_read_unmapped;
- template<int Width, int AddrShift, int Endian> friend class handler_entry_write_unmapped;
- template<int Width, int AddrShift, int Endian> friend class memory_access_cache;
+ template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_read_unmapped;
+ template<int Width, int AddrShift, endianness_t Endian> friend class handler_entry_write_unmapped;
struct notifier_t {
std::function<void (read_or_write)> m_notifier;
@@ -1212,7 +1258,7 @@ public:
int spacenum() const { return m_spacenum; }
address_map *map() const { return m_map.get(); }
- template<int Width, int AddrShift, int Endian> memory_access_cache<Width, AddrShift, Endian> *cache() {
+ template<int Width, int AddrShift, endianness_t Endian> void cache(emu::detail::memory_access_cache<Width, AddrShift, Endian> &v) {
if(AddrShift != m_config.addr_shift())
fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
if(8 << Width != m_config.data_width())
@@ -1221,19 +1267,21 @@ public:
fatalerror("Requesting cache() with endianness %s while the config says %s\n",
endianness_names[Endian], endianness_names[m_config.endianness()]);
- return static_cast<memory_access_cache<Width, AddrShift, Endian> *>(create_cache());
+ v.set(this, get_cache_info());
}
- template<int Width, int AddrShift, int Endian> memory_access_specific<Width, AddrShift, Endian> *specific() {
+ template<int Level, int Width, int AddrShift, endianness_t Endian> void specific(emu::detail::memory_access_specific<Level, Width, AddrShift, Endian> &v) {
+ if(Level != emu::detail::handler_entry_dispatch_level(m_config.addr_width()))
+ fatalerror("Requesting specific() with wrong level, bad address witdh (the config says %d\n", m_config.addr_width());
if(AddrShift != m_config.addr_shift())
- fatalerror("Requesting cache() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
+ fatalerror("Requesting specific() with address shift %d while the config says %d\n", AddrShift, m_config.addr_shift());
if(8 << Width != m_config.data_width())
- fatalerror("Requesting cache() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
+ fatalerror("Requesting specific() with data width %d while the config says %d\n", 8 << Width, m_config.data_width());
if(Endian != m_config.endianness())
- fatalerror("Requesting cache() with endianness %s while the config says %s\n",
+ fatalerror("Requesting spefific() with endianness %s while the config says %s\n",
endianness_names[Endian], endianness_names[m_config.endianness()]);
- return static_cast<memory_access_specific<Width, AddrShift, Endian> *>(create_specific());
+ v.set(this, get_specific_info());
}
int add_change_notifier(std::function<void (read_or_write)> n);
@@ -1551,13 +1599,13 @@ public:
void allocate_memory();
void locate_memory();
- template<int Width, int AddrShift, int 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, int 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); }
+ 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); }
protected:
// internal helpers
- virtual void *create_cache() = 0;
- virtual void *create_specific() = 0;
+ virtual std::pair<void *, void *> get_cache_info() = 0;
+ virtual std::pair<const void *, const void *> get_specific_info() = 0;
void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite);
virtual void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmirror, read_or_write readorwrite, bool quiet) = 0;
@@ -1797,7 +1845,7 @@ private:
class memory_manager
{
friend class address_space;
- template<int Width, int AddrShift, endianness_t Endian> friend class address_space_specific;
+ 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
@@ -1913,14 +1961,19 @@ private:
#define QWORD_ALIGNED(a) (((a) & 7) == 0)
-template<int Width, int AddrShift, int Endian> typename emu::detail::handler_entry_size<Width>::uX memory_access_cache<Width, AddrShift, Endian>::read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian>
+typename emu::detail::handler_entry_size<Width>::uX
+emu::detail::memory_access_cache<Width, AddrShift, Endian>::
+read_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX mask)
{
address &= m_addrmask;
check_address_r(address);
return m_cache_r->read(address, mask);
}
-template<int Width, int AddrShift, int Endian> void memory_access_cache<Width, AddrShift, Endian>::write_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mask)
+template<int Width, int AddrShift, endianness_t Endian>
+void emu::detail::memory_access_cache<Width, AddrShift, Endian>::
+write_native(offs_t address, typename emu::detail::handler_entry_size<Width>::uX data, typename emu::detail::handler_entry_size<Width>::uX mask)
{
address &= m_addrmask;
check_address_w(address);
@@ -1932,16 +1985,47 @@ void memory_passthrough_handler::remove()
m_space.remove_passthrough(m_handlers);
}
-template<int Width, int AddrShift, int Endian> memory_access_specific<Width, AddrShift, Endian>::memory_access_specific(address_space &space,
- handler_entry_read <Width, AddrShift, Endian> *const *dispatch_read, u8 shift_read,
- handler_entry_write<Width, AddrShift, Endian> *const *dispatch_write, u8 shift_write)
- : m_space(space),
- m_addrmask(space.addrmask()),
- m_dispatch_read(dispatch_read),
- m_dispatch_write(dispatch_write),
- m_shift_read(shift_read),
- m_shift_write(shift_write)
+
+template<int Level, int Width, int AddrShift, endianness_t Endian>
+void emu::detail::memory_access_specific<Level, Width, AddrShift, Endian>::
+set(address_space *space, std::pair<const void *, const void *> rw)
+{
+ m_space = space;
+ m_addrmask = space->addrmask();
+ m_dispatch_read = (const handler_entry_read <Width, AddrShift, Endian> *const *)(rw.first);
+ m_dispatch_write = (const handler_entry_write<Width, AddrShift, Endian> *const *)(rw.second);
+}
+
+
+template<int Width, int AddrShift, endianness_t Endian>
+void emu::detail::memory_access_cache<Width, AddrShift, Endian>::
+set(address_space *space, std::pair<void *, void *> rw)
+{
+ m_space = space;
+ m_addrmask = space->addrmask();
+
+ m_notifier_id = space->add_change_notifier([this](read_or_write mode) {
+ if(u32(mode) & u32(read_or_write::READ)) {
+ m_addrend_r = 0;
+ m_addrstart_r = 1;
+ m_cache_r = nullptr;
+ }
+ if(u32(mode) & u32(read_or_write::WRITE)) {
+ m_addrend_w = 0;
+ m_addrstart_w = 1;
+ m_cache_w = nullptr;
+ }
+ });
+ m_root_read = (handler_entry_read <Width, AddrShift, Endian> *)(rw.first);
+ m_root_write = (handler_entry_write<Width, AddrShift, Endian> *)(rw.second);
+}
+
+template<int Width, int AddrShift, endianness_t Endian>
+emu::detail::memory_access_cache<Width, AddrShift, Endian>::
+~memory_access_cache()
{
+ if(m_space)
+ m_space->remove_change_notifier(m_notifier_id);
}
#endif /* MAME_EMU_EMUMEM_H */