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.h272
1 files changed, 167 insertions, 105 deletions
diff --git a/src/emu/emumem.h b/src/emu/emumem.h
index 19edc918aaa..45e1a759138 100644
--- a/src/emu/emumem.h
+++ b/src/emu/emumem.h
@@ -17,6 +17,14 @@
#ifndef MAME_EMU_EMUMEM_H
#define MAME_EMU_EMUMEM_H
+using s8 = std::int8_t;
+using u8 = std::uint8_t;
+using s16 = std::int16_t;
+using u16 = std::uint16_t;
+using s32 = std::int32_t;
+using u32 = std::uint32_t;
+using s64 = std::int64_t;
+using u64 = std::uint64_t;
//**************************************************************************
@@ -63,21 +71,21 @@ typedef named_delegate<void (address_map &)> address_map_delegate;
// struct with function pointers for accessors; use is generally discouraged unless necessary
struct data_accessors
{
- u8 (*read_byte)(address_space &space, offs_t byteaddress);
- u16 (*read_word)(address_space &space, offs_t byteaddress);
- u16 (*read_word_masked)(address_space &space, offs_t byteaddress, u16 mask);
- u32 (*read_dword)(address_space &space, offs_t byteaddress);
- u32 (*read_dword_masked)(address_space &space, offs_t byteaddress, u32 mask);
- u64 (*read_qword)(address_space &space, offs_t byteaddress);
- u64 (*read_qword_masked)(address_space &space, offs_t byteaddress, u64 mask);
-
- void (*write_byte)(address_space &space, offs_t byteaddress, u8 data);
- void (*write_word)(address_space &space, offs_t byteaddress, u16 data);
- void (*write_word_masked)(address_space &space, offs_t byteaddress, u16 data, u16 mask);
- void (*write_dword)(address_space &space, offs_t byteaddress, u32 data);
- void (*write_dword_masked)(address_space &space, offs_t byteaddress, u32 data, u32 mask);
- void (*write_qword)(address_space &space, offs_t byteaddress, u64 data);
- void (*write_qword_masked)(address_space &space, offs_t byteaddress, u64 data, u64 mask);
+ u8 (*read_byte)(address_space &space, offs_t address);
+ u16 (*read_word)(address_space &space, offs_t address);
+ u16 (*read_word_masked)(address_space &space, offs_t address, u16 mask);
+ u32 (*read_dword)(address_space &space, offs_t address);
+ u32 (*read_dword_masked)(address_space &space, offs_t address, u32 mask);
+ u64 (*read_qword)(address_space &space, offs_t address);
+ u64 (*read_qword_masked)(address_space &space, offs_t address, u64 mask);
+
+ void (*write_byte)(address_space &space, offs_t address, u8 data);
+ void (*write_word)(address_space &space, offs_t address, u16 data);
+ void (*write_word_masked)(address_space &space, offs_t address, u16 data, u16 mask);
+ void (*write_dword)(address_space &space, offs_t address, u32 data);
+ void (*write_dword_masked)(address_space &space, offs_t address, u32 data, u32 mask);
+ void (*write_qword)(address_space &space, offs_t address, u64 data);
+ void (*write_qword_masked)(address_space &space, offs_t address, u64 data, u64 mask);
};
@@ -106,26 +114,28 @@ typedef device_delegate<void (address_space &, offs_t)> setoffset_delegate;
// ======================> direct_read_data
// direct_read_data contains state data for direct read access
-class direct_read_data
+template<int addr_shift> class direct_read_data
{
friend class address_table;
public:
+ using direct_update_delegate = delegate<offs_t (direct_read_data<addr_shift> &, offs_t)>;
+
// direct_range is an internal class that is part of a list of start/end ranges
class direct_range
{
public:
// construction
- direct_range(): m_bytestart(0),m_byteend(~0) { }
+ direct_range(): m_addrstart(0),m_addrend(~0) { }
inline bool operator==(direct_range val) noexcept
{ // return true if _Left and _Right identify the same thread
- return (m_bytestart == val.m_bytestart) && (m_byteend == val.m_byteend);
+ return (m_addrstart == val.m_addrstart) && (m_addrend == val.m_addrend);
}
// internal state
- offs_t m_bytestart; // starting byte offset of the range
- offs_t m_byteend; // ending byte offset of the range
+ offs_t m_addrstart; // starting offset of the range
+ offs_t m_addrend; // ending offset of the range
};
// construction/destruction
@@ -137,31 +147,32 @@ public:
u8 *ptr() const { return m_ptr; }
// see if an address is within bounds, or attempt to update it if not
- bool address_is_valid(offs_t byteaddress) { return EXPECTED(byteaddress >= m_bytestart && byteaddress <= m_byteend) || set_direct_region(byteaddress); }
+ bool address_is_valid(offs_t address) { return EXPECTED(address >= m_addrstart && address <= m_addrend) || set_direct_region(address); }
// force a recomputation on the next read
- void force_update() { m_byteend = 0; m_bytestart = 1; }
+ void force_update() { m_addrend = 0; m_addrstart = 1; }
void force_update(u16 if_match) { if (m_entry == if_match) force_update(); }
// accessor methods
- void *read_ptr(offs_t byteaddress, offs_t directxor = 0);
- u8 read_byte(offs_t byteaddress, offs_t directxor = 0);
- u16 read_word(offs_t byteaddress, offs_t directxor = 0);
- u32 read_dword(offs_t byteaddress, offs_t directxor = 0);
- u64 read_qword(offs_t byteaddress, offs_t directxor = 0);
+ void *read_ptr(offs_t address, offs_t directxor = 0);
+ u8 read_byte(offs_t address, offs_t directxor = 0);
+ u16 read_word(offs_t address, offs_t directxor = 0);
+ u32 read_dword(offs_t address, offs_t directxor = 0);
+ u64 read_qword(offs_t address, offs_t directxor = 0);
+
+ void remove_intersecting_ranges(offs_t start, offs_t end);
private:
// internal helpers
- bool set_direct_region(offs_t byteaddress);
- direct_range *find_range(offs_t byteaddress, u16 &entry);
- void remove_intersecting_ranges(offs_t bytestart, offs_t byteend);
+ bool set_direct_region(offs_t address);
+ direct_range *find_range(offs_t address, u16 &entry);
// internal state
address_space & m_space;
u8 * m_ptr; // direct access data pointer
- offs_t m_bytemask; // byte address mask
- offs_t m_bytestart; // minimum valid byte address
- offs_t m_byteend; // maximum valid byte address
+ offs_t m_addrmask; // address mask
+ offs_t m_addrstart; // minimum valid address
+ offs_t m_addrend; // maximum valid address
u16 m_entry; // live entry
std::list<direct_range> m_rangelist[TOTAL_MEMORY_BANKS]; // list of ranges for each entry
};
@@ -185,11 +196,17 @@ public:
endianness_t endianness() const { return m_endianness; }
int data_width() const { return m_databus_width; }
int addr_width() const { return m_addrbus_width; }
+ int addrbus_shift() const { return m_addrbus_shift; }
- // address-to-byte conversion helpers
+ // Actual alignment of the bus addresses
+ int alignment() const { int bytes = m_databus_width / 8; return m_addrbus_shift < 0 ? bytes >> -m_addrbus_shift : bytes << m_addrbus_shift; }
+
+ // Address delta to byte delta helpers
inline offs_t addr2byte(offs_t address) const { return (m_addrbus_shift < 0) ? (address << -m_addrbus_shift) : (address >> m_addrbus_shift); }
- inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); }
inline offs_t byte2addr(offs_t address) const { return (m_addrbus_shift > 0) ? (address << m_addrbus_shift) : (address >> -m_addrbus_shift); }
+
+ // address-to-byte conversion helpers
+ inline offs_t addr2byte_end(offs_t address) const { return (m_addrbus_shift < 0) ? ((address << -m_addrbus_shift) | ((1 << -m_addrbus_shift) - 1)) : (address >> m_addrbus_shift); }
inline offs_t byte2addr_end(offs_t address) const { return (m_addrbus_shift > 0) ? ((address << m_addrbus_shift) | ((1 << m_addrbus_shift) - 1)) : (address >> -m_addrbus_shift); }
// state
@@ -218,7 +235,11 @@ class address_space
friend class address_table_read;
friend class address_table_write;
friend class address_table_setoffset;
- friend class direct_read_data;
+ friend class direct_read_data<3>;
+ friend class direct_read_data<0>;
+ friend class direct_read_data<-1>;
+ friend class direct_read_data<-2>;
+ friend class direct_read_data<-3>;
protected:
// construction/destruction
@@ -235,19 +256,24 @@ public:
int spacenum() const { return m_spacenum; }
address_map *map() const { return m_map.get(); }
- direct_read_data &direct() const { return *m_direct; }
+ template<int addr_shift> direct_read_data<addr_shift> *direct() const {
+ static_assert(addr_shift == 3 || addr_shift == 0 || addr_shift == -1 || addr_shift == -2 || addr_shift == -3, "Unsupported addr_shift in direct()");
+ if(addr_shift != m_config.addrbus_shift())
+ fatalerror("Requesing direct() with address shift %d while the config says %d\n", addr_shift, m_config.addrbus_shift());
+ return static_cast<direct_read_data<addr_shift> *>(m_direct);
+ }
int data_width() const { return m_config.data_width(); }
int addr_width() const { return m_config.addr_width(); }
+ int alignment() const { return m_config.alignment(); }
endianness_t endianness() const { return m_config.endianness(); }
+ int addrbus_shift() const { return m_config.addrbus_shift(); }
u64 unmap() const { return m_unmap; }
bool is_octal() const { return m_config.m_is_octal; }
offs_t addrmask() const { return m_addrmask; }
- offs_t bytemask() const { return m_bytemask; }
u8 addrchars() const { return m_addrchars; }
offs_t logaddrmask() const { return m_logaddrmask; }
- offs_t logbytemask() const { return m_logbytemask; }
u8 logaddrchars() const { return m_logaddrchars; }
// debug helpers
@@ -262,41 +288,41 @@ public:
// general accessors
virtual void accessors(data_accessors &accessors) const = 0;
- virtual void *get_read_ptr(offs_t byteaddress) = 0;
- virtual void *get_write_ptr(offs_t byteaddress) = 0;
+ virtual void *get_read_ptr(offs_t address) = 0;
+ virtual void *get_write_ptr(offs_t address) = 0;
// read accessors
- virtual u8 read_byte(offs_t byteaddress) = 0;
- virtual u16 read_word(offs_t byteaddress) = 0;
- virtual u16 read_word(offs_t byteaddress, u16 mask) = 0;
- virtual u16 read_word_unaligned(offs_t byteaddress) = 0;
- virtual u16 read_word_unaligned(offs_t byteaddress, u16 mask) = 0;
- virtual u32 read_dword(offs_t byteaddress) = 0;
- virtual u32 read_dword(offs_t byteaddress, u32 mask) = 0;
- virtual u32 read_dword_unaligned(offs_t byteaddress) = 0;
- virtual u32 read_dword_unaligned(offs_t byteaddress, u32 mask) = 0;
- virtual u64 read_qword(offs_t byteaddress) = 0;
- virtual u64 read_qword(offs_t byteaddress, u64 mask) = 0;
- virtual u64 read_qword_unaligned(offs_t byteaddress) = 0;
- virtual u64 read_qword_unaligned(offs_t byteaddress, u64 mask) = 0;
+ virtual u8 read_byte(offs_t address) = 0;
+ virtual u16 read_word(offs_t address) = 0;
+ virtual u16 read_word(offs_t address, u16 mask) = 0;
+ virtual u16 read_word_unaligned(offs_t address) = 0;
+ virtual u16 read_word_unaligned(offs_t address, u16 mask) = 0;
+ virtual u32 read_dword(offs_t address) = 0;
+ virtual u32 read_dword(offs_t address, u32 mask) = 0;
+ virtual u32 read_dword_unaligned(offs_t address) = 0;
+ virtual u32 read_dword_unaligned(offs_t address, u32 mask) = 0;
+ virtual u64 read_qword(offs_t address) = 0;
+ virtual u64 read_qword(offs_t address, u64 mask) = 0;
+ virtual u64 read_qword_unaligned(offs_t address) = 0;
+ virtual u64 read_qword_unaligned(offs_t address, u64 mask) = 0;
// write accessors
- virtual void write_byte(offs_t byteaddress, u8 data) = 0;
- virtual void write_word(offs_t byteaddress, u16 data) = 0;
- virtual void write_word(offs_t byteaddress, u16 data, u16 mask) = 0;
- virtual void write_word_unaligned(offs_t byteaddress, u16 data) = 0;
- virtual void write_word_unaligned(offs_t byteaddress, u16 data, u16 mask) = 0;
- virtual void write_dword(offs_t byteaddress, u32 data) = 0;
- virtual void write_dword(offs_t byteaddress, u32 data, u32 mask) = 0;
- virtual void write_dword_unaligned(offs_t byteaddress, u32 data) = 0;
- virtual void write_dword_unaligned(offs_t byteaddress, u32 data, u32 mask) = 0;
- virtual void write_qword(offs_t byteaddress, u64 data) = 0;
- virtual void write_qword(offs_t byteaddress, u64 data, u64 mask) = 0;
- virtual void write_qword_unaligned(offs_t byteaddress, u64 data) = 0;
- virtual void write_qword_unaligned(offs_t byteaddress, u64 data, u64 mask) = 0;
+ virtual void write_byte(offs_t address, u8 data) = 0;
+ virtual void write_word(offs_t address, u16 data) = 0;
+ virtual void write_word(offs_t address, u16 data, u16 mask) = 0;
+ virtual void write_word_unaligned(offs_t address, u16 data) = 0;
+ virtual void write_word_unaligned(offs_t address, u16 data, u16 mask) = 0;
+ virtual void write_dword(offs_t address, u32 data) = 0;
+ virtual void write_dword(offs_t address, u32 data, u32 mask) = 0;
+ virtual void write_dword_unaligned(offs_t address, u32 data) = 0;
+ virtual void write_dword_unaligned(offs_t address, u32 data, u32 mask) = 0;
+ virtual void write_qword(offs_t address, u64 data) = 0;
+ virtual void write_qword(offs_t address, u64 data, u64 mask) = 0;
+ virtual void write_qword_unaligned(offs_t address, u64 data) = 0;
+ virtual void write_qword_unaligned(offs_t address, u64 data, u64 mask) = 0;
// Set address. This will invoke setoffset handlers for the respective entries.
- virtual void set_address(offs_t byteaddress) = 0;
+ virtual void set_address(offs_t address) = 0;
// address-to-byte conversion helpers
offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); }
@@ -386,6 +412,10 @@ public:
void allocate_memory();
void locate_memory();
+ void invalidate_read_caches();
+ void invalidate_read_caches(u16 entry);
+ void invalidate_read_caches(offs_t start, offs_t end);
+
private:
// internal helpers
virtual address_table_read &read() = 0;
@@ -412,15 +442,13 @@ protected:
// private state
const address_space_config &m_config; // configuration of this space
device_t & m_device; // reference to the owning device
- std::unique_ptr<address_map> m_map; // original memory map
+ std::unique_ptr<address_map> m_map; // original memory map
offs_t m_addrmask; // physical address mask
- offs_t m_bytemask; // byte-converted physical address mask
offs_t m_logaddrmask; // logical address mask
- offs_t m_logbytemask; // byte-converted logical address mask
u64 m_unmap; // unmapped value
int m_spacenum; // address space index
bool m_log_unmap; // log unmapped accesses in this space?
- std::unique_ptr<direct_read_data> m_direct; // fast direct-access read info
+ void * m_direct; // fast direct-access read info
const char * m_name; // friendly name of the address space
u8 m_addrchars; // number of characters to use for physical addresses
u8 m_logaddrchars; // number of characters to use for logical addresses
@@ -440,26 +468,26 @@ class memory_block
public:
// construction/destruction
- memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory = nullptr);
+ 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 bytestart() const { return m_bytestart; }
- offs_t byteend() const { return m_byteend; }
+ 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 bytestart, offs_t byteend) const
+ bool contains(address_space &space, offs_t addrstart, offs_t addrend) const
{
- return (&space == &m_space && m_bytestart <= bytestart && m_byteend >= byteend);
+ 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_bytestart, m_byteend; // byte-normalized start/end for verifying a match
+ 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
};
@@ -502,7 +530,7 @@ class memory_bank
public:
// construction/destruction
- memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag = nullptr);
+ memory_bank(address_space &space, int index, offs_t start, offs_t end, const char *tag = nullptr);
~memory_bank();
// getters
@@ -510,16 +538,16 @@ public:
int index() const { return m_index; }
int entry() const { return m_curentry; }
bool anonymous() const { return m_anonymous; }
- offs_t bytestart() const { return m_bytestart; }
+ offs_t addrstart() const { return m_addrstart; }
void *base() const { return *m_baseptr; }
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 bytestart, offs_t byteend) const { return (m_bytestart == bytestart && m_byteend == byteend); }
- bool fully_covers(offs_t bytestart, offs_t byteend) const { return (m_bytestart <= bytestart && m_byteend >= byteend); }
- bool is_covered_by(offs_t bytestart, offs_t byteend) const { return (m_bytestart >= bytestart && m_byteend <= byteend); }
- bool straddles(offs_t bytestart, offs_t byteend) const { return (m_bytestart < byteend && m_byteend > bytestart); }
+ 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;
@@ -543,8 +571,8 @@ private:
u8 ** m_baseptr; // pointer to our base pointer in the global array
u16 m_index; // array index for this handler
bool m_anonymous; // are we anonymous or explicit?
- offs_t m_bytestart; // byte-adjusted start offset
- offs_t m_byteend; // byte-adjusted end offset
+ offs_t m_addrstart; // start offset
+ offs_t m_addrend; // end offset
int m_curentry; // current entry
std::vector<bank_entry> m_entry; // array of entries (dynamically allocated)
std::string m_name; // friendly name for this bank
@@ -791,10 +819,16 @@ private:
// backing that address
//-------------------------------------------------
-inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline void *direct_read_data<addr_shift>::read_ptr(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return &m_ptr[(byteaddress ^ directxor) & m_bytemask];
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return &m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)];
+ else if(addr_shift == 0)
+ return &m_ptr[(address ^ directxor) & m_addrmask];
+ else
+ return &m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)];
+ }
return nullptr;
}
@@ -804,11 +838,17 @@ inline void *direct_read_data::read_ptr(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u8 direct_read_data<addr_shift>::read_byte(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return m_ptr[(byteaddress ^ directxor) & m_bytemask];
- return m_space.read_byte(byteaddress);
+ if(addr_shift <= -1)
+ fatalerror("Can't direct_read_data::read_byte on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift == 0)
+ return m_ptr[(address ^ directxor) & m_addrmask];
+ else
+ return m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)];
+ }
+ return m_space.read_byte(address);
}
@@ -817,11 +857,19 @@ inline u8 direct_read_data::read_byte(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u16 direct_read_data<addr_shift>::read_word(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u16 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_word(byteaddress);
+ if(addr_shift <= -2)
+ fatalerror("Can't direct_read_data::read_word on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u16 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u16 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_word(address);
}
@@ -830,11 +878,19 @@ inline u16 direct_read_data::read_word(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u32 direct_read_data<addr_shift>::read_dword(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u32 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_dword(byteaddress);
+ if(addr_shift <= -3)
+ fatalerror("Can't direct_read_data::read_dword on a memory space with address shift %d", addr_shift);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u32 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u32 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_dword(address);
}
@@ -843,11 +899,17 @@ inline u32 direct_read_data::read_dword(offs_t byteaddress, offs_t directxor)
// direct_read_data class
//-------------------------------------------------
-inline u64 direct_read_data::read_qword(offs_t byteaddress, offs_t directxor)
+template<int addr_shift> inline u64 direct_read_data<addr_shift>::read_qword(offs_t address, offs_t directxor)
{
- if (address_is_valid(byteaddress))
- return *reinterpret_cast<u64 *>(&m_ptr[(byteaddress ^ directxor) & m_bytemask]);
- return m_space.read_qword(byteaddress);
+ if (address_is_valid(address)) {
+ if(addr_shift < 0)
+ return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) << iabs(addr_shift)]);
+ else if(addr_shift == 0)
+ return *reinterpret_cast<u64 *>(&m_ptr[(address ^ directxor) & m_addrmask]);
+ else
+ return *reinterpret_cast<u64 *>(&m_ptr[((address ^ directxor) & m_addrmask) >> iabs(addr_shift)]);
+ }
+ return m_space.read_qword(address);
}
#endif /* MAME_EMU_EMUMEM_H */