summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/memory.c')
-rw-r--r--src/emu/memory.c6642
1 files changed, 3327 insertions, 3315 deletions
diff --git a/src/emu/memory.c b/src/emu/memory.c
index 506c399f7f8..b1f3e6deada 100644
--- a/src/emu/memory.c
+++ b/src/emu/memory.c
@@ -4,8 +4,36 @@
Functions which handle device memory access.
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
****************************************************************************
@@ -177,2041 +205,2336 @@
#include "debug/debugcpu.h"
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
#define MEM_DUMP (0)
#define VERBOSE (0)
-#define ALLOW_ONLY_AUTO_MALLOC_BANKS 0
#define VPRINTF(x) do { if (VERBOSE) mame_printf_debug x; } while (0)
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* banking constants */
-#define MAX_BANK_ENTRIES 4096 /* maximum number of possible bank values */
-
-/* address map lookup table definitions */
-#define LEVEL1_BITS 18 /* number of address bits in the level 1 table */
-#define LEVEL2_BITS (32 - LEVEL1_BITS) /* number of address bits in the level 2 table */
-#define SUBTABLE_COUNT 64 /* number of slots reserved for subtables */
-#define SUBTABLE_BASE (256 - SUBTABLE_COUNT) /* first index of a subtable */
-#define ENTRY_COUNT (SUBTABLE_BASE) /* number of legitimate (non-subtable) entries */
-#define SUBTABLE_ALLOC 8 /* number of subtables to allocate at a time */
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
-/* shares are initially mapped to this invalid pointer */
-#define UNMAPPED_SHARE_PTR ((void *)-1)
+// banking constants
+const int BANK_ENTRY_UNSPECIFIED = -1;
-/* other address map constants */
-#define MEMORY_BLOCK_CHUNK 65536 /* minimum chunk size of allocated memory blocks */
+// shares are initially mapped to this invalid pointer
+static void *UNMAPPED_SHARE_PTR = ((void *)-1);
-/* read or write constants */
-enum _read_or_write
-{
- ROW_READ,
- ROW_WRITE
-};
-typedef enum _read_or_write read_or_write;
+// other address map constants
+const int MEMORY_BLOCK_CHUNK = 65536; // minimum chunk size of allocated memory blocks
-/* static data access handler constants */
+// static data access handler constants
enum
{
- STATIC_INVALID = 0, /* invalid - should never be used */
- STATIC_BANK1 = 1, /* first memory bank */
- STATIC_BANKMAX = 122, /* last memory bank */
- STATIC_RAM, /* RAM - reads/writes map to dynamic banks */
- STATIC_ROM, /* ROM - reads = RAM; writes = UNMAP */
- STATIC_NOP, /* NOP - reads = unmapped value; writes = no-op */
- STATIC_UNMAP, /* unmapped - same as NOP except we log errors */
- STATIC_WATCHPOINT, /* watchpoint - used internally */
- STATIC_COUNT /* total number of static handlers */
+ STATIC_INVALID = 0, // invalid - should never be used
+ STATIC_BANK1 = 1, // first memory bank
+ STATIC_BANKMAX = 122, // last memory bank
+ STATIC_RAM, // RAM - reads/writes map to dynamic banks
+ STATIC_ROM, // ROM - reads = RAM; writes = UNMAP
+ STATIC_NOP, // NOP - reads = unmapped value; writes = no-op
+ STATIC_UNMAP, // unmapped - same as NOP except we log errors
+ STATIC_WATCHPOINT, // watchpoint - used internally
+ STATIC_COUNT // total number of static handlers
};
-/***************************************************************************
- MACROS
-***************************************************************************/
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
-/* table lookup helpers */
-#define LEVEL1_INDEX(a) ((a) >> LEVEL2_BITS)
-#define LEVEL2_INDEX(e,a) ((1 << LEVEL1_BITS) + (((e) - SUBTABLE_BASE) << LEVEL2_BITS) + ((a) & ((1 << LEVEL2_BITS) - 1)))
-/* helper macros */
-#define HANDLER_IS_RAM(h) ((FPTR)(h) == STATIC_RAM)
-#define HANDLER_IS_ROM(h) ((FPTR)(h) == STATIC_ROM)
-#define HANDLER_IS_BANK(h) ((FPTR)(h) >= STATIC_BANK1 && (FPTR)(h) <= STATIC_BANKMAX)
-#define HANDLER_IS_STATIC(h) ((FPTR)(h) < STATIC_COUNT)
+// ======================> memory_block
-#define HANDLER_TO_BANK(h) ((UINT32)(FPTR)(h))
+// 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);
-#define SUBTABLE_PTR(tabledata, entry) (&(tabledata)->table[(1 << LEVEL1_BITS) + (((entry) - SUBTABLE_BASE) << LEVEL2_BITS)])
+ friend class simple_list<memory_block>;
+ friend resource_pool_object<memory_block>::~resource_pool_object();
+public:
+ // construction/destruction
+ memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory = NULL);
+ ~memory_block();
+ // getters
+ memory_block *next() const { return m_next; }
+ offs_t bytestart() const { return m_bytestart; }
+ offs_t byteend() const { return m_byteend; }
+ UINT8 *data() const { return m_data; }
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
+ // is the given range contained by this memory block?
+ bool contains(address_space &space, offs_t bytestart, offs_t byteend) const
+ {
+ return (&space == &m_space && m_bytestart <= bytestart && m_byteend >= byteend);
+ }
-/* a memory block is a chunk of RAM associated with a range of memory in a device's address space */
-typedef struct _memory_block memory_block;
-struct _memory_block
-{
- memory_block * next; /* next memory block in the list */
- const address_space * space; /* which address space are we associated with? */
- UINT8 isallocated; /* did we allocate this ourselves? */
- offs_t bytestart, byteend; /* byte-normalized start/end for verifying a match */
- UINT8 * data; /* pointer to the data for this block */
+private:
+ // internal state
+ memory_block * m_next; // next memory block in the list
+ running_machine & m_machine; // need the machine to free our memory
+ address_space & m_space; // which address space are we associated with?
+ bool m_isallocated; // did we allocate this ourselves?
+ offs_t m_bytestart, m_byteend; // byte-normalized start/end for verifying a match
+ UINT8 * m_data; // pointer to the data for this block
};
-/* a bank reference is an entry in a list of address spaces that reference a given bank */
-typedef struct _bank_reference bank_reference;
-struct _bank_reference
+
+// ======================> memory_bank
+
+// a memory bank is a global pointer to memory that can be shared across devices and changed dynamically
+class memory_bank
{
- bank_reference * next; /* link to the next reference */
- const address_space * space; /* address space that references us */
-};
+ friend class simple_list<memory_bank>;
+ friend resource_pool_object<memory_bank>::~resource_pool_object();
+
+ // a bank reference is an entry in a list of address spaces that reference a given bank
+ class bank_reference
+ {
+ friend class simple_list<bank_reference>;
+ friend resource_pool_object<bank_reference>::~resource_pool_object();
+
+ public:
+ // construction/destruction
+ bank_reference(address_space &space, read_or_write readorwrite)
+ : m_next(NULL),
+ m_space(space),
+ m_readorwrite(readorwrite) { }
+
+ // getters
+ bank_reference *next() const { return m_next; }
+ address_space &space() const { return m_space; }
+
+ // does this reference match the space+read/write combination?
+ bool matches(address_space &space, read_or_write readorwrite) const
+ {
+ return (&space == &m_space && (readorwrite == ROW_READWRITE || readorwrite == m_readorwrite));
+ }
+
+ private:
+ // internal state
+ bank_reference * m_next; // link to the next reference
+ address_space & m_space; // address space that references us
+ read_or_write m_readorwrite; // used for read or write?
+ };
+
+ // a bank_entry contains a raw and decrypted pointer
+ struct bank_entry
+ {
+ UINT8 * m_raw;
+ UINT8 * m_decrypted;
+ };
-/* a bank is a global pointer to memory that can be shared across devices and changed dynamically */
-typedef struct _bank_info bank_info;
-struct _bank_info
-{
- bank_info * next; /* next bank in sequence */
- UINT8 index; /* array index for this handler */
- UINT8 read; /* is this bank used for reads? */
- UINT8 write; /* is this bank used for writes? */
- void * handler; /* handler for this bank */
- bank_reference * reflist; /* linked list of address spaces referencing this bank */
- offs_t bytestart; /* byte-adjusted start offset */
- offs_t byteend; /* byte-adjusted end offset */
- UINT16 curentry; /* current entry */
- void * entry[MAX_BANK_ENTRIES];/* array of entries for this bank */
- void * entryd[MAX_BANK_ENTRIES];/* array of decrypted entries for this bank */
- char * name; /* friendly name for this bank */
- char tag[1]; /* tag associated with this bank */
+public:
+ // construction/destruction
+ memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag = NULL);
+ ~memory_bank();
+
+ // getters
+ memory_bank *next() const { return m_next; }
+ 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; }
+ void *base() const { return *m_baseptr; }
+ void *base_decrypted() const { return *m_basedptr; }
+ const char *tag() const { return m_tag; }
+ const char *name() const { return m_name; }
+
+ // 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 partially_covers(offs_t bytestart, offs_t byteend) const { return m_bytestart <= byteend && m_byteend >= bytestart; }
+
+ // track and verify address space references to this bank
+ bool references_space(address_space &space, read_or_write readorwrite) const;
+ void add_reference(address_space &space, read_or_write readorwrite);
+
+ // set the base explicitly
+ void set_base(void *base);
+ void set_base_decrypted(void *base);
+
+ // configure and set entries
+ void configure(int entrynum, void *base);
+ void configure_decrypted(int entrynum, void *base);
+ void set_entry(int entrynum);
+
+private:
+ // internal helpers
+ void invalidate_references();
+ void expand_entries(int entrynum);
+
+ // internal state
+ memory_bank * m_next; // next bank in sequence
+ running_machine & m_machine; // need the machine to free our memory
+ UINT8 ** m_baseptr; // pointer to our base pointer in the global array
+ UINT8 ** m_basedptr; // same for the decrypted base pointer
+ UINT8 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
+ int m_curentry; // current entry
+ bank_entry * m_entry; // array of entries (dynamically allocated)
+ int m_entry_count; // number of allocated entries
+ astring m_name; // friendly name for this bank
+ astring m_tag; // tag for this bank
+ simple_list<bank_reference> m_reflist; // linked list of address spaces referencing this bank
};
-/* In memory.h: typedef struct _direct_range direct_range; */
-struct _direct_range
+
+// ======================> handler_entry
+
+// a handler entry contains information about a memory handler
+class handler_entry : public bindable_object
{
- direct_range * next; /* pointer to the next range in the list */
- offs_t bytestart; /* starting byte offset of the range */
- offs_t byteend; /* ending byte offset of the range */
-};
+ DISABLE_COPYING(handler_entry);
+
+protected:
+ // construction/destruction
+ handler_entry(UINT8 width, endianness_t endianness, UINT8 **rambaseptr);
+ virtual ~handler_entry();
+
+public:
+ // getters
+ bool populated() const { return m_populated; }
+ offs_t bytestart() const { return m_bytestart; }
+ offs_t byteend() const { return m_byteend; }
+ offs_t bytemask() const { return m_bytemask; }
+ virtual const char *name() const = 0;
+
+ // return offset within the range referenced by this handler
+ offs_t byteoffset(offs_t byteaddress) const { return (byteaddress - m_bytestart) & m_bytemask; }
+
+ // return a pointer to the backing RAM at the given offset
+ UINT8 *ramptr(offs_t offset = 0) const { return *m_rambaseptr + offset; }
+
+ // see if we are an exact match to the given parameters
+ bool matches_exactly(offs_t bytestart, offs_t byteend, offs_t bytemask) const
+ {
+ return (m_populated && m_bytestart == bytestart && m_byteend == byteend && m_bytemask == bytemask);
+ }
+
+ // get the start/end address with the given mirror
+ void mirrored_start_end(offs_t byteaddress, offs_t &start, offs_t &end) const
+ {
+ offs_t mirrorbits = (byteaddress - m_bytestart) & ~m_bytemask;
+ start = m_bytestart | mirrorbits;
+ end = m_byteend | mirrorbits;
+ }
-/* In memory.h: typedef struct _handler_data handler_data */
-struct _handler_data
-{
- memory_handler handler; /* function pointer for handler */
- void * object; /* object associated with the handler */
- const char * name; /* name of the handler */
- memory_handler subhandler; /* function pointer for subhandler */
- void * subobject; /* object associated with the subhandler */
- UINT8 subunits; /* number of subunits to access */
- UINT8 subshift[8]; /* shift amounts for up to 8 subunits */
- offs_t bytestart; /* byte-adjusted start address for handler */
- offs_t byteend; /* byte-adjusted end address for handler */
- offs_t bytemask; /* byte-adjusted mask against the final address */
- UINT8 ** bankbaseptr; /* pointer to the bank base */
+ // configure the handler addresses, and mark as populated
+ void configure(offs_t bytestart, offs_t byteend, offs_t bytemask)
+ {
+ m_populated = true;
+ m_bytestart = bytestart;
+ m_byteend = byteend;
+ m_bytemask = bytemask;
+ }
+
+ // apply a global mask
+ void apply_mask(offs_t bytemask) { m_bytemask &= bytemask; }
+
+protected:
+ // internal helpers
+ void configure_subunits(UINT64 handlermask, int handlerbits);
+
+ // internal state
+ bool m_populated; // populated?
+ UINT8 m_datawidth;
+ endianness_t m_endianness;
+ offs_t m_bytestart; // byte-adjusted start address for handler
+ offs_t m_byteend; // byte-adjusted end address for handler
+ offs_t m_bytemask; // byte-adjusted mask against the final address
+ UINT8 ** m_rambaseptr; // pointer to the bank base
+ UINT8 m_subunits; // for width stubs, the number of subunits
+ UINT8 m_subshift[8]; // for width stubs, the shift of each subunit
};
-/* In memory.h: typedef struct _subtable_data subtable_data; */
-struct _subtable_data
+
+// ======================> handler_entry_read
+
+// a read-access-specific extension of handler_entry
+class handler_entry_read : public handler_entry
{
- UINT8 checksum_valid; /* is the checksum valid */
- UINT32 checksum; /* checksum over all the bytes */
- UINT32 usecount; /* number of times this has been used */
+public:
+ // construction/destruction
+ handler_entry_read(UINT8 width, endianness_t endianness, UINT8 **rambaseptr)
+ : handler_entry(width, endianness, rambaseptr)
+ {
+ m_legacy_object.space = NULL;
+ m_legacy_handler.space8 = NULL;
+ }
+
+ // getters
+ virtual const char *name() const;
+
+ // configure delegate callbacks
+ void set_delegate(read8_delegate delegate, UINT64 mask = 0);
+ void set_delegate(read16_delegate delegate, UINT64 mask = 0);
+ void set_delegate(read32_delegate delegate, UINT64 mask = 0);
+ void set_delegate(read64_delegate delegate, UINT64 mask = 0);
+
+ // configure legacy address space functions
+ void set_legacy_func(const address_space &space, read8_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, read16_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, read32_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, read64_space_func func, const char *name, UINT64 mask = 0);
+
+ // configure legacy device functions
+ void set_legacy_func(device_t &device, read8_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, read16_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, read32_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, read64_device_func func, const char *name, UINT64 mask = 0);
+
+ // configure I/O port access
+ void set_ioport(const input_port_config &ioport);
+
+ // read via the underlying delegates
+ UINT8 read8(address_space &space, offs_t offset, UINT8 mask) const { return m_read8(space, offset, mask); }
+ UINT16 read16(address_space &space, offs_t offset, UINT16 mask) const { return m_read16(space, offset, mask); }
+ UINT32 read32(address_space &space, offs_t offset, UINT32 mask) const { return m_read32(space, offset, mask); }
+ UINT64 read64(address_space &space, offs_t offset, UINT64 mask) const { return m_read64(space, offset, mask); }
+
+private:
+ // stubs for converting between address sizes
+ UINT16 read_stub_16_from_8(address_space &space, offs_t offset, UINT16 mask);
+ UINT32 read_stub_32_from_8(address_space &space, offs_t offset, UINT32 mask);
+ UINT64 read_stub_64_from_8(address_space &space, offs_t offset, UINT64 mask);
+ UINT32 read_stub_32_from_16(address_space &space, offs_t offset, UINT32 mask);
+ UINT64 read_stub_64_from_16(address_space &space, offs_t offset, UINT64 mask);
+ UINT64 read_stub_64_from_32(address_space &space, offs_t offset, UINT64 mask);
+
+ // stubs for calling legacy read handlers
+ UINT8 read_stub_legacy(address_space &space, offs_t offset, UINT8 mask);
+ UINT16 read_stub_legacy(address_space &space, offs_t offset, UINT16 mask);
+ UINT32 read_stub_legacy(address_space &space, offs_t offset, UINT32 mask);
+ UINT64 read_stub_legacy(address_space &space, offs_t offset, UINT64 mask);
+
+ // stubs for reading I/O ports
+ template<typename _UintType>
+ _UintType read_stub_ioport(address_space &space, offs_t offset, _UintType mask) { return input_port_read_direct(m_ioport); }
+
+ // internal state
+ read8_delegate m_read8;
+ read16_delegate m_read16;
+ read32_delegate m_read32;
+ read64_delegate m_read64;
+ const input_port_config * m_ioport;
+
+ // unions to hold legacy objects and callbacks
+ union
+ {
+ const address_space * space;
+ device_t * device;
+ } m_legacy_object;
+
+ union
+ {
+ read8_space_func space8;
+ read16_space_func space16;
+ read32_space_func space32;
+ read64_space_func space64;
+ read8_device_func device8;
+ read16_device_func device16;
+ read32_device_func device32;
+ read64_device_func device64;
+ } m_legacy_handler;
};
-struct _memory_private
+
+// ======================> handler_entry_write
+
+// a write-access-specific extension of handler_entry
+class handler_entry_write : public handler_entry
{
- UINT8 initialized; /* have we completed initialization? */
+public:
+ // construction/destruction
+ handler_entry_write(UINT8 width, endianness_t endianness, UINT8 **rambaseptr)
+ : handler_entry(width, endianness, rambaseptr)
+ {
+ m_legacy_object.space = NULL;
+ m_legacy_handler.space8 = NULL;
+ }
+
+ // getters
+ virtual const char *name() const;
+
+ // configure delegate callbacks
+ void set_delegate(write8_delegate delegate, UINT64 mask = 0);
+ void set_delegate(write16_delegate delegate, UINT64 mask = 0);
+ void set_delegate(write32_delegate delegate, UINT64 mask = 0);
+ void set_delegate(write64_delegate delegate, UINT64 mask = 0);
+
+ // configure legacy address space functions
+ void set_legacy_func(const address_space &space, write8_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, write16_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, write32_space_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(const address_space &space, write64_space_func func, const char *name, UINT64 mask = 0);
+
+ // configure legacy device functions
+ void set_legacy_func(device_t &device, write8_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, write16_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, write32_device_func func, const char *name, UINT64 mask = 0);
+ void set_legacy_func(device_t &device, write64_device_func func, const char *name, UINT64 mask = 0);
+
+ // configure I/O port access
+ void set_ioport(const input_port_config &ioport);
+
+ // write via the underlying delegates
+ void write8(address_space &space, offs_t offset, UINT8 data, UINT8 mask) const { m_write8(space, offset, data, mask); }
+ void write16(address_space &space, offs_t offset, UINT16 data, UINT16 mask) const { m_write16(space, offset, data, mask); }
+ void write32(address_space &space, offs_t offset, UINT32 data, UINT32 mask) const { m_write32(space, offset, data, mask); }
+ void write64(address_space &space, offs_t offset, UINT64 data, UINT64 mask) const { m_write64(space, offset, data, mask); }
+
+private:
+ // stubs for converting between address sizes
+ void write_stub_16_from_8(address_space &space, offs_t offset, UINT16 data, UINT16 mask);
+ void write_stub_32_from_8(address_space &space, offs_t offset, UINT32 data, UINT32 mask);
+ void write_stub_64_from_8(address_space &space, offs_t offset, UINT64 data, UINT64 mask);
+ void write_stub_32_from_16(address_space &space, offs_t offset, UINT32 data, UINT32 mask);
+ void write_stub_64_from_16(address_space &space, offs_t offset, UINT64 data, UINT64 mask);
+ void write_stub_64_from_32(address_space &space, offs_t offset, UINT64 data, UINT64 mask);
+
+ // stubs for calling legacy write handlers
+ void write_stub_legacy(address_space &space, offs_t offset, UINT8 data, UINT8 mask);
+ void write_stub_legacy(address_space &space, offs_t offset, UINT16 data, UINT16 mask);
+ void write_stub_legacy(address_space &space, offs_t offset, UINT32 data, UINT32 mask);
+ void write_stub_legacy(address_space &space, offs_t offset, UINT64 data, UINT64 mask);
+
+ // stubs for writing I/O ports
+ template<typename _UintType>
+ void write_stub_ioport(address_space &space, offs_t offset, _UintType data, _UintType mask) { input_port_write_direct(m_ioport, data, mask); }
+
+ // internal state
+ write8_delegate m_write8;
+ write16_delegate m_write16;
+ write32_delegate m_write32;
+ write64_delegate m_write64;
+ const input_port_config * m_ioport;
+
+ // unions to hold legacy objects and callbacks
+ union
+ {
+ const address_space * space;
+ device_t * device;
+ } m_legacy_object;
- const address_space * spacelist; /* list of address spaces */
+ union
+ {
+ write8_space_func space8;
+ write16_space_func space16;
+ write32_space_func space32;
+ write64_space_func space64;
+ write8_device_func device8;
+ write16_device_func device16;
+ write32_device_func device32;
+ write64_device_func device64;
+ } m_legacy_handler;
+};
- UINT8 * bank_ptr[STATIC_COUNT]; /* array of bank pointers */
- UINT8 * bankd_ptr[STATIC_COUNT]; /* array of decrypted bank pointers */
- memory_block * memory_block_list; /* head of the list of memory blocks */
+// ======================> address_table
- tagmap_t<bank_info *> bankmap; /* map for fast bank lookups */
- bank_info * banklist; /* data gathered for each bank */
- UINT8 banknext; /* next bank to allocate */
+// address_table contains information about read/write accesses within an address space
+class address_table : public bindable_object
+{
+ // address map lookup table definitions
+ static const int LEVEL1_BITS = 18; // number of address bits in the level 1 table
+ static const int LEVEL2_BITS = 32 - LEVEL1_BITS; // number of address bits in the level 2 table
+ static const int SUBTABLE_COUNT = 64; // number of slots reserved for subtables
+ static const int SUBTABLE_BASE = 256 - SUBTABLE_COUNT; // first index of a subtable
+ static const int ENTRY_COUNT = SUBTABLE_BASE; // number of legitimate (non-subtable) entries
+ static const int SUBTABLE_ALLOC = 8; // number of subtables to allocate at a time
- tagmap_t<void *> sharemap; /* map for share lookups */
+ inline int level2_bits() const { return m_large ? LEVEL2_BITS : 0; }
- UINT8 * wptable; /* watchpoint-fill table */
-};
+public:
+ // construction/destruction
+ address_table(address_space &space, bool large);
+ ~address_table();
+
+ // getters
+ virtual handler_entry &handler(UINT32 index) const = 0;
+ bool watchpoints_enabled() const { return (m_live_lookup == s_watchpoint_table); }
+ // address lookups
+ UINT32 lookup_live(offs_t byteaddress) const { return m_large ? lookup_live_large(byteaddress) : lookup_live_small(byteaddress); }
+ UINT32 lookup_live_small(offs_t byteaddress) const { return m_live_lookup[byteaddress]; }
+ UINT32 lookup_live_large(offs_t byteaddress) const
+ {
+ UINT32 entry = m_live_lookup[level1_index_large(byteaddress)];
+ if (entry >= SUBTABLE_BASE)
+ entry = m_live_lookup[level2_index_large(entry, byteaddress)];
+ return entry;
+ }
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
+ UINT32 lookup(offs_t byteaddress) const
+ {
+ UINT32 entry = m_live_lookup[level1_index(byteaddress)];
+ if (entry >= SUBTABLE_BASE)
+ entry = m_live_lookup[level2_index(entry, byteaddress)];
+ return entry;
+ }
-#define ACCESSOR_GROUP(width) \
-{ \
- memory_read_byte_##width, \
- memory_read_word_##width, \
- memory_read_word_masked_##width, \
- memory_read_dword_##width, \
- memory_read_dword_masked_##width, \
- memory_read_qword_##width, \
- memory_read_qword_masked_##width, \
- memory_write_byte_##width, \
- memory_write_word_##width, \
- memory_write_word_masked_##width, \
- memory_write_dword_##width, \
- memory_write_dword_masked_##width, \
- memory_write_qword_##width, \
- memory_write_qword_masked_##width \
-}
-
-static const data_accessors memory_accessors[4][2] =
-{
- { ACCESSOR_GROUP(8le), ACCESSOR_GROUP(8be) },
- { ACCESSOR_GROUP(16le), ACCESSOR_GROUP(16be) },
- { ACCESSOR_GROUP(32le), ACCESSOR_GROUP(32be) },
- { ACCESSOR_GROUP(64le), ACCESSOR_GROUP(64be) }
+ // enable watchpoints by swapping in the watchpoint table
+ void enable_watchpoints(bool enable = true) { m_live_lookup = enable ? s_watchpoint_table : m_table; }
+
+ // table mapping helpers
+ UINT8 map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, UINT8 staticentry = 0);
+ UINT8 derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const;
+
+ // misc helpers
+ void mask_all_handlers(offs_t mask);
+ const char *handler_name(UINT8 entry) const;
+
+protected:
+ // determine table indexes based on the address
+ UINT32 level1_index_large(offs_t address) const { return address >> LEVEL2_BITS; }
+ UINT32 level2_index_large(UINT8 l1entry, offs_t address) const { return (1 << LEVEL1_BITS) + ((l1entry - SUBTABLE_BASE) << LEVEL2_BITS) + (address & ((1 << LEVEL2_BITS) - 1)); }
+ UINT32 level1_index(offs_t address) const { return m_large ? level1_index_large(address) : address; }
+ UINT32 level2_index(UINT8 l1entry, offs_t address) const { return m_large ? level2_index_large(l1entry, address) : 0; }
+
+ // table population/depopulation
+ void populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handler);
+ void populate_range(offs_t bytestart, offs_t byteend, UINT8 handler);
+ void depopulate_unused();
+
+ // subtable management
+ UINT8 subtable_alloc();
+ void subtable_realloc(UINT8 subentry);
+ int subtable_merge();
+ void subtable_release(UINT8 subentry);
+ UINT8 *subtable_open(offs_t l1index);
+ void subtable_close(offs_t l1index);
+ UINT8 *subtable_ptr(UINT8 entry) { return &m_table[level2_index(entry, 0)]; }
+
+ // internal state
+ UINT8 * m_table; // pointer to base of table
+ UINT8 * m_live_lookup; // current lookup
+ address_space & m_space; // pointer back to the space
+ bool m_large; // large memory model?
+
+ // subtable_data is an internal class with information about each subtable
+ class subtable_data
+ {
+ public:
+ subtable_data()
+ : m_checksum_valid(false),
+ m_checksum(0),
+ m_usecount(0) { }
+
+ bool m_checksum_valid; // is the checksum valid
+ UINT32 m_checksum; // checksum over all the bytes
+ UINT32 m_usecount; // number of times this has been used
+ };
+ subtable_data * m_subtable; // info about each subtable
+ UINT8 m_subtable_alloc; // number of subtables allocated
+
+ // static global read-only watchpoint table
+ static UINT8 s_watchpoint_table[1 << LEVEL1_BITS];
};
+// ======================> address_table_read
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+// read access-specific version of an address table
+class address_table_read : public address_table
+{
+public:
+ // construction/destruction
+ address_table_read(address_space &space, bool large);
+ ~address_table_read();
-/* internal initialization */
-static void memory_init_spaces(running_machine *machine);
-static void memory_init_preflight(running_machine *machine);
-static void memory_init_populate(running_machine *machine);
-static void memory_init_map_entry(address_space *space, const address_map_entry *entry, read_or_write readorwrite);
-static void memory_init_allocate(running_machine *machine);
-static void memory_init_locate(running_machine *machine);
-static void memory_exit(running_machine &machine);
-
-/* memory mapping helpers */
-static void space_map_range(address_space *space, read_or_write readorwrite, int handlerbits, int handlerunitmask, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, genf *handler, void *object, const char *handler_name);
-static void *space_find_backing_memory(const address_space *space, offs_t addrstart, offs_t addrend);
-static int space_needs_backing_store(const address_space *space, const address_map_entry *entry);
-
-/* banking helpers */
-static genf *bank_find_or_allocate(const address_space *space, const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite);
-static STATE_POSTLOAD( bank_reattach );
+ // getters
+ virtual handler_entry &handler(UINT32 index) const;
+ handler_entry_read &handler_read(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
+
+private:
+ // internal unmapped handler
+ template<typename _UintType>
+ _UintType unmap_r(address_space &space, offs_t offset, _UintType mask)
+ {
+ if (m_space.log_unmap() && !m_space.debugger_access())
+ logerror("%s: unmapped %s memory read from %s\n", cpuexec_describe_context(&m_space.m_machine), m_space.name(), core_i64_hex_format(m_space.byte_to_address(offset), m_space.addrchars()));
+ return m_space.unmap();
+ }
+
+ // internal no-op handler
+ template<typename _UintType>
+ _UintType nop_r(address_space &space, offs_t offset, _UintType mask)
+ {
+ return m_space.unmap();
+ }
-/* table management */
-static UINT8 table_assign_handler(const address_space *space, handler_data **table, void *object, genf *handler, const char *handler_name, offs_t bytestart, offs_t byteend, offs_t bytemask);
-static void table_compute_subhandler(handler_data **table, UINT8 entry, read_or_write readorwrite, int spacebits, int spaceendian, int handlerbits, int handlerunitmask);
-static void table_populate_range(address_table *tabledata, offs_t bytestart, offs_t byteend, UINT8 handler);
-static void table_populate_range_mirrored(address_space *space, address_table *tabledata, offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handler);
-static UINT8 table_derive_range(const address_table *table, offs_t byteaddress, offs_t *bytestart, offs_t *byteend);
+ // internal watchpoint handler
+ template<typename _UintType>
+ _UintType watchpoint_r(address_space &space, offs_t offset, _UintType mask)
+ {
+ m_space.device().debug()->memory_read_hook(m_space, offset, mask);
+
+ UINT8 *oldtable = m_live_lookup;
+ m_live_lookup = m_table;
+ _UintType result;
+ if (sizeof(_UintType) == 1) result = m_space.read_byte(offset);
+ if (sizeof(_UintType) == 2) result = m_space.read_word(offset, mask);
+ if (sizeof(_UintType) == 4) result = m_space.read_dword(offset, mask);
+ if (sizeof(_UintType) == 8) result = m_space.read_qword(offset, mask);
+ m_live_lookup = oldtable;
+ return result;
+ }
-/* subtable management */
-static UINT8 subtable_alloc(address_table *tabledata);
-static void subtable_realloc(address_table *tabledata, UINT8 subentry);
-static int subtable_merge(address_table *tabledata);
-static void subtable_release(address_table *tabledata, UINT8 subentry);
-static UINT8 *subtable_open(address_table *tabledata, offs_t l1index);
-static void subtable_close(address_table *tabledata, offs_t l1index);
+ // internal state
+ handler_entry_read * m_handlers[256]; // array of user-installed handlers
+};
-/* direct memory ranges */
-static direct_range *direct_range_find(address_space *space, offs_t byteaddress, UINT8 *entry);
-static void direct_range_remove_intersecting(address_space *space, offs_t bytestart, offs_t byteend);
-/* memory block allocation */
-static void *block_allocate(const address_space *space, offs_t bytestart, offs_t byteend, void *memory);
-static address_map_entry *block_assign_intersecting(address_space *space, offs_t bytestart, offs_t byteend, UINT8 *base);
+// ======================> address_table_write
-/* internal handlers */
-static memory_handler get_stub_handler(read_or_write readorwrite, int spacedbits, int handlerdbits);
-static genf *get_static_handler(int handlerbits, int readorwrite, int which);
+// write access-specific version of an address table
+class address_table_write : public address_table
+{
+public:
+ // construction/destruction
+ address_table_write(address_space &space, bool large);
+ ~address_table_write();
-/* debugging */
-static const char *handler_to_string(const address_space *space, const address_table *table, UINT8 entry);
-static void dump_map(FILE *file, const address_space *space, const address_table *table);
-static void mem_dump(running_machine *machine);
+ // getters
+ virtual handler_entry &handler(UINT32 index) const;
+ handler_entry_write &handler_write(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
-/* input port handlers */
-static UINT8 input_port_read8(const input_port_config *port, offs_t offset);
-static UINT16 input_port_read16(const input_port_config *port, offs_t offset, UINT16 mem_mask);
-static UINT32 input_port_read32(const input_port_config *port, offs_t offset, UINT32 mem_mask);
-static UINT64 input_port_read64(const input_port_config *port, offs_t offset, UINT64 mem_mask);
+private:
+ // internal handlers
+ template<typename _UintType>
+ void unmap_w(address_space &space, offs_t offset, _UintType data, _UintType mask)
+ {
+ if (m_space.log_unmap() && !m_space.debugger_access())
+ logerror("%s: unmapped %s memory write to %s\n", cpuexec_describe_context(&m_space.m_machine), m_space.name(), core_i64_hex_format(m_space.byte_to_address(offset), m_space.addrchars()));
+ }
-/* output port handlers */
-static void input_port_write8(const input_port_config *port, offs_t offset, UINT8 data);
-static void input_port_write16(const input_port_config *port, offs_t offset, UINT16 data, UINT16 mem_mask);
-static void input_port_write32(const input_port_config *port, offs_t offset, UINT32 data, UINT32 mem_mask);
-static void input_port_write64(const input_port_config *port, offs_t offset, UINT64 data, UINT64 mem_mask);
+ template<typename _UintType>
+ void nop_w(address_space &space, offs_t offset, _UintType data, _UintType mask)
+ {
+ }
+ template<typename _UintType>
+ void watchpoint_w(address_space &space, offs_t offset, _UintType data, _UintType mask)
+ {
+ m_space.device().debug()->memory_write_hook(m_space, offset, data, 0xff);
+
+ UINT8 *oldtable = m_live_lookup;
+ m_live_lookup = m_table;
+ if (sizeof(_UintType) == 1) m_space.write_byte(offset, data);
+ if (sizeof(_UintType) == 2) m_space.write_word(offset, data, mask);
+ if (sizeof(_UintType) == 4) m_space.write_dword(offset, data, mask);
+ if (sizeof(_UintType) == 8) m_space.write_qword(offset, data, mask);
+ m_live_lookup = oldtable;
+ }
+ // internal state
+ handler_entry_write * m_handlers[256]; // array of user-installed handlers
+};
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-/*-------------------------------------------------
- force_opbase_update - ensure that we update
- the opcode base
--------------------------------------------------*/
+// ======================> address_space_specific
-INLINE void force_opbase_update(const address_space *space)
+// this is a derived class of address_space with specific width, endianness, and table size
+template<typename _NativeType, endianness_t _Endian, bool _Large>
+class address_space_specific : public address_space
{
- address_space *spacerw = (address_space *)space;
- spacerw->direct.byteend = 0;
- spacerw->direct.bytestart = 1;
-}
+ typedef address_space_specific<_NativeType, _Endian, _Large> this_type;
+ // helpers to simplify core code
+ offs_t endian_xor(offs_t value) { if (_Endian == ENDIANNESS_BIG) value = ~value; return value; }
+ int endian_shift(int levalue, int bevalue) { return (_Endian == ENDIANNESS_LITTLE) ? levalue : bevalue; }
+ UINT32 read_lookup(offs_t byteaddress) const { return _Large ? m_read.lookup_live_large(byteaddress) : m_read.lookup_live_small(byteaddress); }
+ UINT32 write_lookup(offs_t byteaddress) const { return _Large ? m_write.lookup_live_large(byteaddress) : m_write.lookup_live_small(byteaddress); }
-/*-------------------------------------------------
- adjust_addresses - adjust addresses for a
- given address space in a standard fashion
--------------------------------------------------*/
+public:
+ // construction/destruction
+ address_space_specific(device_memory_interface &memory, int spacenum)
+ : address_space(memory, spacenum, _Large),
+ m_read(*this, _Large),
+ m_write(*this, _Large) { }
+
+ // accessors
+ virtual address_table_read &read() { return m_read; }
+ virtual address_table_write &write() { return m_write; }
-INLINE void adjust_addresses(const address_space *space, offs_t *start, offs_t *end, offs_t *mask, offs_t *mirror)
-{
- /* adjust start/end/mask values */
- if (*mask == 0)
- *mask = space->addrmask & ~*mirror;
- else
- *mask &= space->addrmask;
- *start &= ~*mirror & space->addrmask;
- *end &= ~*mirror & space->addrmask;
+ // watchpoint control
+ virtual void enable_read_watchpoints(bool enable = true) { m_read.enable_watchpoints(enable); }
+ virtual void enable_write_watchpoints(bool enable = true) { m_write.enable_watchpoints(enable); }
- /* adjust to byte values */
- *start = memory_address_to_byte(space, *start);
- *end = memory_address_to_byte_end(space, *end);
- *mask = memory_address_to_byte_end(space, *mask);
- *mirror = memory_address_to_byte(space, *mirror);
-}
+ // generate accessor table
+ virtual void accessors(data_accessors &accessors) const
+ {
+ accessors.read_byte = reinterpret_cast<UINT8 (*)(const address_space *, offs_t)>(&read_byte_static);
+ accessors.read_word = reinterpret_cast<UINT16 (*)(const address_space *, offs_t)>(&read_word_static);
+ accessors.read_word_masked = reinterpret_cast<UINT16 (*)(const address_space *, offs_t, UINT16)>(&read_word_masked_static);
+ accessors.read_dword = reinterpret_cast<UINT32 (*)(const address_space *, offs_t)>(&read_dword_static);
+ accessors.read_dword_masked = reinterpret_cast<UINT32 (*)(const address_space *, offs_t, UINT32)>(&read_dword_masked_static);
+ accessors.read_qword = reinterpret_cast<UINT64 (*)(const address_space *, offs_t)>(&read_qword_static);
+ accessors.read_qword_masked = reinterpret_cast<UINT64 (*)(const address_space *, offs_t, UINT64)>(&read_qword_masked_static);
+ accessors.write_byte = reinterpret_cast<void (*)(const address_space *, offs_t, UINT8)>(&write_byte_static);
+ accessors.write_word = reinterpret_cast<void (*)(const address_space *, offs_t, UINT16)>(&write_word_static);
+ accessors.write_word_masked = reinterpret_cast<void (*)(const address_space *, offs_t, UINT16, UINT16)>(&write_word_masked_static);
+ accessors.write_dword = reinterpret_cast<void (*)(const address_space *, offs_t, UINT32)>(&write_dword_static);
+ accessors.write_dword_masked = reinterpret_cast<void (*)(const address_space *, offs_t, UINT32, UINT32)>(&write_dword_masked_static);
+ accessors.write_qword = reinterpret_cast<void (*)(const address_space *, offs_t, UINT64)>(&write_qword_static);
+ accessors.write_qword_masked = reinterpret_cast<void (*)(const address_space *, offs_t, UINT64, UINT64)>(&write_qword_masked_static);
+ }
+ //
+ virtual void *get_read_ptr(offs_t byteaddress)
+ {
+ // perform the lookup
+ byteaddress &= m_bytemask;
+ UINT32 entry = read_lookup(byteaddress);
+ const handler_entry_read &handler = m_read.handler_read(entry);
+
+ // 8-bit case: RAM/ROM
+ if (entry >= STATIC_RAM)
+ return NULL;
+ return handler.ramptr(handler.byteoffset(byteaddress));
+ }
-/*-------------------------------------------------
- bank_references_space - return true if the
- given bank is referenced by a particular
- address space
--------------------------------------------------*/
+ virtual void *get_write_ptr(offs_t byteaddress)
+ {
+ // perform the lookup
+ byteaddress &= m_bytemask;
+ UINT32 entry = read_lookup(byteaddress);
+ const handler_entry_write &handler = m_write.handler_write(entry);
+
+ // 8-bit case: RAM/ROM
+ if (entry >= STATIC_RAM)
+ return NULL;
+ return handler.ramptr(handler.byteoffset(byteaddress));
+ }
-INLINE int bank_references_space(const bank_info *bank, const address_space *space)
-{
- bank_reference *ref;
+ // native read
+ _NativeType read_native(offs_t offset, _NativeType mask)
+ {
+ profiler_mark_start(PROFILER_MEMREAD);
+
+ // look up the handler
+ offs_t byteaddress = offset & m_bytemask;
+ UINT32 entry = read_lookup(byteaddress);
+ const handler_entry_read &handler = m_read.handler_read(entry);
+
+ // either read directly from RAM, or call the delegate
+ offset = handler.byteoffset(byteaddress) / sizeof(_NativeType);
+ _NativeType result;
+ if (entry < STATIC_RAM) result = *reinterpret_cast<_NativeType *>(handler.ramptr(offset * sizeof(_NativeType)));
+ else if (sizeof(_NativeType) == 1) result = handler.read8(*this, offset, mask);
+ else if (sizeof(_NativeType) == 2) result = handler.read16(*this, offset, mask);
+ else if (sizeof(_NativeType) == 4) result = handler.read32(*this, offset, mask);
+ else if (sizeof(_NativeType) == 8) result = handler.read64(*this, offset, mask);
+
+ profiler_mark_end();
+ return result;
+ }
- for (ref = bank->reflist; ref != NULL; ref = ref->next)
- if (ref->space == space)
- return TRUE;
- return FALSE;
-}
+ // native write
+ void write_native(offs_t offset, _NativeType data, _NativeType mask)
+ {
+ profiler_mark_start(PROFILER_MEMWRITE);
+ // look up the handler
+ offs_t byteaddress = offset & m_bytemask;
+ UINT32 entry = write_lookup(byteaddress);
+ const handler_entry_write &handler = m_write.handler_write(entry);
-/*-------------------------------------------------
- add_bank_reference - add a new address space
- reference to a bank
--------------------------------------------------*/
+ // either write directly to RAM, or call the delegate
+ offset = handler.byteoffset(byteaddress) / sizeof(_NativeType);
+ if (entry < STATIC_RAM)
+ {
+ _NativeType *dest = reinterpret_cast<_NativeType *>(handler.ramptr(offset * sizeof(_NativeType)));
+ *dest = (*dest & ~mask) | (data & mask);
+ }
+ else if (sizeof(_NativeType) == 1) handler.write8(*this, offset, data, mask);
+ else if (sizeof(_NativeType) == 2) handler.write16(*this, offset, data, mask);
+ else if (sizeof(_NativeType) == 4) handler.write32(*this, offset, data, mask);
+ else if (sizeof(_NativeType) == 8) handler.write64(*this, offset, data, mask);
-INLINE void add_bank_reference(bank_info *bank, const address_space *space)
-{
- bank_reference **refptr;
+ profiler_mark_end();
+ }
- /* make sure we don't already have a reference to the bank */
- for (refptr = &bank->reflist; *refptr != NULL; refptr = &(*refptr)->next)
- if ((*refptr)->space == space)
- return;
+ // read byte
+ UINT8 read_byte_direct(offs_t address)
+ {
+ if (sizeof(_NativeType) == 1)
+ return read_native(address, 0xff);
+
+ if (sizeof(_NativeType) > 1)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 1)) * 8;
+ return read_native(address, (_NativeType)0xff << shift) >> shift;
+ }
+ }
+
+ // read word
+ UINT16 read_word_direct(offs_t address, UINT16 mask)
+ {
+ if (sizeof(_NativeType) == 2)
+ return read_native(address, mask);
- /* allocate a new entry and fill it */
- (*refptr) = auto_alloc(space->machine, bank_reference);
- (*refptr)->next = NULL;
- (*refptr)->space = space;
-}
+ if (sizeof(_NativeType) > 2)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 2)) * 8;
+ return read_native(address, (_NativeType)mask << shift) >> shift;
+ }
+
+ if (sizeof(_NativeType) < 2)
+ {
+ UINT16 result = 0;
+ if (EXPECTED(mask & (0xff << endian_shift(0,8)))) result |= read_byte_direct(address + 0) << endian_shift(0,8);
+ if (EXPECTED(mask & (0xff << endian_shift(8,0)))) result |= read_byte_direct(address + 1) << endian_shift(8,0);
+ return result;
+ }
+ }
+ // read dword
+ UINT32 read_dword_direct(offs_t address, UINT32 mask)
+ {
+ if (sizeof(_NativeType) == 4)
+ return read_native(address, mask);
-/*-------------------------------------------------
- read_byte_generic - read a byte from an
- arbitrary address space
--------------------------------------------------*/
+ if (sizeof(_NativeType) > 4)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 4)) * 8;
+ return read_native(address, (_NativeType)mask << shift) >> shift;
+ }
+
+ if (sizeof(_NativeType) < 4)
+ {
+ UINT32 result = 0;
+ if (EXPECTED(mask & (0xffff << endian_shift(0,16)))) result |= read_word_direct(address + 0, mask >> endian_shift(0,16)) << endian_shift(0,16);
+ if (EXPECTED(mask & (0xffff << endian_shift(16,0)))) result |= read_word_direct(address + 2, mask >> endian_shift(16,0)) << endian_shift(16,0);
+ return result;
+ }
+ }
-INLINE UINT8 read_byte_generic(const address_space *space, offs_t byteaddress)
-{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
- UINT8 result;
+ // read qword
+ UINT64 read_qword_direct(offs_t address, UINT64 mask)
+ {
+ if (sizeof(_NativeType) == 8)
+ return read_native(address, mask);
+
+ if (sizeof(_NativeType) < 8)
+ {
+ UINT64 result = 0;
+ if (EXPECTED(mask & (U64(0xffffffff) << endian_shift(0,32)))) result |= (UINT64)read_dword_direct(address + 0, mask >> endian_shift(0,32)) << endian_shift(0,32);
+ if (EXPECTED(mask & (U64(0xffffffff) << endian_shift(32,0)))) result |= (UINT64)read_dword_direct(address + 4, mask >> endian_shift(32,0)) << endian_shift(32,0);
+ return result;
+ }
+ }
+
+ // write byte
+ void write_byte_direct(offs_t address, UINT8 data)
+ {
+ if (sizeof(_NativeType) == 1)
+ return write_native(address, data, 0xff);
+
+ if (sizeof(_NativeType) > 1)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 1)) * 8;
+ return write_native(address, (_NativeType)data << shift, (_NativeType)0xff << shift);
+ }
+ }
+
+ // write word
+ void write_word_direct(offs_t address, UINT16 data, UINT16 mask)
+ {
+ if (sizeof(_NativeType) == 2)
+ return write_native(address, data, mask);
+
+ if (sizeof(_NativeType) > 2)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 2)) * 8;
+ return write_native(address, (_NativeType)data << shift, (_NativeType)mask << shift);
+ }
- profiler_mark_start(PROFILER_MEMREAD);
+ if (sizeof(_NativeType) < 2)
+ {
+ if (EXPECTED(mask & (0xff << endian_shift(0,8)))) write_byte_direct(address + 0, data >> endian_shift(0,8));
+ if (EXPECTED(mask & (0xff << endian_shift(8,0)))) write_byte_direct(address + 1, data >> endian_shift(8,0));
+ }
+ }
+
+ // write dword
+ void write_dword_direct(offs_t address, UINT32 data, UINT32 mask)
+ {
+ if (sizeof(_NativeType) == 4)
+ return write_native(address, data, mask);
+
+ if (sizeof(_NativeType) > 4)
+ {
+ UINT32 shift = (endian_xor(address) & (sizeof(_NativeType) - 4)) * 8;
+ return write_native(address, (_NativeType)data << shift, (_NativeType)mask << shift);
+ }
- byteaddress &= space->bytemask;
- entry = space->readlookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->readlookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->read.handlers[entry];
+ if (sizeof(_NativeType) < 4)
+ {
+ if (EXPECTED(mask & (0xffff << endian_shift(0,16)))) write_word_direct(address + 0, data >> endian_shift(0,16), mask >> endian_shift(0,16));
+ if (EXPECTED(mask & (0xffff << endian_shift(16,0)))) write_word_direct(address + 2, data >> endian_shift(16,0), mask >> endian_shift(16,0));
+ }
+ }
+
+ // write qword
+ void write_qword_direct(offs_t address, UINT64 data, UINT64 mask)
+ {
+ if (sizeof(_NativeType) == 8)
+ return write_native(address, data, mask);
+
+ if (sizeof(_NativeType) < 8)
+ {
+ if (EXPECTED(mask & (U64(0xffffffff) << endian_shift(0,32)))) write_dword_direct(address + 0, data >> endian_shift(0,32), mask >> endian_shift(0,32));
+ if (EXPECTED(mask & (U64(0xffffffff) << endian_shift(32,0)))) write_dword_direct(address + 4, data >> endian_shift(32,0), mask >> endian_shift(32,0));
+ }
+ }
+
+ // virtual access to these functions
+ UINT8 read_byte(offs_t address) { return read_byte_direct(address); }
+ UINT16 read_word(offs_t address, UINT16 mask) { return read_word_direct(address, mask); }
+ UINT32 read_dword(offs_t address, UINT32 mask) { return read_dword_direct(address, mask); }
+ UINT64 read_qword(offs_t address, UINT64 mask) { return read_qword_direct(address, mask); }
+ void write_byte(offs_t address, UINT8 data) { write_byte_direct(address, data); }
+ void write_word(offs_t address, UINT16 data, UINT16 mask) { write_word_direct(address, data, mask); }
+ void write_dword(offs_t address, UINT32 data, UINT32 mask) { write_dword_direct(address, data, mask); }
+ void write_qword(offs_t address, UINT64 data, UINT64 mask) { write_qword_direct(address, data, mask); }
+
+ // static access to these functions
+ static UINT8 read_byte_static(this_type *space, offs_t address) { return space->read_byte_direct(address); }
+ static UINT16 read_word_static(this_type *space, offs_t address) { return space->read_word_direct(address, 0xffff); }
+ static UINT16 read_word_masked_static(this_type *space, offs_t address, UINT16 mask) { return space->read_word_direct(address, mask); }
+ static UINT32 read_dword_static(this_type *space, offs_t address) { return space->read_dword_direct(address, 0xffffffff); }
+ static UINT32 read_dword_masked_static(this_type *space, offs_t address, UINT32 mask) { return space->read_dword_direct(address, mask); }
+ static UINT64 read_qword_static(this_type *space, offs_t address) { return space->read_qword_direct(address, U64(0xffffffffffffffff)); }
+ static UINT64 read_qword_masked_static(this_type *space, offs_t address, UINT64 mask) { return space->read_qword_direct(address, mask); }
+ static void write_byte_static(this_type *space, offs_t address, UINT8 data) { space->write_byte_direct(address, data); }
+ static void write_word_static(this_type *space, offs_t address, UINT16 data) { space->write_word_direct(address, data, 0xffff); }
+ static void write_word_masked_static(this_type *space, offs_t address, UINT16 data, UINT16 mask) { space->write_word_direct(address, data, mask); }
+ static void write_dword_static(this_type *space, offs_t address, UINT32 data) { space->write_dword_direct(address, data, 0xffffffff); }
+ static void write_dword_masked_static(this_type *space, offs_t address, UINT32 data, UINT32 mask) { space->write_dword_direct(address, data, mask); }
+ static void write_qword_static(this_type *space, offs_t address, UINT64 data) { space->write_qword_direct(address, data, U64(0xffffffffffffffff)); }
+ static void write_qword_masked_static(this_type *space, offs_t address, UINT64 data, UINT64 mask) { space->write_qword_direct(address, data, mask); }
+
+ address_table_read m_read; // memory read lookup table
+ address_table_write m_write; // memory write lookup table
+};
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- result = (*handler->bankbaseptr)[byteoffset];
- else
- result = (*handler->handler.read.shandler8)((const address_space *)handler->object, byteoffset);
+typedef address_space_specific<UINT8, ENDIANNESS_LITTLE, false> address_space_8le_small;
+typedef address_space_specific<UINT8, ENDIANNESS_BIG, false> address_space_8be_small;
+typedef address_space_specific<UINT16, ENDIANNESS_LITTLE, false> address_space_16le_small;
+typedef address_space_specific<UINT16, ENDIANNESS_BIG, false> address_space_16be_small;
+typedef address_space_specific<UINT32, ENDIANNESS_LITTLE, false> address_space_32le_small;
+typedef address_space_specific<UINT32, ENDIANNESS_BIG, false> address_space_32be_small;
+typedef address_space_specific<UINT64, ENDIANNESS_LITTLE, false> address_space_64le_small;
+typedef address_space_specific<UINT64, ENDIANNESS_BIG, false> address_space_64be_small;
- profiler_mark_end();
- return result;
-}
+typedef address_space_specific<UINT8, ENDIANNESS_LITTLE, true> address_space_8le_large;
+typedef address_space_specific<UINT8, ENDIANNESS_BIG, true> address_space_8be_large;
+typedef address_space_specific<UINT16, ENDIANNESS_LITTLE, true> address_space_16le_large;
+typedef address_space_specific<UINT16, ENDIANNESS_BIG, true> address_space_16be_large;
+typedef address_space_specific<UINT32, ENDIANNESS_LITTLE, true> address_space_32le_large;
+typedef address_space_specific<UINT32, ENDIANNESS_BIG, true> address_space_32be_large;
+typedef address_space_specific<UINT64, ENDIANNESS_LITTLE, true> address_space_64le_large;
+typedef address_space_specific<UINT64, ENDIANNESS_BIG, true> address_space_64be_large;
-/*-------------------------------------------------
- write_byte_generic - write a byte to an
- arbitrary address space
--------------------------------------------------*/
+// ======================> _memory_private
-INLINE void write_byte_generic(const address_space *space, offs_t byteaddress, UINT8 data)
+// holds internal state for the memory system
+struct _memory_private
{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
+ bool initialized; // have we completed initialization?
- profiler_mark_start(PROFILER_MEMWRITE);
+ UINT8 * bank_ptr[STATIC_COUNT]; // array of bank pointers
+ UINT8 * bankd_ptr[STATIC_COUNT]; // array of decrypted bank pointers
- byteaddress &= space->bytemask;
- entry = space->writelookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->writelookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->write.handlers[entry];
+ simple_list<address_space> spacelist; // list of address spaces
+ simple_list<memory_block> blocklist; // head of the list of memory blocks
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- (*handler->bankbaseptr)[byteoffset] = data;
- else
- (*handler->handler.write.shandler8)((const address_space *)handler->object, byteoffset, data);
+ simple_list<memory_bank> banklist; // data gathered for each bank
+ tagmap_t<memory_bank *> bankmap; // map for fast bank lookups
+ UINT8 banknext; // next bank to allocate
- profiler_mark_end();
-}
+ tagmap_t<void *> sharemap; // map for share lookups
+};
-/*-------------------------------------------------
- read_word_generic - read a word from an
- arbitrary address space
--------------------------------------------------*/
-INLINE UINT16 read_word_generic(const address_space *space, offs_t byteaddress, UINT16 mem_mask)
-{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
- UINT16 result;
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
- profiler_mark_start(PROFILER_MEMREAD);
+// global watchpoint table
+UINT8 address_table::s_watchpoint_table[1 << LEVEL1_BITS];
- byteaddress &= space->bytemask;
- entry = space->readlookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->readlookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->read.handlers[entry];
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- result = *(UINT16 *)&(*handler->bankbaseptr)[byteoffset & ~1];
- else
- result = (*handler->handler.read.shandler16)((const address_space *)handler->object, byteoffset >> 1, mem_mask);
- profiler_mark_end();
- return result;
-}
+//**************************************************************************
+// FUNCTION PROTOTYPES
+//**************************************************************************
+
+// banking helpers
+static STATE_POSTLOAD( bank_reattach );
+
+// debugging
+static void generate_memdump(running_machine *machine);
-/*-------------------------------------------------
- write_word_generic - write a word to an
- arbitrary address space
--------------------------------------------------*/
-INLINE void write_word_generic(const address_space *space, offs_t byteaddress, UINT16 data, UINT16 mem_mask)
+//**************************************************************************
+// CORE SYSTEM OPERATIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// memory_init - initialize the memory system
+//-------------------------------------------------
+
+void memory_init(running_machine *machine)
{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
+ // allocate our private data
+ memory_private *memdata = machine->memory_data = auto_alloc_clear(machine, memory_private);
+ memdata->banknext = STATIC_BANK1;
+
+ // loop over devices and spaces within each device
+ device_memory_interface *memory = NULL;
+ for (bool gotone = machine->m_devicelist.first(memory); gotone; gotone = memory->next(memory))
+ for (int spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ {
+ // if there is a configuration for this space, we need an address space
+ const address_space_config *spaceconfig = memory->space_config(spacenum);
+ if (spaceconfig != NULL)
+ memdata->spacelist.append(address_space::allocate(*machine, *spaceconfig, *memory, spacenum));
+ }
- profiler_mark_start(PROFILER_MEMWRITE);
+ // construct and preprocess the address_map for each space
+ for (address_space *space = memdata->spacelist.first(); space != NULL; space = space->next())
+ space->prepare_map();
- byteaddress &= space->bytemask;
- entry = space->writelookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->writelookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->write.handlers[entry];
+ // create the handlers from the resulting address maps
+ for (address_space *space = memdata->spacelist.first(); space != NULL; space = space->next())
+ space->populate_from_map();
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- {
- UINT16 *dest = (UINT16 *)&(*handler->bankbaseptr)[byteoffset & ~1];
- *dest = (*dest & ~mem_mask) | (data & mem_mask);
- }
- else
- (*handler->handler.write.shandler16)((const address_space *)handler->object, byteoffset >> 1, data, mem_mask);
+ // allocate memory needed to back each address space
+ for (address_space *space = memdata->spacelist.first(); space != NULL; space = space->next())
+ space->allocate_memory();
- profiler_mark_end();
-}
+ // find all the allocated pointers
+ for (address_space *space = memdata->spacelist.first(); space != NULL; space = space->next())
+ space->locate_memory();
+
+ // register a callback to reset banks when reloading state
+ state_save_register_postload(machine, bank_reattach, NULL);
+ // dump the final memory configuration
+ generate_memdump(machine);
-/*-------------------------------------------------
- read_dword_generic - read a dword from an
- arbitrary address space
--------------------------------------------------*/
+ // borrow the first address space to be used as a dummy space
+ machine->m_nonspecific_space = memdata->spacelist.first();
-INLINE UINT32 read_dword_generic(const address_space *space, offs_t byteaddress, UINT32 mem_mask)
-{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
- UINT32 result;
+ // we are now initialized
+ memdata->initialized = true;
+}
- profiler_mark_start(PROFILER_MEMREAD);
- byteaddress &= space->bytemask;
- entry = space->readlookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->readlookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->read.handlers[entry];
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- result = *(UINT32 *)&(*handler->bankbaseptr)[byteoffset & ~3];
- else
- result = (*handler->handler.read.shandler32)((const address_space *)handler->object, byteoffset >> 2, mem_mask);
+//**************************************************************************
+// MEMORY BANKING
+//**************************************************************************
- profiler_mark_end();
- return result;
+//-------------------------------------------------
+// memory_configure_bank - configure the
+// addresses for a bank
+//-------------------------------------------------
+
+void memory_configure_bank(running_machine *machine, const char *tag, int startentry, int numentries, void *base, offs_t stride)
+{
+ // validation checks
+ memory_bank *bank = machine->memory_data->bankmap.find_hash_only(tag);
+ if (bank == NULL)
+ fatalerror("memory_configure_bank called for unknown bank '%s'", tag);
+ if (base == NULL)
+ fatalerror("memory_configure_bank called NULL base");
+
+ // fill in the requested bank entries (backwards to improve allocation)
+ for (int entrynum = startentry + numentries - 1; entrynum >= startentry; entrynum--)
+ bank->configure(entrynum, reinterpret_cast<UINT8 *>(base) + (entrynum - startentry) * stride);
}
-/*-------------------------------------------------
- write_dword_generic - write a dword to an
- arbitrary address space
--------------------------------------------------*/
+//-------------------------------------------------
+// memory_configure_bank_decrypted - configure
+// the decrypted addresses for a bank
+//-------------------------------------------------
-INLINE void write_dword_generic(const address_space *space, offs_t byteaddress, UINT32 data, UINT32 mem_mask)
+void memory_configure_bank_decrypted(running_machine *machine, const char *tag, int startentry, int numentries, void *base, offs_t stride)
{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
+ // validation checks
+ memory_bank *bank = machine->memory_data->bankmap.find_hash_only(tag);
+ if (bank == NULL)
+ fatalerror("memory_configure_bank_decrypted called for unknown bank '%s'", tag);
+ if (base == NULL)
+ fatalerror("memory_configure_bank_decrypted called NULL base");
- profiler_mark_start(PROFILER_MEMWRITE);
+ // fill in the requested bank entries (backwards to improve allocation)
+ for (int entrynum = startentry + numentries - 1; entrynum >= startentry; entrynum--)
+ bank->configure_decrypted(entrynum, reinterpret_cast<UINT8 *>(base) + (entrynum - startentry) * stride);
+}
- byteaddress &= space->bytemask;
- entry = space->writelookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->writelookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->write.handlers[entry];
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- {
- UINT32 *dest = (UINT32 *)&(*handler->bankbaseptr)[byteoffset & ~3];
- *dest = (*dest & ~mem_mask) | (data & mem_mask);
- }
- else
- (*handler->handler.write.shandler32)((const address_space *)handler->object, byteoffset >> 2, data, mem_mask);
+//-------------------------------------------------
+// memory_set_bank - select one pre-configured
+// entry to be the new bank base
+//-------------------------------------------------
+
+void memory_set_bank(running_machine *machine, const char *tag, int entrynum)
+{
+ // validation checks
+ memory_bank *bank = machine->memory_data->bankmap.find_hash_only(tag);
+ if (bank == NULL)
+ fatalerror("memory_set_bank called for unknown bank '%s'", tag);
- profiler_mark_end();
+ // set the base
+ bank->set_entry(entrynum);
}
-/*-------------------------------------------------
- read_qword_generic - read a qword from an
- arbitrary address space
--------------------------------------------------*/
+//-------------------------------------------------
+// memory_get_bank - return the currently
+// selected bank
+//-------------------------------------------------
-INLINE UINT64 read_qword_generic(const address_space *space, offs_t byteaddress, UINT64 mem_mask)
+int memory_get_bank(running_machine *machine, const char *tag)
{
- const handler_data *handler;
- offs_t byteoffset;
- UINT32 entry;
- UINT64 result;
+ // validation checks
+ memory_bank *bank = machine->memory_data->bankmap.find_hash_only(tag);
+ if (bank == NULL)
+ fatalerror("memory_get_bank called for unknown bank '%s'", tag);
- profiler_mark_start(PROFILER_MEMREAD);
+ // return the current entry
+ return bank->entry();
+}
- byteaddress &= space->bytemask;
- entry = space->readlookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->readlookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->read.handlers[entry];
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
- result = *(UINT64 *)&(*handler->bankbaseptr)[byteoffset & ~7];
- else
- result = (*handler->handler.read.shandler64)((const address_space *)handler->object, byteoffset >> 3, mem_mask);
+//-------------------------------------------------
+// memory_set_bankptr - set the base of a bank
+//-------------------------------------------------
- profiler_mark_end();
- return result;
+void memory_set_bankptr(running_machine *machine, const char *tag, void *base)
+{
+ // validation checks
+ memory_bank *bank = machine->memory_data->bankmap.find_hash_only(tag);
+ if (bank == NULL)
+ throw emu_fatalerror("memory_set_bankptr called for unknown bank '%s'", tag);
+
+ // set the base
+ bank->set_base(base);
}
-/*-------------------------------------------------
- write_qword_generic - write a qword to an
- arbitrary address space
--------------------------------------------------*/
+//-------------------------------------------------
+// memory_dump - dump the internal memory tables
+// to the given file
+//-------------------------------------------------
-INLINE void write_qword_generic(const address_space *space, offs_t byteaddress, UINT64 data, UINT64 mem_mask)
+void memory_dump(running_machine *machine, FILE *file)
{
- const handler_data *handler;
- offs_t offset;
- UINT32 entry;
+ // skip if we can't open the file
+ if (file == NULL)
+ return;
+
+ // loop over address spaces
+ for (address_space *space = machine->memory_data->spacelist.first(); space != NULL; space = space->next())
+ {
+ fprintf(file, "\n\n"
+ "====================================================\n"
+ "Device '%s' %s address space read handler dump\n"
+ "====================================================\n", space->device().tag(), space->name());
+ space->dump_map(file, ROW_READ);
+
+ fprintf(file, "\n\n"
+ "====================================================\n"
+ "Device '%s' %s address space write handler dump\n"
+ "====================================================\n", space->device().tag(), space->name());
+ space->dump_map(file, ROW_WRITE);
+ }
+}
- profiler_mark_start(PROFILER_MEMWRITE);
- byteaddress &= space->bytemask;
- entry = space->writelookup[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->writelookup[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->write.handlers[entry];
+//-------------------------------------------------
+// generate_memdump - internal memory dump
+//-------------------------------------------------
- offset = (byteaddress - handler->bytestart) & handler->bytemask;
- if (entry < STATIC_RAM)
+static void generate_memdump(running_machine *machine)
+{
+ if (MEM_DUMP)
{
- UINT64 *dest = (UINT64 *)&(*handler->bankbaseptr)[offset & ~7];
- *dest = (*dest & ~mem_mask) | (data & mem_mask);
+ FILE *file = fopen("memdump.log", "w");
+ if (file)
+ {
+ memory_dump(machine, file);
+ fclose(file);
+ }
}
- else
- (*handler->handler.write.shandler64)((const address_space *)handler->object, offset >> 3, data, mem_mask);
+}
+
- profiler_mark_end();
+//-------------------------------------------------
+// bank_reattach - reconnect banks after a load
+//-------------------------------------------------
+
+static STATE_POSTLOAD( bank_reattach )
+{
+ // for each non-anonymous bank, explicitly reset its entry
+ for (memory_bank *bank = machine->memory_data->banklist.first(); bank != NULL; bank = bank->next())
+ if (!bank->anonymous() && bank->entry() != BANK_ENTRY_UNSPECIFIED)
+ bank->set_entry(bank->entry());
}
-/***************************************************************************
- CORE SYSTEM OPERATIONS
-***************************************************************************/
+//**************************************************************************
+// ADDRESS SPACE
+//**************************************************************************
-/*-------------------------------------------------
- memory_init - initialize the memory system
--------------------------------------------------*/
+//-------------------------------------------------
+// address_space - constructor
+//-------------------------------------------------
-void memory_init(running_machine *machine)
+address_space::address_space(device_memory_interface &memory, int spacenum, bool large)
+ : machine(memory.device().machine),
+ cpu(&memory.device()),
+ m_machine(*memory.device().machine),
+ m_next(NULL),
+ m_config(*memory.space_config(spacenum)),
+ m_device(memory.device()),
+ m_map(NULL),
+ m_addrmask(0xffffffffUL >> (32 - m_config.m_addrbus_width)),
+ m_bytemask(address_to_byte_end(m_addrmask)),
+ m_logaddrmask(0xffffffffUL >> (32 - m_config.m_logaddr_width)),
+ m_logbytemask(address_to_byte_end(m_logaddrmask)),
+ m_unmap(0),
+ m_spacenum(spacenum),
+ m_debugger_access(false),
+ m_log_unmap(true),
+ m_direct(*auto_alloc(memory.device().machine, direct_read_data(*this))),
+ m_name(memory.space_config(spacenum)->name()),
+ m_addrchars((m_config.m_databus_width + 3) / 4),
+ m_logaddrchars((m_config.m_logaddr_width + 3) / 4)
{
- memory_private *memdata;
+ // notify the device
+ memory.set_address_space(spacenum, *this);
+}
+
- machine->add_notifier(MACHINE_NOTIFY_EXIT, memory_exit);
+//-------------------------------------------------
+// ~address_space - destructor
+//-------------------------------------------------
- /* allocate our private data */
- memdata = machine->memory_data = auto_alloc_clear(machine, memory_private);
+address_space::~address_space()
+{
+ global_free(&m_direct);
+ global_free(m_map);
+}
- /* build up the list of address spaces */
- memory_init_spaces(machine);
- /* preflight the memory handlers and check banks */
- memory_init_preflight(machine);
+//-------------------------------------------------
+// allocate - static smart allocator of subtypes
+//-------------------------------------------------
- /* then fill in the tables */
- memory_init_populate(machine);
+address_space &address_space::allocate(running_machine &machine, const address_space_config &config, device_memory_interface &memory, int spacenum)
+{
+ // allocate one of the appropriate type
+ bool large = (config.addr2byte_end(0xffffffffUL >> (32 - config.m_addrbus_width)) >= (1 << 18));
- /* allocate any necessary memory */
- memory_init_allocate(machine);
+ switch (config.data_width())
+ {
+ case 8:
+ if (config.endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_8le_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_8le_small(memory, spacenum));
+ }
+ else
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_8be_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_8be_small(memory, spacenum));
+ }
- /* find all the allocated pointers */
- memory_init_locate(machine);
+ case 16:
+ if (config.endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_16le_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_16le_small(memory, spacenum));
+ }
+ else
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_16be_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_16be_small(memory, spacenum));
+ }
- /* dump the final memory configuration */
- mem_dump(machine);
+ case 32:
+ if (config.endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_32le_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_32le_small(memory, spacenum));
+ }
+ else
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_32be_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_32be_small(memory, spacenum));
+ }
- /* we are now initialized */
- memdata->initialized = TRUE;
+ case 64:
+ if (config.endianness() == ENDIANNESS_LITTLE)
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_64le_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_64le_small(memory, spacenum));
+ }
+ else
+ {
+ if (large)
+ return *auto_alloc(&machine, address_space_64be_large(memory, spacenum));
+ else
+ return *auto_alloc(&machine, address_space_64be_small(memory, spacenum));
+ }
+ }
+ throw emu_fatalerror("Invalid width %d specified for address_space::allocate", config.data_width());
}
+//-------------------------------------------------
+// adjust_addresses - adjust addresses for a
+// given address space in a standard fashion
+//-------------------------------------------------
-/***************************************************************************
- DIRECT ACCESS CONTROL
-***************************************************************************/
+inline void address_space::adjust_addresses(offs_t &start, offs_t &end, offs_t &mask, offs_t &mirror)
+{
+ // adjust start/end/mask values
+ if (mask == 0)
+ mask = m_addrmask & ~mirror;
+ else
+ mask &= m_addrmask;
+ start &= ~mirror & m_addrmask;
+ end &= ~mirror & m_addrmask;
+
+ // adjust to byte values
+ start = address_to_byte(start);
+ end = address_to_byte_end(end);
+ mask = address_to_byte_end(mask);
+ mirror = address_to_byte(mirror);
+}
-/*-------------------------------------------------
- memory_set_decrypted_region - registers an
- address range as having a decrypted data
- pointer
--------------------------------------------------*/
-void memory_set_decrypted_region(const address_space *space, offs_t addrstart, offs_t addrend, void *base)
+//-------------------------------------------------
+// prepare_map - allocate the address map and
+// walk through it to find implcit memory regions
+// and identify shared regions
+//-------------------------------------------------
+
+void address_space::prepare_map()
{
- offs_t bytestart = memory_address_to_byte(space, addrstart);
- offs_t byteend = memory_address_to_byte_end(space, addrend);
- int found = FALSE;
- bank_info *bank;
+ const region_info *devregion = (m_spacenum == ADDRESS_SPACE_0) ? m_machine.region(m_device.tag()) : NULL;
+ UINT32 devregionsize = (devregion != NULL) ? devregion->bytes() : 0;
+
+ // allocate the address map
+ m_map = global_alloc(address_map(m_device.baseconfig(), m_spacenum));
- /* loop over banks looking for a match */
- for (bank = space->machine->memory_data->banklist; bank != NULL; bank = bank->next)
+ // extract global parameters specified by the map
+ m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0;
+ if (m_map->m_globalmask != 0)
{
- /* consider this bank if it is used for reading and matches the address space */
- if (bank->read && bank_references_space(bank, space))
+ m_addrmask = m_map->m_globalmask;
+ m_bytemask = address_to_byte_end(m_addrmask);
+ }
+
+ // make a pass over the address map, adjusting for the device and getting memory pointers
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ {
+ // if we have a share entry, add it to our map
+ if (entry->m_share != NULL)
+ m_machine.memory_data->sharemap.add(entry->m_share, UNMAPPED_SHARE_PTR, false);
+
+ // computed adjusted addresses first
+ entry->m_bytestart = entry->m_addrstart;
+ entry->m_byteend = entry->m_addrend;
+ entry->m_bytemirror = entry->m_addrmirror;
+ entry->m_bytemask = entry->m_addrmask;
+ adjust_addresses(entry->m_bytestart, entry->m_byteend, entry->m_bytemask, entry->m_bytemirror);
+
+ // if this is a ROM handler without a specified region, attach it to the implicit region
+ if (m_spacenum == ADDRESS_SPACE_0 && entry->m_read.m_type == AMH_ROM && entry->m_region == NULL)
{
- /* verify that the region fully covers the decrypted range */
- if (bank->bytestart >= bytestart && bank->byteend <= byteend)
+ // make sure it fits within the memory region before doing so, however
+ if (entry->m_byteend < devregionsize)
{
- /* set the decrypted pointer for the corresponding memory bank */
- space->machine->memory_data->bankd_ptr[bank->index] = (UINT8 *)base + bank->bytestart - bytestart;
- found = TRUE;
-
- /* if we are executing from here, force an opcode base update */
- if (space->direct.entry == bank->index)
- force_opbase_update(space);
+ entry->m_region = m_device.tag();
+ entry->m_rgnoffs = entry->m_bytestart;
}
+ }
- /* fatal error if the decrypted region straddles the bank */
- else if (bank->bytestart < byteend && bank->byteend > bytestart)
- fatalerror("memory_set_decrypted_region found straddled region %08X-%08X for device '%s'", bytestart, byteend, space->cpu->tag());
+ // validate adjusted addresses against implicit regions
+ if (entry->m_region != NULL && entry->m_share == NULL && entry->m_baseptr == NULL)
+ {
+ const region_info *region = m_machine.region(entry->m_region);
+ if (region == NULL)
+ fatalerror("Error: device '%s' %s space memory map entry %X-%X references non-existant region \"%s\"", m_device.tag(), m_name, entry->m_addrstart, entry->m_addrend, entry->m_region);
+
+ // validate the region
+ if (entry->m_rgnoffs + (entry->m_byteend - entry->m_bytestart + 1) > region->bytes())
+ fatalerror("Error: device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)", m_device.tag(), m_name, entry->m_addrstart, entry->m_addrend, entry->m_region, region->bytes());
}
+
+ // convert any region-relative entries to their memory pointers
+ if (entry->m_region != NULL)
+ entry->m_memory = m_machine.region(entry->m_region)->base() + entry->m_rgnoffs;
}
- /* fatal error as well if we didn't find any relevant memory banks */
- if (!found)
- fatalerror("memory_set_decrypted_region unable to find matching region %08X-%08X for device '%s'", bytestart, byteend, space->cpu->tag());
+ // now loop over all the handlers and enforce the address mask
+ read().mask_all_handlers(m_bytemask);
+ write().mask_all_handlers(m_bytemask);
}
-/*-------------------------------------------------
- memory_set_direct_update_handler - register a
- handler for opcode base changes on a given
- device
--------------------------------------------------*/
+//-------------------------------------------------
+// populate_from_map - walk the map in reverse
+// order and install the appropriate handler for
+// each case
+//-------------------------------------------------
-direct_update_func memory_set_direct_update_handler(const address_space *space, direct_update_func function)
+void address_space::populate_from_map()
{
- address_space *spacerw = (address_space *)space;
- direct_update_func old = spacerw->directupdate;
- spacerw->directupdate = function;
- return old;
+ // no map, nothing to do
+ if (m_map == NULL)
+ return;
+
+ // install the handlers, using the original, unadjusted memory map
+ const address_map_entry *last_entry = NULL;
+ while (last_entry != m_map->m_entrylist.first())
+ {
+ // find the entry before the last one we processed
+ const address_map_entry *entry;
+ for (entry = m_map->m_entrylist.first(); entry->next() != last_entry; entry = entry->next()) ;
+ last_entry = entry;
+
+ // map both read and write halves
+ populate_map_entry(*entry, ROW_READ);
+ populate_map_entry(*entry, ROW_WRITE);
+ }
}
-/*-------------------------------------------------
- memory_set_direct_region - called by device
- cores to update the opcode base for the given
- address
--------------------------------------------------*/
+//-------------------------------------------------
+// populate_map_entry - map a single read or
+// write entry based on information from an
+// address map entry
+//-------------------------------------------------
-int memory_set_direct_region(const address_space *space, offs_t *byteaddress)
+void address_space::populate_map_entry(const address_map_entry &entry, read_or_write readorwrite)
{
- memory_private *memdata = space->machine->memory_data;
- address_space *spacerw = (address_space *)space;
- UINT8 *base = NULL, *based = NULL;
- const handler_data *handlers;
- direct_range *range;
- offs_t maskedbits;
- offs_t overrideaddress = *byteaddress;
- UINT8 entry;
+ const map_handler_data &data = (readorwrite == ROW_READ) ? entry.m_read : entry.m_write;
+ bindable_object *object;
+ device_t *device;
- /* allow overrides */
- if (spacerw->directupdate != NULL)
+ // based on the handler type, alter the bits, name, funcptr, and object
+ switch (data.m_type)
{
- overrideaddress = (*spacerw->directupdate)(spacerw, overrideaddress, &spacerw->direct);
- if (overrideaddress == ~0)
- return TRUE;
+ case AMH_NONE:
+ return;
- *byteaddress = overrideaddress;
- }
+ case AMH_ROM:
+ // writes to ROM are no-ops
+ if (readorwrite == ROW_WRITE)
+ return;
+ // fall through to the RAM case otherwise
- /* remove the masked bits (we'll put them back later) */
- maskedbits = overrideaddress & ~spacerw->bytemask;
+ case AMH_RAM:
+ install_ram(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, readorwrite);
+ break;
- /* find or allocate a matching range */
- range = direct_range_find(spacerw, overrideaddress, &entry);
+ case AMH_NOP:
+ unmap(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, readorwrite, true);
+ break;
- /* keep track of current entry */
- spacerw->direct.entry = entry;
+ case AMH_UNMAP:
+ unmap(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, readorwrite, false);
+ break;
- /* if we don't map to a bank, return FALSE */
- if (entry < STATIC_BANK1 || entry >= STATIC_RAM)
- {
- /* ensure future updates to land here as well until we get back into a bank */
- spacerw->direct.byteend = 0;
- spacerw->direct.bytestart = 1;
- return FALSE;
- }
+ case AMH_DRIVER_DELEGATE:
+ case AMH_DEVICE_DELEGATE:
+ if (data.m_type == AMH_DRIVER_DELEGATE)
+ {
+ object = m_machine.driver_data<driver_data_t>();
+ if (object == NULL)
+ throw emu_fatalerror("Attempted to map a driver delegate in space %s of device '%s' when there is no driver data\n", m_name, m_device.tag());
+ }
+ else
+ {
+ object = m_machine.device(data.m_tag);
+ if (object == NULL)
+ throw emu_fatalerror("Attempted to map a non-existent device '%s' in space %s of device '%s'\n", data.m_tag, m_name, m_device.tag());
+ }
- /* if no decrypted opcodes, point to the same base */
- base = memdata->bank_ptr[entry];
- based = memdata->bankd_ptr[entry];
- if (based == NULL)
- based = base;
+ if (readorwrite == ROW_READ)
+ switch (data.m_bits)
+ {
+ case 8: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, read8_delegate(entry.m_rproto8, *object), data.m_mask); break;
+ case 16: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, read16_delegate(entry.m_rproto16, *object), data.m_mask); break;
+ case 32: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, read32_delegate(entry.m_rproto32, *object), data.m_mask); break;
+ case 64: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, read64_delegate(entry.m_rproto64, *object), data.m_mask); break;
+ }
+ else
+ switch (data.m_bits)
+ {
+ case 8: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, write8_delegate(entry.m_wproto8, *object), data.m_mask); break;
+ case 16: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, write16_delegate(entry.m_wproto16, *object), data.m_mask); break;
+ case 32: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, write32_delegate(entry.m_wproto32, *object), data.m_mask); break;
+ case 64: install_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, write64_delegate(entry.m_wproto64, *object), data.m_mask); break;
+ }
+ break;
+
+ case AMH_LEGACY_SPACE_HANDLER:
+ if (readorwrite == ROW_READ)
+ switch (data.m_bits)
+ {
+ case 8: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rspace8, data.m_name, data.m_mask); break;
+ case 16: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rspace16, data.m_name, data.m_mask); break;
+ case 32: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rspace32, data.m_name, data.m_mask); break;
+ case 64: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rspace64, data.m_name, data.m_mask); break;
+ }
+ else
+ switch (data.m_bits)
+ {
+ case 8: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wspace8, data.m_name, data.m_mask); break;
+ case 16: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wspace16, data.m_name, data.m_mask); break;
+ case 32: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wspace32, data.m_name, data.m_mask); break;
+ case 64: install_legacy_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wspace64, data.m_name, data.m_mask); break;
+ }
+ break;
+
+ case AMH_LEGACY_DEVICE_HANDLER:
+ device = m_machine.device(data.m_tag);
+ if (device == NULL)
+ fatalerror("Attempted to map a non-existent device '%s' in space %s of device '%s'\n", data.m_tag, m_name, m_device.tag());
+
+ if (readorwrite == ROW_READ)
+ switch (data.m_bits)
+ {
+ case 8: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rdevice8, data.m_name, data.m_mask); break;
+ case 16: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rdevice16, data.m_name, data.m_mask); break;
+ case 32: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rdevice32, data.m_name, data.m_mask); break;
+ case 64: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_rdevice64, data.m_name, data.m_mask); break;
+ }
+ else
+ switch (data.m_bits)
+ {
+ case 8: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wdevice8, data.m_name, data.m_mask); break;
+ case 16: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wdevice16, data.m_name, data.m_mask); break;
+ case 32: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wdevice32, data.m_name, data.m_mask); break;
+ case 64: install_legacy_handler(*device, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_wdevice64, data.m_name, data.m_mask); break;
+ }
+ break;
- /* compute the adjusted base */
- handlers = spacerw->read.handlers[entry];
- spacerw->direct.bytemask = handlers->bytemask;
- spacerw->direct.raw = base - (handlers->bytestart & spacerw->direct.bytemask);
- spacerw->direct.decrypted = based - (handlers->bytestart & spacerw->direct.bytemask);
- spacerw->direct.bytestart = maskedbits | range->bytestart;
- spacerw->direct.byteend = maskedbits | range->byteend;
- return TRUE;
+ case AMH_PORT:
+ install_port(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror,
+ (readorwrite == ROW_READ) ? data.m_tag : NULL,
+ (readorwrite == ROW_WRITE) ? data.m_tag : NULL);
+ break;
+
+ case AMH_BANK:
+ install_bank(entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror,
+ (readorwrite == ROW_READ) ? data.m_tag : NULL,
+ (readorwrite == ROW_WRITE) ? data.m_tag : NULL);
+ break;
+ }
}
-/*-------------------------------------------------
- memory_get_read_ptr - return a pointer the
- memory byte provided in the given address
- space, or NULL if it is not mapped to a bank
--------------------------------------------------*/
+//-------------------------------------------------
+// allocate_memory - determine all neighboring
+// address ranges and allocate memory to back
+// them
+//-------------------------------------------------
-void *memory_get_read_ptr(const address_space *space, offs_t byteaddress)
+void address_space::allocate_memory()
{
- const handler_data *handler;
- offs_t byteoffset;
- UINT8 entry;
+ simple_list<memory_block> &blocklist = m_machine.memory_data->blocklist;
- /* perform the lookup */
- byteaddress &= space->bytemask;
- entry = space->read.table[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->read.table[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->read.handlers[entry];
+ // 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
+ memory_block *prev_memblock_tail = blocklist.last();
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ if (entry->m_memory != NULL)
+ blocklist.append(*auto_alloc(&m_machine, memory_block(*this, entry->m_bytestart, entry->m_byteend, entry->m_memory)));
- /* 8-bit case: RAM/ROM */
- if (entry >= STATIC_RAM)
- return NULL;
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- return &(*handler->bankbaseptr)[byteoffset];
-}
+ // loop over all blocks just allocated and assign pointers from them
+ address_map_entry *unassigned = NULL;
+ memory_block *first_new_block = (prev_memblock_tail != NULL) ? prev_memblock_tail->next() : blocklist.first();
+ for (memory_block *memblock = first_new_block; memblock != NULL; memblock = memblock->next())
+ unassigned = block_assign_intersecting(memblock->bytestart(), memblock->byteend(), memblock->data());
+ // if we don't have an unassigned pointer yet, try to find one
+ if (unassigned == NULL)
+ unassigned = block_assign_intersecting(~0, 0, NULL);
-/*-------------------------------------------------
- memory_get_write_ptr - return a pointer the
- memory byte provided in the given address
- space, or NULL if it is not mapped to a
- writeable bank
--------------------------------------------------*/
+ // loop until we've assigned all memory in this space
+ while (unassigned != NULL)
+ {
+ // work in MEMORY_BLOCK_CHUNK-sized chunks
+ offs_t curblockstart = unassigned->m_bytestart / MEMORY_BLOCK_CHUNK;
+ offs_t curblockend = unassigned->m_byteend / MEMORY_BLOCK_CHUNK;
-void *memory_get_write_ptr(const address_space *space, offs_t byteaddress)
-{
- const handler_data *handler;
- offs_t byteoffset;
- UINT8 entry;
+ // loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_CHUNK chunks
+ bool changed;
+ do
+ {
+ changed = false;
- /* perform the lookup */
- byteaddress &= space->bytemask;
- entry = space->write.table[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = space->write.table[LEVEL2_INDEX(entry, byteaddress)];
- handler = space->write.handlers[entry];
+ // scan for unmapped blocks in the adjusted map
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ if (entry->m_memory == NULL && entry != unassigned && needs_backing_store(entry))
+ {
+ // get block start/end blocks for this block
+ offs_t blockstart = entry->m_bytestart / MEMORY_BLOCK_CHUNK;
+ offs_t blockend = entry->m_byteend / MEMORY_BLOCK_CHUNK;
- /* 8-bit case: RAM/ROM */
- if (entry >= STATIC_RAM)
- return NULL;
- byteoffset = (byteaddress - handler->bytestart) & handler->bytemask;
- return &(*handler->bankbaseptr)[byteoffset];
-}
+ // 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 curbytestart = curblockstart * MEMORY_BLOCK_CHUNK;
+ offs_t curbyteend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1);
+ memory_block &block = blocklist.append(*auto_alloc(&m_machine, memory_block(*this, curbytestart, curbyteend)));
+ // assign memory that intersected the new block
+ unassigned = block_assign_intersecting(curbytestart, curbyteend, block.data());
+ }
+}
-/***************************************************************************
- MEMORY BANKING
-***************************************************************************/
-/*-------------------------------------------------
- memory_configure_bank - configure the
- addresses for a bank
--------------------------------------------------*/
+//-------------------------------------------------
+// locate_memory - find all the requested
+// pointers into the final allocated memory
+//-------------------------------------------------
-void memory_configure_bank(running_machine *machine, const char *tag, int startentry, int numentries, void *base, offs_t stride)
+void address_space::locate_memory()
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank = memdata->bankmap.find_hash_only(tag);
- int entrynum;
-
- /* validation checks */
- if (bank == NULL)
- fatalerror("memory_configure_bank called for unknown bank '%s'", tag);
- if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES)
- fatalerror("memory_configure_bank called with out-of-range entries %d-%d", startentry, startentry + numentries - 1);
- if (!base)
- fatalerror("memory_configure_bank called NULL base");
+ // fill in base/size entries
+ for (const address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ {
+ if (entry->m_baseptr != NULL)
+ *entry->m_baseptr = entry->m_memory;
+ if (entry->m_baseptroffs_plus1 != 0)
+ *(void **)(reinterpret_cast<UINT8 *>(m_machine.driver_data<void>()) + entry->m_baseptroffs_plus1 - 1) = entry->m_memory;
+ if (entry->m_genbaseptroffs_plus1 != 0)
+ *(void **)((UINT8 *)&m_machine.generic + entry->m_genbaseptroffs_plus1 - 1) = entry->m_memory;
+ if (entry->m_sizeptr != NULL)
+ *entry->m_sizeptr = entry->m_byteend - entry->m_bytestart + 1;
+ if (entry->m_sizeptroffs_plus1 != 0)
+ *(size_t *)(reinterpret_cast<UINT8 *>(m_machine.driver_data<void>()) + entry->m_sizeptroffs_plus1 - 1) = entry->m_byteend - entry->m_bytestart + 1;
+ if (entry->m_gensizeptroffs_plus1 != 0)
+ *(size_t *)((UINT8 *)&m_machine.generic + entry->m_gensizeptroffs_plus1 - 1) = entry->m_byteend - entry->m_bytestart + 1;
+ }
- /* fill in the requested bank entries */
- for (entrynum = startentry; entrynum < startentry + numentries; entrynum++)
- bank->entry[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride;
+ // once this is done, find the starting bases for the banks
+ for (memory_bank *bank = m_machine.memory_data->banklist.first(); bank != NULL; bank = bank->next())
+ if (bank->base() == NULL && bank->references_space(*this, ROW_READWRITE))
+ {
+ // set the initial bank pointer
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ if (entry->m_bytestart == bank->bytestart() && entry->m_memory != NULL)
+ {
+ bank->set_base(entry->m_memory);
+ VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank->tag(), entry->m_addrstart, entry->m_addrend, entry->m_memory));
+ break;
+ }
- /* if we have no bankptr yet, set it to the first entry */
- if (memdata->bank_ptr[bank->index] == NULL)
- memdata->bank_ptr[bank->index] = (UINT8 *)bank->entry[0];
+ // if the entry was set ahead of time, override the automatically found pointer
+ if (!bank->anonymous() && bank->entry() != BANK_ENTRY_UNSPECIFIED)
+ bank->set_entry(bank->entry());
+ }
}
-/*-------------------------------------------------
- memory_configure_bank_decrypted - configure
- the decrypted addresses for a bank
--------------------------------------------------*/
+//-------------------------------------------------
+// set_decrypted_region - registers an address
+// range as having a decrypted data pointer
+//-------------------------------------------------
-void memory_configure_bank_decrypted(running_machine *machine, const char *tag, int startentry, int numentries, void *base, offs_t stride)
+void address_space::set_decrypted_region(offs_t addrstart, offs_t addrend, void *base)
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank = memdata->bankmap.find_hash_only(tag);
- int entrynum;
+ offs_t bytestart = address_to_byte(addrstart);
+ offs_t byteend = address_to_byte_end(addrend);
+ bool found = false;
- /* validation checks */
- if (bank == NULL)
- fatalerror("memory_configure_bank_decrypted called for unknown bank '%s'", tag);
- if (startentry < 0 || startentry + numentries > MAX_BANK_ENTRIES)
- fatalerror("memory_configure_bank_decrypted called with out-of-range entries %d-%d", startentry, startentry + numentries - 1);
- if (!base)
- fatalerror("memory_configure_bank_decrypted called NULL base");
+ // loop over banks looking for a match
+ for (memory_bank *bank = m_machine.memory_data->banklist.first(); bank != NULL; bank = bank->next())
+ {
+ // consider this bank if it is used for reading and matches the address space
+ if (bank->references_space(*this, ROW_READ))
+ {
+ // verify that the region fully covers the decrypted range
+ if (bank->fully_covers(bytestart, byteend))
+ {
+ // set the decrypted pointer for the corresponding memory bank
+ bank->set_base_decrypted(reinterpret_cast<UINT8 *>(base) + bank->bytestart() - bytestart);
+ found = true;
+ }
- /* fill in the requested bank entries */
- for (entrynum = startentry; entrynum < startentry + numentries; entrynum++)
- bank->entryd[entrynum] = (UINT8 *)base + (entrynum - startentry) * stride;
+ // fatal error if the decrypted region straddles the bank
+ else if (bank->partially_covers(bytestart, byteend))
+ throw emu_fatalerror("memory_set_decrypted_region found straddled region %08X-%08X for device '%s'", bytestart, byteend, m_device.tag());
+ }
+ }
- /* if we have no bankptr yet, set it to the first entry */
- if (memdata->bankd_ptr[bank->index] == NULL)
- memdata->bankd_ptr[bank->index] = (UINT8 *)bank->entryd[0];
+ // fatal error as well if we didn't find any relevant memory banks
+ if (!found)
+ throw emu_fatalerror("memory_set_decrypted_region unable to find matching region %08X-%08X for device '%s'", bytestart, byteend, m_device.tag());
}
-/*-------------------------------------------------
- memory_set_bank - select one pre-configured
- entry to be the new bank base
--------------------------------------------------*/
+//-------------------------------------------------
+// block_assign_intersecting - find all
+// intersecting blocks and assign their pointers
+//-------------------------------------------------
-void memory_set_bank(running_machine *machine, const char *tag, int entrynum)
+address_map_entry *address_space::block_assign_intersecting(offs_t bytestart, offs_t byteend, UINT8 *base)
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank = memdata->bankmap.find_hash_only(tag);
- bank_reference *ref;
+ memory_private *memdata = m_machine.memory_data;
+ address_map_entry *unassigned = NULL;
- /* validation checks */
- if (bank == NULL)
- fatalerror("memory_set_bank called for unknown bank '%s'", tag);
- if (entrynum < 0 || entrynum > MAX_BANK_ENTRIES)
- fatalerror("memory_set_bank called with out-of-range entry %d", entrynum);
- if (!bank->entry[entrynum])
- fatalerror("memory_set_bank called for bank '%s' with invalid bank entry %d", tag, entrynum);
+ // loop over the adjusted map and assign memory to any blocks we can
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
+ {
+ // if we haven't assigned this block yet, see if we have a mapped shared pointer for it
+ if (entry->m_memory == NULL && entry->m_share != NULL)
+ {
+ void *shareptr = memdata->sharemap.find(entry->m_share);
+ if (shareptr != UNMAPPED_SHARE_PTR)
+ {
+ entry->m_memory = shareptr;
+ VPRINTF(("memory range %08X-%08X -> shared_ptr '%s' [%p]\n", entry->m_addrstart, entry->m_addrend, entry->m_share, entry->m_memory));
+ }
+ }
+
+ // otherwise, look for a match in this block
+ if (entry->m_memory == NULL && entry->m_bytestart >= bytestart && entry->m_byteend <= byteend)
+ {
+ entry->m_memory = base + (entry->m_bytestart - bytestart);
+ VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry->m_addrstart, entry->m_addrend, bytestart, byteend, entry->m_memory));
+ }
+
+ // if we're the first match on a shared pointer, assign it now
+ if (entry->m_memory != NULL && entry->m_share != NULL)
+ {
+ void *shareptr = memdata->sharemap.find(entry->m_share);
+ if (shareptr == UNMAPPED_SHARE_PTR)
+ memdata->sharemap.add(entry->m_share, entry->m_memory, TRUE);
+ }
- /* set the base */
- bank->curentry = entrynum;
- memdata->bank_ptr[bank->index] = (UINT8 *)bank->entry[entrynum];
- memdata->bankd_ptr[bank->index] = (UINT8 *)bank->entryd[entrynum];
+ // keep track of the first unassigned entry
+ if (entry->m_memory == NULL && unassigned == NULL && needs_backing_store(entry))
+ unassigned = entry;
+ }
- /* invalidate all the direct references to any referenced address spaces */
- for (ref = bank->reflist; ref != NULL; ref = ref->next)
- force_opbase_update(ref->space);
+ return unassigned;
}
-/*-------------------------------------------------
- memory_get_bank - return the currently
- selected bank
--------------------------------------------------*/
+//-------------------------------------------------
+// get_handler_string - return a string
+// describing the handler at a particular offset
+//-------------------------------------------------
-int memory_get_bank(running_machine *machine, const char *tag)
+const char *address_space::get_handler_string(read_or_write readorwrite, offs_t byteaddress)
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank = memdata->bankmap.find_hash_only(tag);
-
- /* validation checks */
- if (bank == NULL)
- fatalerror("memory_get_bank called for unknown bank '%s'", tag);
- return bank->curentry;
+ if (readorwrite == ROW_READ)
+ return read().handler_name(read().lookup(byteaddress));
+ else
+ return write().handler_name(write().lookup(byteaddress));
}
-/*-------------------------------------------------
- memory_set_bankptr - set the base of a bank
--------------------------------------------------*/
+//-------------------------------------------------
+// dump_map - dump the contents of a single
+// address space
+//-------------------------------------------------
-void memory_set_bankptr(running_machine *machine, const char *tag, void *base)
+void address_space::dump_map(FILE *file, read_or_write readorwrite)
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank = memdata->bankmap.find_hash_only(tag);
- bank_reference *ref;
-
- /* validation checks */
- if (bank == NULL)
- fatalerror("memory_set_bankptr called for unknown bank '%s'", tag);
- if (base == NULL)
- fatalerror("memory_set_bankptr called NULL base");
-// if (ALLOW_ONLY_AUTO_MALLOC_BANKS)
-// validate_auto_malloc_memory(base, bank->byteend - bank->bytestart + 1);
+ const address_table &table = (readorwrite == ROW_READ) ? static_cast<address_table &>(read()) : static_cast<address_table &>(write());
- /* set the base */
- memdata->bank_ptr[bank->index] = (UINT8 *)base;
+ // dump generic information
+ fprintf(file, " Address bits = %d\n", m_config.m_addrbus_width);
+ fprintf(file, " Data bits = %d\n", m_config.m_databus_width);
+ fprintf(file, " Address mask = %X\n", m_bytemask);
+ fprintf(file, "\n");
- /* invalidate all the direct references to any referenced address spaces */
- for (ref = bank->reflist; ref != NULL; ref = ref->next)
- force_opbase_update(ref->space);
+ // iterate over addresses
+ offs_t bytestart, byteend;
+ for (offs_t byteaddress = 0; byteaddress <= m_bytemask; byteaddress = byteend)
+ {
+ UINT8 entry = table.derive_range(byteaddress, bytestart, byteend);
+ fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
+ bytestart, byteend, entry, table.handler_name(entry), table.handler(entry).bytestart());
+ if (++byteend == 0)
+ break;
+ }
}
+//**************************************************************************
+// DYNAMIC ADDRESS SPACE MAPPING
+//**************************************************************************
-/***************************************************************************
- DYNAMIC ADDRESS SPACE MAPPING
-***************************************************************************/
-
-/*-------------------------------------------------
- _memory_install_handler - install a new memory
- handler into the given address space,
- returning a pointer to the memory backing it,
- if present
--------------------------------------------------*/
-
-#ifdef UNUSED_CODE
-void *_memory_install_handler(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, FPTR rhandler, FPTR whandler)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler >= STATIC_COUNT)
- fatalerror("Attempted to install non-static read handler via memory_install_handler() in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler >= STATIC_COUNT)
- fatalerror("Attempted to install non-static write handler via memory_install_handler() in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != 0)
- space_map_range(spacerw, ROW_READ, spacerw->dbits, 0, addrstart, addrend, addrmask, addrmirror, (genf *)(FPTR)rhandler, spacerw, NULL);
- if (whandler != 0)
- space_map_range(spacerw, ROW_WRITE, spacerw->dbits, 0, addrstart, addrend, addrmask, addrmirror, (genf *)(FPTR)whandler, spacerw, NULL);
- mem_dump(space->machine);
- return space_find_backing_memory(spacerw, addrstart, addrend);
-}
-#endif
-
-
-/*-------------------------------------------------
- _memory_install_handler8 - same as above but
- explicitly for 8-bit handlers
--------------------------------------------------*/
-
-UINT8 *_memory_install_handler8(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_space_func rhandler, const char *rhandler_name, write8_space_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 8, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, spacerw, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 8, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, spacerw, whandler_name);
- mem_dump(space->machine);
- return (UINT8 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_handler16 - same as above but
- explicitly for 16-bit handlers
--------------------------------------------------*/
-
-UINT16 *_memory_install_handler16(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_space_func rhandler, const char *rhandler_name, write16_space_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 16, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, spacerw, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 16, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, spacerw, whandler_name);
- mem_dump(space->machine);
- return (UINT16 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_handler32 - same as above but
- explicitly for 32-bit handlers
--------------------------------------------------*/
-
-UINT32 *_memory_install_handler32(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_space_func rhandler, const char *rhandler_name, write32_space_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 32, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, spacerw, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 32, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, spacerw, whandler_name);
- mem_dump(space->machine);
- return (UINT32 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_handler64 - same as above but
- explicitly for 64-bit handlers
--------------------------------------------------*/
-
-UINT64 *_memory_install_handler64(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_space_func rhandler, const char *rhandler_name, write64_space_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler in space %s of device '%s'\n", space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 64, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, spacerw, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 64, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, spacerw, whandler_name);
- mem_dump(space->machine);
- return (UINT64 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_device_handler8 - same as above
- but explicitly for 8-bit handlers
--------------------------------------------------*/
-
-UINT8 *_memory_install_device_handler8(const address_space *space, device_t *device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_device_func rhandler, const char *rhandler_name, write8_device_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 8, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, (void *)device, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 8, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, (void *)device, whandler_name);
- mem_dump(space->machine);
- return (UINT8 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_device_handler16 - same as
- above but explicitly for 16-bit handlers
--------------------------------------------------*/
-
-UINT16 *_memory_install_device_handler16(const address_space *space, device_t *device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_device_func rhandler, const char *rhandler_name, write16_device_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 16, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, (void *)device, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 16, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, (void *)device, whandler_name);
- mem_dump(space->machine);
- return (UINT16 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
-
-/*-------------------------------------------------
- _memory_install_device_handler32 - same as
- above but explicitly for 32-bit handlers
--------------------------------------------------*/
-
-UINT32 *_memory_install_device_handler32(const address_space *space, device_t *device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_device_func rhandler, const char *rhandler_name, write32_device_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 32, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, (void *)device, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 32, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, (void *)device, whandler_name);
- mem_dump(space->machine);
- return (UINT32 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
-
+//-------------------------------------------------
+// unmap - unmap a section of address space
+//-------------------------------------------------
-/*-------------------------------------------------
- _memory_install_device_handler64 - same as
- above but explicitly for 64-bit handlers
--------------------------------------------------*/
-
-UINT64 *_memory_install_device_handler64(const address_space *space, device_t *device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_device_func rhandler, const char *rhandler_name, write64_device_func whandler, const char *whandler_name, int handlerunitmask)
-{
- address_space *spacerw = (address_space *)space;
- if (rhandler != NULL && (FPTR)rhandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid read handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (whandler != NULL && (FPTR)whandler < STATIC_COUNT)
- fatalerror("Attempted to install invalid write handler for device '%s' in space %s of device '%s'\n", device->tag(), space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- if (rhandler != NULL)
- space_map_range(spacerw, ROW_READ, 64, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)rhandler, (void *)device, rhandler_name);
- if (whandler != NULL)
- space_map_range(spacerw, ROW_WRITE, 64, handlerunitmask, addrstart, addrend, addrmask, addrmirror, (genf *)whandler, (void *)device, whandler_name);
- mem_dump(space->machine);
- return (UINT64 *)space_find_backing_memory(spacerw, addrstart, addrend);
-}
+void address_space::unmap(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, bool quiet)
+{
+ // read space
+ if (readorwrite == ROW_READ || readorwrite == ROW_READWRITE)
+ read().map_range(addrstart, addrend, addrmask, addrmirror, quiet ? STATIC_NOP : STATIC_UNMAP);
+ // write space
+ if (readorwrite == ROW_WRITE || readorwrite == ROW_READWRITE)
+ write().map_range(addrstart, addrend, addrmask, addrmirror, quiet ? STATIC_NOP : STATIC_UNMAP);
+}
-/*-------------------------------------------------
- _memory_install_port - install a
- new port handler into the given address space
--------------------------------------------------*/
-
-void _memory_install_port(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag)
-{
- address_space *spacerw = (address_space *)space;
- genf *rhandler = NULL;
- genf *whandler = NULL;
- /* pick the appropriate read/write handlers */
- switch (space->dbits)
- {
- case 8: rhandler = (genf *)input_port_read8; whandler = (genf *)input_port_write8; break;
- case 16: rhandler = (genf *)input_port_read16; whandler = (genf *)input_port_write16; break;
- case 32: rhandler = (genf *)input_port_read32; whandler = (genf *)input_port_write32; break;
- case 64: rhandler = (genf *)input_port_read64; whandler = (genf *)input_port_write64; break;
- }
+//-------------------------------------------------
+// install_port - install a new I/O port handler
+// into this address space
+//-------------------------------------------------
- /* assign the read handler */
+void address_space::install_port(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag)
+{
+ // read handler
if (rtag != NULL)
{
- const input_port_config *port = space->machine->port(rtag);
+ // find the port
+ const input_port_config *port = m_machine.port(rtag);
if (port == NULL)
- fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- space_map_range(spacerw, ROW_READ, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, rhandler, (void *)port, rtag);
+ throw emu_fatalerror("Attempted to map non-existent port '%s' for read in space %s of device '%s'\n", rtag, m_name, m_device.tag());
+
+ // map the range and set the ioport
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_ioport(*port);
}
- /* assign the write handler */
if (wtag != NULL)
{
- const input_port_config *port = space->machine->port(wtag);
+ // find the port
+ const input_port_config *port = m_machine.port(wtag);
if (port == NULL)
- fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- space_map_range(spacerw, ROW_WRITE, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, whandler, (void *)port, wtag);
+ fatalerror("Attempted to map non-existent port '%s' for write in space %s of device '%s'\n", wtag, m_name, m_device.tag());
+
+ // map the range and set the ioport
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_ioport(*port);
}
- /* update the memory dump */
- mem_dump(space->machine);
+ // update the memory dump
+ generate_memdump(&m_machine);
}
-/*-------------------------------------------------
- _memory_install_bank - install a
- new port handler into the given address space
--------------------------------------------------*/
+//-------------------------------------------------
+// install_bank - install a range as mapping to
+// a particular bank
+//-------------------------------------------------
-void _memory_install_bank(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag)
+void address_space::install_bank(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag)
{
- address_space *spacerw = (address_space *)space;
-
- /* map the read bank */
+ // map the read bank
if (rtag != NULL)
{
- genf *handler = bank_find_or_allocate(space, rtag, addrstart, addrend, addrmask, addrmirror, ROW_READ);
- space_map_range(spacerw, ROW_READ, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, handler, spacerw, rtag);
+ memory_bank &bank = bank_find_or_allocate(rtag, addrstart, addrend, addrmask, addrmirror, ROW_READ);
+ read().map_range(addrstart, addrend, addrmask, addrmirror, bank.index());
}
- /* map the write bank */
+ // map the write bank
if (wtag != NULL)
{
- genf *handler = bank_find_or_allocate(space, wtag, addrstart, addrend, addrmask, addrmirror, ROW_WRITE);
- space_map_range(spacerw, ROW_WRITE, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, handler, spacerw, wtag);
+ memory_bank &bank = bank_find_or_allocate(wtag, addrstart, addrend, addrmask, addrmirror, ROW_WRITE);
+ write().map_range(addrstart, addrend, addrmask, addrmirror, bank.index());
}
- /* update the memory dump */
- mem_dump(space->machine);
+ // update the memory dump
+ generate_memdump(&m_machine);
}
-/*-------------------------------------------------
- _memory_install_ram - install a simple fixed
- RAM region into the given address space
--------------------------------------------------*/
+//-------------------------------------------------
+// install_ram - install a simple fixed RAM
+// region into the given address space
+//-------------------------------------------------
-void *_memory_install_ram(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, UINT8 install_read, UINT8 install_write, void *baseptr)
+void *address_space::install_ram(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, void *baseptr)
{
- memory_private *memdata = space->machine->memory_data;
- address_space *spacerw = (address_space *)space;
- FPTR bankindex;
- genf *handler;
+ memory_private *memdata = m_machine.memory_data;
- /* map for read */
- if (install_read)
+ // map for read
+ if (readorwrite == ROW_READ || readorwrite == ROW_READWRITE)
{
- handler = bank_find_or_allocate(space, NULL, addrstart, addrend, addrmask, addrmirror, ROW_READ);
- space_map_range(spacerw, ROW_READ, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, handler, spacerw, "ram");
+ // find a bank and map it
+ memory_bank &bank = bank_find_or_allocate(NULL, addrstart, addrend, addrmask, addrmirror, ROW_READ);
+ read().map_range(addrstart, addrend, addrmask, addrmirror, bank.index());
- /* if we are provided a pointer, set it */
- bankindex = (FPTR)handler;
+ // if we are provided a pointer, set it
if (baseptr != NULL)
- memdata->bank_ptr[bankindex] = (UINT8 *)baseptr;
+ bank.set_base(baseptr);
- /* if we don't have a bank pointer yet, try to find one */
- if (memdata->bank_ptr[bankindex] == NULL)
- memdata->bank_ptr[bankindex] = (UINT8 *)space_find_backing_memory(space, addrstart, addrend);
+ // if we don't have a bank pointer yet, try to find one
+ if (bank.base() == NULL)
+ {
+ void *backing = find_backing_memory(addrstart, addrend);
+ if (backing != NULL)
+ bank.set_base(backing);
+ }
- /* if we still don't have a pointer, and we're past the initialization phase, allocate a new block */
- if (memdata->bank_ptr[bankindex] == NULL && memdata->initialized)
+ // if we still don't have a pointer, and we're past the initialization phase, allocate a new block
+ if (bank.base() == NULL && memdata->initialized)
{
- if (space->machine->phase() >= MACHINE_PHASE_RESET)
+ if (m_machine.phase() >= MACHINE_PHASE_RESET)
fatalerror("Attempted to call memory_install_ram() after initialization time without a baseptr!");
- memdata->bank_ptr[bankindex] = (UINT8 *)block_allocate(space, memory_address_to_byte(space, addrstart), memory_address_to_byte_end(space, addrend), NULL);
+ memory_block &block = memdata->blocklist.append(*auto_alloc(&m_machine, memory_block(*this, address_to_byte(addrstart), address_to_byte_end(addrend))));
+ bank.set_base(block.data());
}
}
- /* map for write */
- if (install_write)
+ // map for write
+ if (readorwrite == ROW_WRITE || readorwrite == ROW_READWRITE)
{
- handler = bank_find_or_allocate(space, NULL, addrstart, addrend, addrmask, addrmirror, ROW_WRITE);
- space_map_range(spacerw, ROW_WRITE, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, handler, spacerw, "ram");
+ // find a bank and map it
+ memory_bank &bank = bank_find_or_allocate(NULL, addrstart, addrend, addrmask, addrmirror, ROW_WRITE);
+ write().map_range(addrstart, addrend, addrmask, addrmirror, bank.index());
- /* if we are provided a pointer, set it */
- bankindex = (FPTR)handler;
+ // if we are provided a pointer, set it
if (baseptr != NULL)
- memdata->bank_ptr[bankindex] = (UINT8 *)baseptr;
+ bank.set_base(baseptr);
- /* if we don't have a bank pointer yet, try to find one */
- if (memdata->bank_ptr[bankindex] == NULL)
- memdata->bank_ptr[bankindex] = (UINT8 *)space_find_backing_memory(space, addrstart, addrend);
+ // if we don't have a bank pointer yet, try to find one
+ if (bank.base() == NULL)
+ {
+ void *backing = find_backing_memory(addrstart, addrend);
+ if (backing != NULL)
+ bank.set_base(backing);
+ }
- /* if we still don't have a pointer, and we're past the initialization phase, allocate a new block */
- if (memdata->bank_ptr[bankindex] == NULL && memdata->initialized)
+ // if we still don't have a pointer, and we're past the initialization phase, allocate a new block
+ if (bank.base() == NULL && memdata->initialized)
{
- if (space->machine->phase() >= MACHINE_PHASE_RESET)
+ if (m_machine.phase() >= MACHINE_PHASE_RESET)
fatalerror("Attempted to call memory_install_ram() after initialization time without a baseptr!");
- memdata->bank_ptr[bankindex] = (UINT8 *)block_allocate(space, memory_address_to_byte(space, addrstart), memory_address_to_byte_end(space, addrend), NULL);
+ memory_block &block = memdata->blocklist.append(*auto_alloc(&m_machine, memory_block(*this, address_to_byte(addrstart), address_to_byte_end(addrend))));
+ bank.set_base(block.data());
}
}
- return (void *)space_find_backing_memory(spacerw, addrstart, addrend);
+ return (void *)find_backing_memory(addrstart, addrend);
}
-/*-------------------------------------------------
- _memory_unmap - unmap a section of address
- space
--------------------------------------------------*/
+//-------------------------------------------------
+// install_handler - install 8-bit read/write
+// delegate handlers for the space
+//-------------------------------------------------
-void _memory_unmap(const address_space *space, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, UINT8 unmap_read, UINT8 unmap_write, UINT8 quiet)
+UINT8 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_delegate handler, UINT64 unitmask)
{
- address_space *spacerw = (address_space *)space;
-
- if (unmap_read)
- space_map_range(spacerw, ROW_READ, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, (genf *)(FPTR)(quiet ? STATIC_NOP : STATIC_UNMAP), spacerw, "unmapped");
- if (unmap_write)
- space_map_range(spacerw, ROW_WRITE, space->dbits, 0, addrstart, addrend, addrmask, addrmirror, (genf *)(FPTR)(quiet ? STATIC_NOP : STATIC_UNMAP), spacerw, "unmapped");
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-
-/***************************************************************************
- DEBUGGER HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- memory_get_handler_string - return a string
- describing the handler at a particular offset
--------------------------------------------------*/
-
-const char *memory_get_handler_string(const address_space *space, int read0_or_write1, offs_t byteaddress)
+UINT8 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write8_delegate handler, UINT64 unitmask)
{
- const address_table *table = read0_or_write1 ? &space->write : &space->read;
- UINT8 entry;
-
- /* perform the lookup */
- byteaddress &= space->bytemask;
- entry = table->table[LEVEL1_INDEX(byteaddress)];
- if (entry >= SUBTABLE_BASE)
- entry = table->table[LEVEL2_INDEX(entry, byteaddress)];
-
- /* 8-bit case: RAM/ROM */
- return handler_to_string(space, table, entry);
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_enable_read_watchpoints - enable/disable
- read watchpoint tracking for a given address
- space
--------------------------------------------------*/
-
-void memory_enable_read_watchpoints(const address_space *space, int enable)
+UINT8 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_delegate rhandler, write8_delegate whandler, UINT64 unitmask)
{
- address_space *spacerw = (address_space *)space;
- if (enable)
- spacerw->readlookup = space->machine->memory_data->wptable;
- else
- spacerw->readlookup = spacerw->read.table;
+ install_handler(addrstart, addrend, addrmask, addrmirror, rhandler, unitmask);
+ return install_handler(addrstart, addrend, addrmask, addrmirror, whandler, unitmask);
}
-/*-------------------------------------------------
- memory_enable_write_watchpoints - enable/disable
- write watchpoint tracking for a given address
- space
--------------------------------------------------*/
+//-------------------------------------------------
+// install_legacy_handler - install 8-bit read/
+// write legacy address space handlers for the
+// space
+//-------------------------------------------------
-void memory_enable_write_watchpoints(const address_space *space, int enable)
+UINT8 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_space_func rhandler, const char *rname, UINT64 unitmask)
{
- address_space *spacerw = (address_space *)space;
- if (enable)
- spacerw->writelookup = space->machine->memory_data->wptable;
- else
- spacerw->writelookup = spacerw->write.table;
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(*this, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_set_debugger_access - control whether
- subsequent accesses are treated as coming from
- the debugger
--------------------------------------------------*/
-
-void memory_set_debugger_access(const address_space *space, int debugger)
+UINT8 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write8_space_func whandler, const char *wname, UINT64 unitmask)
{
- address_space *spacerw = (address_space *)space;
- spacerw->debugger_access = debugger;
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(*this, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_set_log_unmap - sets whether unmapped
- memory accesses should be logged or not
--------------------------------------------------*/
-
-void memory_set_log_unmap(const address_space *space, int log)
+UINT8 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_space_func rhandler, const char *rname, write8_space_func whandler, const char *wname, UINT64 unitmask)
{
- address_space *spacerw = (address_space *)space;
- spacerw->log_unmap = log;
+ install_legacy_handler(addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
}
-/*-------------------------------------------------
- memory_get_log_unmap - gets whether unmapped
- memory accesses should be logged or not
--------------------------------------------------*/
+//-------------------------------------------------
+// install_legacy_handler - install 8-bit read/
+// write legacy device handlers for the space
+//-------------------------------------------------
-int memory_get_log_unmap(const address_space *space)
+UINT8 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_device_func rhandler, const char *rname, UINT64 unitmask)
{
- return space->log_unmap;
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(device, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_dump - dump the internal memory tables
- to the given file
--------------------------------------------------*/
-
-void memory_dump(running_machine *machine, FILE *file)
+UINT8 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write8_device_func whandler, const char *wname, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- const address_space *space;
-
- /* skip if we can't open the file */
- if (!file)
- return;
-
- /* loop over valid address spaces */
- for (space = memdata->spacelist; space != NULL; space = space->next)
- {
- fprintf(file, "\n\n"
- "====================================================\n"
- "Device '%s' %s address space read handler dump\n"
- "====================================================\n", space->cpu->tag(), space->name);
- dump_map(file, space, &space->read);
-
- fprintf(file, "\n\n"
- "====================================================\n"
- "Device '%s' %s address space write handler dump\n"
- "====================================================\n", space->cpu->tag(), space->name);
- dump_map(file, space, &space->write);
- }
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(device, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT8 *>(find_backing_memory(addrstart, addrend));
}
-
-
-/***************************************************************************
- INTERNAL INITIALIZATION
-***************************************************************************/
-
-/*-------------------------------------------------
- memory_init_spaces - create the address
- spaces
--------------------------------------------------*/
-
-static void memory_init_spaces(running_machine *machine)
+UINT8 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read8_device_func rhandler, const char *rname, write8_device_func whandler, const char *wname, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- address_space **nextptr = (address_space **)&memdata->spacelist;
- int spacenum;
-
- /* create a global watchpoint-filled table */
- memdata->wptable = auto_alloc_array(machine, UINT8, 1 << LEVEL1_BITS);
- memset(memdata->wptable, STATIC_WATCHPOINT, 1 << LEVEL1_BITS);
-
- /* loop over devices */
- device_memory_interface *memory = NULL;
- for (bool gotone = machine->m_devicelist.first(memory); gotone; gotone = memory->next(memory))
- for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
- {
- const address_space_config *spaceconfig = memory->space_config(spacenum);
- if (spaceconfig != NULL)
- {
- address_space *space = auto_alloc_clear(machine, address_space);
- int ashift = spaceconfig->m_addrbus_shift;
- int abits = spaceconfig->m_addrbus_width;
- int dbits = spaceconfig->m_databus_width;
- int logbits = spaceconfig->m_logaddr_width;
- endianness_t endianness = spaceconfig->m_endianness;
- int accessorindex = (dbits == 8) ? 0 : (dbits == 16) ? 1 : (dbits == 32) ? 2 : 3;
- int entrynum;
-
- /* if logbits is 0, revert to abits */
- if (logbits == 0)
- logbits = abits;
-
- /* determine the address and data bits */
- space->machine = machine;
- space->cpu = &memory->device();
- space->name = spaceconfig->m_name;
- space->accessors = memory_accessors[accessorindex][(endianness == ENDIANNESS_LITTLE) ? 0 : 1];
- space->addrmask = 0xffffffffUL >> (32 - abits);
- space->bytemask = (ashift < 0) ? ((space->addrmask << -ashift) | ((1 << -ashift) - 1)) : (space->addrmask >> ashift);
- space->logaddrmask = 0xffffffffUL >> (32 - logbits);
- space->logbytemask = (ashift < 0) ? ((space->logaddrmask << -ashift) | ((1 << -ashift) - 1)) : (space->logaddrmask >> ashift);
- space->spacenum = spacenum;
- space->endianness = endianness;
- space->ashift = ashift;
- space->abits = abits;
- space->dbits = dbits;
- space->addrchars = (abits + 3) / 4;
- space->logaddrchars = (logbits + 3) / 4;
- space->log_unmap = TRUE;
-
- /* allocate subtable information; we malloc this manually because it will be realloc'ed */
- space->read.subtable = auto_alloc_array_clear(machine, subtable_data, SUBTABLE_COUNT);
- space->write.subtable = auto_alloc_array_clear(machine, subtable_data, SUBTABLE_COUNT);
-
- /* allocate the handler table */
- space->read.handlers[0] = auto_alloc_array_clear(machine, handler_data, ARRAY_LENGTH(space->read.handlers));
- space->write.handlers[0] = auto_alloc_array_clear(machine, handler_data, ARRAY_LENGTH(space->write.handlers));
- for (entrynum = 1; entrynum < ARRAY_LENGTH(space->read.handlers); entrynum++)
- {
- space->read.handlers[entrynum] = space->read.handlers[0] + entrynum;
- space->write.handlers[entrynum] = space->write.handlers[0] + entrynum;
- }
-
- /* init the static handlers */
- for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++)
- {
- space->read.handlers[entrynum]->handler.generic = get_static_handler(space->dbits, 0, entrynum);
- space->read.handlers[entrynum]->object = space;
- space->write.handlers[entrynum]->handler.generic = get_static_handler(space->dbits, 1, entrynum);
- space->write.handlers[entrynum]->object = space;
- }
-
- /* make sure we fix up the mask for the unmap and watchpoint handlers */
- space->read.handlers[STATIC_UNMAP]->bytemask = ~0;
- space->write.handlers[STATIC_UNMAP]->bytemask = ~0;
- space->read.handlers[STATIC_WATCHPOINT]->bytemask = ~0;
- space->write.handlers[STATIC_WATCHPOINT]->bytemask = ~0;
-
- /* allocate memory */
- space->read.machine = machine;
- space->read.table = auto_alloc_array(machine, UINT8, 1 << LEVEL1_BITS);
- space->write.machine = machine;
- space->write.table = auto_alloc_array(machine, UINT8, 1 << LEVEL1_BITS);
-
- /* initialize everything to unmapped */
- memset(space->read.table, STATIC_UNMAP, 1 << LEVEL1_BITS);
- memset(space->write.table, STATIC_UNMAP, 1 << LEVEL1_BITS);
-
- /* initialize the lookups */
- space->readlookup = space->read.table;
- space->writelookup = space->write.table;
-
- /* set the direct access information base */
- space->direct.raw = space->direct.decrypted = NULL;
- space->direct.bytemask = space->bytemask;
- space->direct.bytestart = 1;
- space->direct.byteend = 0;
- space->direct.entry = STATIC_UNMAP;
- space->directupdate = NULL;
-
- /* link us in */
- *nextptr = space;
- nextptr = (address_space **)&space->next;
-
- /* notify the device */
- memory->set_address_space(spacenum, space);
- }
- }
+ install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
}
-/*-------------------------------------------------
- memory_init_preflight - verify the memory structs
- and track which banks are referenced
--------------------------------------------------*/
+//-------------------------------------------------
+// install_handler - install 16-bit read/write
+// delegate handlers for the space
+//-------------------------------------------------
-static void memory_init_preflight(running_machine *machine)
+UINT16 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_delegate handler, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- address_space *space;
-
- /* reset the banking state */
- memdata->banknext = STATIC_BANK1;
-
- /* loop over valid address spaces */
- for (space = (address_space *)memdata->spacelist; space != NULL; space = (address_space *)space->next)
- {
- const region_info *devregion = (space->spacenum == ADDRESS_SPACE_0) ? space->machine->region(space->cpu->tag()) : NULL;
- int devregionsize = (devregion != NULL) ? devregion->bytes() : 0;
- address_map_entry *entry;
- int entrynum;
-
- /* allocate the address map */
- space->map = global_alloc(address_map(space->cpu->baseconfig(), space->spacenum));
-
- /* extract global parameters specified by the map */
- space->unmap = (space->map->m_unmapval == 0) ? 0 : ~0;
- if (space->map->m_globalmask != 0)
- {
- space->addrmask = space->map->m_globalmask;
- space->bytemask = memory_address_to_byte_end(space, space->addrmask);
- }
-
- /* make a pass over the address map, adjusting for the device and getting memory pointers */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- {
- /* if we have a share entry, add it to our map */
- if (entry->m_share != NULL)
- memdata->sharemap.add(entry->m_share, UNMAPPED_SHARE_PTR, FALSE);
-
- /* computed adjusted addresses first */
- entry->m_bytestart = entry->m_addrstart;
- entry->m_byteend = entry->m_addrend;
- entry->m_bytemirror = entry->m_addrmirror;
- entry->m_bytemask = entry->m_addrmask;
- adjust_addresses(space, &entry->m_bytestart, &entry->m_byteend, &entry->m_bytemask, &entry->m_bytemirror);
-
- /* if this is a ROM handler without a specified region, attach it to the implicit region */
- if (space->spacenum == ADDRESS_SPACE_0 && entry->m_read.type == AMH_ROM && entry->m_region == NULL)
- {
- /* make sure it fits within the memory region before doing so, however */
- if (entry->m_byteend < devregionsize)
- {
- entry->m_region = space->cpu->tag();
- entry->m_rgnoffs = entry->m_bytestart;
- }
- }
-
- /* validate adjusted addresses against implicit regions */
- if (entry->m_region != NULL && entry->m_share == NULL && entry->m_baseptr == NULL)
- {
- const region_info *region = machine->region(entry->m_region);
- if (region == NULL)
- fatalerror("Error: device '%s' %s space memory map entry %X-%X references non-existant region \"%s\"", space->cpu->tag(), space->name, entry->m_addrstart, entry->m_addrend, entry->m_region);
-
- /* validate the region */
- if (entry->m_rgnoffs + (entry->m_byteend - entry->m_bytestart + 1) > region->bytes())
- fatalerror("Error: device '%s' %s space memory map entry %X-%X extends beyond region \"%s\" size (%X)", space->cpu->tag(), space->name, entry->m_addrstart, entry->m_addrend, entry->m_region, region->bytes());
- }
-
- /* convert any region-relative entries to their memory pointers */
- if (entry->m_region != NULL)
- entry->m_memory = machine->region(entry->m_region)->base() + entry->m_rgnoffs;
- }
-
- /* now loop over all the handlers and enforce the address mask */
- /* we don't loop over map entries because the mask applies to static handlers as well */
- for (entrynum = 0; entrynum < ENTRY_COUNT; entrynum++)
- {
- space->read.handlers[entrynum]->bytemask &= space->bytemask;
- space->write.handlers[entrynum]->bytemask &= space->bytemask;
- }
- }
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_init_populate - populate the memory
- mapping tables with entries
--------------------------------------------------*/
-
-static void memory_init_populate(running_machine *machine)
+UINT16 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write16_delegate handler, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- address_space *space;
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
+}
- /* loop over valid address spaces */
- for (space = (address_space *)memdata->spacelist; space != NULL; space = (address_space *)space->next)
- if (space->map != NULL)
- {
- const address_map_entry *last_entry = NULL;
+UINT16 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_delegate rhandler, write16_delegate whandler, UINT64 unitmask)
+{
+ install_handler(addrstart, addrend, addrmask, addrmirror, rhandler, unitmask);
+ return install_handler(addrstart, addrend, addrmask, addrmirror, whandler, unitmask);
+}
- /* install the handlers, using the original, unadjusted memory map */
- while (last_entry != space->map->m_entrylist)
- {
- const address_map_entry *entry;
- /* find the entry before the last one we processed */
- for (entry = space->map->m_entrylist; entry->m_next != last_entry; entry = entry->m_next) ;
- last_entry = entry;
+//-------------------------------------------------
+// install_legacy_handler - install 16-bit read/
+// write legacy address space handlers for the
+// space
+//-------------------------------------------------
- /* map both read and write halves */
- memory_init_map_entry(space, entry, ROW_READ);
- memory_init_map_entry(space, entry, ROW_WRITE);
- }
- }
+UINT16 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_space_func rhandler, const char *rname, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(*this, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
}
+UINT16 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write16_space_func whandler, const char *wname, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(*this, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
+}
-/*-------------------------------------------------
- memory_init_map_entry - map a single read or
- write entry based on information from an
- address map entry
--------------------------------------------------*/
-
-static void memory_init_map_entry(address_space *space, const address_map_entry *entry, read_or_write readorwrite)
+UINT16 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_space_func rhandler, const char *rname, write16_space_func whandler, const char *wname, UINT64 unitmask)
{
- const map_handler_data *handler = (readorwrite == ROW_READ) ? &entry->m_read : &entry->m_write;
- device_t *device;
+ install_legacy_handler(addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
+}
- /* based on the handler type, alter the bits, name, funcptr, and object */
- switch (handler->type)
- {
- case AMH_NONE:
- return;
- case AMH_ROM:
- if (readorwrite == ROW_WRITE)
- return;
- /* fall through to the RAM case otherwise */
+//-------------------------------------------------
+// install_legacy_handler - install 16-bit read/
+// write legacy device handlers for the space
+//-------------------------------------------------
- case AMH_RAM:
- _memory_install_ram(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- readorwrite == ROW_READ, readorwrite == ROW_WRITE, NULL);
- break;
+UINT16 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_device_func rhandler, const char *rname, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(device, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
+}
- case AMH_NOP:
- _memory_unmap(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- readorwrite == ROW_READ, readorwrite == ROW_WRITE, TRUE);
- break;
+UINT16 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write16_device_func whandler, const char *wname, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(device, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT16 *>(find_backing_memory(addrstart, addrend));
+}
- case AMH_UNMAP:
- _memory_unmap(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- readorwrite == ROW_READ, readorwrite == ROW_WRITE, FALSE);
- break;
+UINT16 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read16_device_func rhandler, const char *rname, write16_device_func whandler, const char *wname, UINT64 unitmask)
+{
+ install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
+}
- case AMH_HANDLER:
- switch ((handler->bits != 0) ? handler->bits : space->dbits)
- {
- case 8:
- _memory_install_handler8(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.shandler8 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.shandler8 : NULL, handler->name,
- handler->mask);
- break;
- case 16:
- _memory_install_handler16(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.shandler16 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.shandler16 : NULL, handler->name,
- handler->mask);
- break;
+//-------------------------------------------------
+// install_handler - install 32-bit read/write
+// delegate handlers for the space
+//-------------------------------------------------
- case 32:
- _memory_install_handler32(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.shandler32 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.shandler32 : NULL, handler->name,
- handler->mask);
- break;
+UINT32 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_delegate handler, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- case 64:
- _memory_install_handler64(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.shandler64 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.shandler64 : NULL, handler->name,
- handler->mask);
- break;
- }
- break;
+UINT32 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write32_delegate handler, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- case AMH_DEVICE_HANDLER:
- device = space->machine->device(handler->tag);
- if (device == NULL)
- fatalerror("Attempted to map a non-existent device '%s' in space %s of device '%s'\n", handler->tag, space->name, (space->cpu != NULL) ? space->cpu->tag() : "??");
- switch ((handler->bits != 0) ? handler->bits : space->dbits)
- {
- case 8:
- _memory_install_device_handler8(space, device, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.dhandler8 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.dhandler8 : NULL, handler->name,
- handler->mask);
- break;
+UINT32 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_delegate rhandler, write32_delegate whandler, UINT64 unitmask)
+{
+ install_handler(addrstart, addrend, addrmask, addrmirror, rhandler, unitmask);
+ return install_handler(addrstart, addrend, addrmask, addrmirror, whandler, unitmask);
+}
- case 16:
- _memory_install_device_handler16(space, device, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.dhandler16 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.dhandler16 : NULL, handler->name,
- handler->mask);
- break;
- case 32:
- _memory_install_device_handler32(space, device, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.dhandler32 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.dhandler32 : NULL, handler->name,
- handler->mask);
- break;
+//-------------------------------------------------
+// install_legacy_handler - install 32-bit read/
+// write legacy address space handlers for the
+// space
+//-------------------------------------------------
- case 64:
- _memory_install_device_handler64(space, device, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->handler.read.dhandler64 : NULL, handler->name,
- (readorwrite == ROW_WRITE) ? handler->handler.write.dhandler64 : NULL, handler->name,
- handler->mask);
- break;
- }
- break;
+UINT32 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_space_func rhandler, const char *rname, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(*this, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- case AMH_PORT:
- _memory_install_port(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->tag : NULL,
- (readorwrite == ROW_WRITE) ? handler->tag : NULL);
- break;
+UINT32 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write32_space_func whandler, const char *wname, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(*this, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- case AMH_BANK:
- _memory_install_bank(space, entry->m_addrstart, entry->m_addrend, entry->m_addrmask, entry->m_addrmirror,
- (readorwrite == ROW_READ) ? handler->tag : NULL,
- (readorwrite == ROW_WRITE) ? handler->tag : NULL);
- break;
- }
+UINT32 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_space_func rhandler, const char *rname, write32_space_func whandler, const char *wname, UINT64 unitmask)
+{
+ install_legacy_handler(addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
}
-/*-------------------------------------------------
- memory_init_allocate - allocate memory for
- device address spaces
--------------------------------------------------*/
+//-------------------------------------------------
+// install_legacy_handler - install 32-bit read/
+// write legacy device handlers for the space
+//-------------------------------------------------
-static void memory_init_allocate(running_machine *machine)
+UINT32 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_device_func rhandler, const char *rname, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- address_space *space;
-
- /* loop over valid address spaces */
- for (space = (address_space *)memdata->spacelist; space != NULL; space = (address_space *)space->next)
- {
- address_map_entry *unassigned = NULL;
- address_map_entry *entry;
- memory_block *prev_memblock_head = memdata->memory_block_list;
- memory_block *memblock;
-
- /* 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 */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- if (entry->m_memory != NULL)
- block_allocate(space, entry->m_bytestart, entry->m_byteend, entry->m_memory);
-
- /* loop over all blocks just allocated and assign pointers from them */
- for (memblock = memdata->memory_block_list; memblock != prev_memblock_head; memblock = memblock->next)
- unassigned = block_assign_intersecting(space, memblock->bytestart, memblock->byteend, memblock->data);
-
- /* if we don't have an unassigned pointer yet, try to find one */
- if (unassigned == NULL)
- unassigned = block_assign_intersecting(space, ~0, 0, NULL);
-
- /* loop until we've assigned all memory in this space */
- while (unassigned != NULL)
- {
- offs_t curbytestart, curbyteend;
- int changed;
- void *block;
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(device, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- /* work in MEMORY_BLOCK_CHUNK-sized chunks */
- offs_t curblockstart = unassigned->m_bytestart / MEMORY_BLOCK_CHUNK;
- offs_t curblockend = unassigned->m_byteend / MEMORY_BLOCK_CHUNK;
+UINT32 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write32_device_func whandler, const char *wname, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(device, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT32 *>(find_backing_memory(addrstart, addrend));
+}
- /* loop while we keep finding unassigned blocks in neighboring MEMORY_BLOCK_CHUNK chunks */
- do
- {
- changed = FALSE;
+UINT32 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read32_device_func rhandler, const char *rname, write32_device_func whandler, const char *wname, UINT64 unitmask)
+{
+ install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
+}
- /* scan for unmapped blocks in the adjusted map */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- if (entry->m_memory == NULL && entry != unassigned && space_needs_backing_store(space, entry))
- {
- offs_t blockstart, blockend;
- /* get block start/end blocks for this block */
- blockstart = entry->m_bytestart / MEMORY_BLOCK_CHUNK;
- blockend = entry->m_byteend / MEMORY_BLOCK_CHUNK;
+//-------------------------------------------------
+// install_handler64 - install 64-bit read/write
+// delegate handlers for the space
+//-------------------------------------------------
- /* 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);
+UINT64 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_delegate handler, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
+}
- /* we now have a block to allocate; do it */
- curbytestart = curblockstart * MEMORY_BLOCK_CHUNK;
- curbyteend = curblockend * MEMORY_BLOCK_CHUNK + (MEMORY_BLOCK_CHUNK - 1);
- block = block_allocate(space, curbytestart, curbyteend, NULL);
+UINT64 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write64_delegate handler, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_delegate(handler, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
+}
- /* assign memory that intersected the new block */
- unassigned = block_assign_intersecting(space, curbytestart, curbyteend, (UINT8 *)block);
- }
- }
+UINT64 *address_space::install_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_delegate rhandler, write64_delegate whandler, UINT64 unitmask)
+{
+ install_handler(addrstart, addrend, addrmask, addrmirror, rhandler, unitmask);
+ return install_handler(addrstart, addrend, addrmask, addrmirror, whandler, unitmask);
}
-/*-------------------------------------------------
- memory_init_locate - find all the requested
- pointers into the final allocated memory
--------------------------------------------------*/
+//-------------------------------------------------
+// install_legacy_handler - install 64-bit read/
+// write legacy address space handlers for the
+// space
+//-------------------------------------------------
-static void memory_init_locate(running_machine *machine)
+UINT64 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_space_func rhandler, const char *rname, UINT64 unitmask)
{
- memory_private *memdata = machine->memory_data;
- address_space *space;
- bank_info *bank;
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(*this, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
+}
- /* loop over valid address spaces */
- for (space = (address_space *)memdata->spacelist; space != NULL; space = (address_space *)space->next)
- {
- const address_map_entry *entry;
+UINT64 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write64_space_func whandler, const char *wname, UINT64 unitmask)
+{
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(*this, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
+}
- /* fill in base/size entries */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- {
- if (entry->m_baseptr != NULL)
- *entry->m_baseptr = entry->m_memory;
- if (entry->m_baseptroffs_plus1 != 0)
- *(void **)(reinterpret_cast<UINT8 *>(machine->driver_data<void>()) + entry->m_baseptroffs_plus1 - 1) = entry->m_memory;
- if (entry->m_genbaseptroffs_plus1 != 0)
- *(void **)((UINT8 *)&machine->generic + entry->m_genbaseptroffs_plus1 - 1) = entry->m_memory;
- if (entry->m_sizeptr != NULL)
- *entry->m_sizeptr = entry->m_byteend - entry->m_bytestart + 1;
- if (entry->m_sizeptroffs_plus1 != 0)
- *(size_t *)(reinterpret_cast<UINT8 *>(machine->driver_data<void>()) + entry->m_sizeptroffs_plus1 - 1) = entry->m_byteend - entry->m_bytestart + 1;
- if (entry->m_gensizeptroffs_plus1 != 0)
- *(size_t *)((UINT8 *)&machine->generic + entry->m_gensizeptroffs_plus1 - 1) = entry->m_byteend - entry->m_bytestart + 1;
- }
- }
+UINT64 *address_space::install_legacy_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_space_func rhandler, const char *rname, write64_space_func whandler, const char *wname, UINT64 unitmask)
+{
+ install_legacy_handler(addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
+}
- /* once this is done, find the starting bases for the banks */
- for (bank = memdata->banklist; bank != NULL; bank = bank->next)
- {
- address_map_entry *entry;
- bank_reference *ref;
- int foundit = FALSE;
-
- /* set the initial bank pointer */
- for (ref = bank->reflist; !foundit && ref != NULL; ref = ref->next)
- for (entry = ref->space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- if (entry->m_bytestart == bank->bytestart && entry->m_memory != NULL)
- {
- memdata->bank_ptr[bank->index] = (UINT8 *)entry->m_memory;
- foundit = TRUE;
- VPRINTF(("assigned bank '%s' pointer to memory from range %08X-%08X [%p]\n", bank->tag, entry->m_addrstart, entry->m_addrend, entry->m_memory));
- break;
- }
- /* if the entry was set ahead of time, override the automatically found pointer */
- if (bank->tag[0] != '~' && bank->curentry != MAX_BANK_ENTRIES)
- memdata->bank_ptr[bank->index] = (UINT8 *)bank->entry[bank->curentry];
- }
+//-------------------------------------------------
+// install_legacy_handler - install 64-bit read/
+// write legacy device handlers for the space
+//-------------------------------------------------
- /* request a callback to fix up the banks when done */
- state_save_register_postload(machine, bank_reattach, NULL);
+UINT64 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_device_func rhandler, const char *rname, UINT64 unitmask)
+{
+ UINT32 entry = read().map_range(addrstart, addrend, addrmask, addrmirror);
+ read().handler_read(entry).set_legacy_func(device, rhandler, rname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
}
-
-/*-------------------------------------------------
- memory_exit - free memory
--------------------------------------------------*/
-
-static void memory_exit(running_machine &machine)
+UINT64 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, write64_device_func whandler, const char *wname, UINT64 unitmask)
{
- memory_private *memdata = machine.memory_data;
- address_space *space;
+ UINT32 entry = write().map_range(addrstart, addrend, addrmask, addrmirror);
+ write().handler_write(entry).set_legacy_func(device, whandler, wname, unitmask);
+ generate_memdump(machine);
+ return reinterpret_cast<UINT64 *>(find_backing_memory(addrstart, addrend));
+}
- /* free all the address spaces and tables */
- for (space = (address_space *)memdata->spacelist; space != NULL; space = space->next)
- {
- /* free the address map and tables */
- global_free(space->map);
- }
+UINT64 *address_space::install_legacy_handler(device_t &device, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read64_device_func rhandler, const char *rname, write64_device_func whandler, const char *wname, UINT64 unitmask)
+{
+ install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, rhandler, rname, unitmask);
+ return install_legacy_handler(device, addrstart, addrend, addrmask, addrmirror, whandler, wname, unitmask);
}
-/***************************************************************************
- MEMORY MAPPING HELPERS
-***************************************************************************/
+//**************************************************************************
+// INTERNAL INITIALIZATION
+//**************************************************************************
-/*-------------------------------------------------
- space_map_range - maps a range of addresses
- to the specified handler within an address
- space
--------------------------------------------------*/
-
-static void space_map_range(address_space *space, read_or_write readorwrite, int handlerbits, int handlerunitmask, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, genf *handler, void *object, const char *handler_name)
-{
- address_table *tabledata = (readorwrite == ROW_WRITE) ? &space->write : &space->read;
- int reset_write = (space->writelookup == space->write.table);
- int reset_read = (space->readlookup == space->read.table);
- offs_t bytestart, byteend, bytemask, bytemirror;
- UINT8 entry;
-
- /* sanity checks */
- assert(space != NULL);
- assert(handlerbits == 8 || handlerbits == 16 || handlerbits == 32 || handlerbits == 64);
-
- /* adjust the incoming addresses */
- bytestart = addrstart;
- byteend = addrend;
- bytemirror = addrmirror;
- bytemask = addrmask;
- adjust_addresses(space, &bytestart, &byteend, &bytemask, &bytemirror);
-
- /* validity checks */
- assert_always(!HANDLER_IS_ROM(handler), "space_map_range called with ROM after initialization");
- assert_always(!HANDLER_IS_RAM(handler), "space_map_range called with RAM after initialization");
- assert_always(addrstart <= addrend, "space_map_range called with start greater than end");
- assert_always(handlerbits <= space->dbits, "space_map_range called with handlers larger than the address space");
- assert_always((bytestart & (space->dbits / 8 - 1)) == 0, "space_map_range called with misaligned start address");
- assert_always((byteend & (space->dbits / 8 - 1)) == (space->dbits / 8 - 1), "space_map_range called with misaligned end address");
-
- /* get the final handler index */
- entry = table_assign_handler(space, tabledata->handlers, object, handler, handler_name, bytestart, byteend, bytemask);
-
- /* fix up the handler if a stub is required */
- if (handlerbits != space->dbits)
- table_compute_subhandler(tabledata->handlers, entry, readorwrite, space->dbits, space->endianness, handlerbits, handlerunitmask);
-
- /* populate it */
- table_populate_range_mirrored(space, tabledata, bytestart, byteend, bytemirror, entry);
-
- /* reset read/write pointers if necessary (could have moved due to realloc) */
- if (reset_write)
- space->writelookup = space->write.table;
- if (reset_read)
- space->readlookup = space->read.table;
-
- /* recompute any direct access on this space if it is a read modification */
- if (readorwrite == ROW_READ && entry == space->direct.entry)
- {
- space->direct.entry = STATIC_UNMAP;
- space->direct.bytestart = 1;
- space->direct.byteend = 0;
- }
-}
+//**************************************************************************
+// MEMORY MAPPING HELPERS
+//**************************************************************************
-/*-------------------------------------------------
- space_find_backing_memory - return a pointer to
- the base of RAM associated with the given
- device and offset
--------------------------------------------------*/
+//-------------------------------------------------
+// find_backing_memory - return a pointer to
+// the base of RAM associated with the given
+// device and offset
+//-------------------------------------------------
-static void *space_find_backing_memory(const address_space *space, offs_t addrstart, offs_t addrend)
+void *address_space::find_backing_memory(offs_t addrstart, offs_t addrend)
{
- offs_t bytestart = memory_address_to_byte(space, addrstart);
- offs_t byteend = memory_address_to_byte_end(space, addrend);
- memory_private *memdata = space->machine->memory_data;
- address_map_entry *entry;
- memory_block *block;
+ offs_t bytestart = address_to_byte(addrstart);
+ offs_t byteend = address_to_byte_end(addrend);
- VPRINTF(("space_find_backing_memory('%s',%s,%08X-%08X) -> ", space->cpu->tag(), space->name, bytestart, byteend));
+ VPRINTF(("address_space::find_backing_memory('%s',%s,%08X-%08X) -> ", m_device.tag(), m_name, bytestart, byteend));
- /* look in the address map first */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
+ // look in the address map first
+ for (address_map_entry *entry = m_map->m_entrylist.first(); entry != NULL; entry = entry->next())
{
offs_t maskstart = bytestart & entry->m_bytemask;
offs_t maskend = byteend & entry->m_bytemask;
@@ -2222,12 +2545,12 @@ static void *space_find_backing_memory(const address_space *space, offs_t addrst
}
}
- /* if not found there, look in the allocated blocks */
- for (block = memdata->memory_block_list; block != NULL; block = block->next)
- if (block->space == space && block->bytestart <= bytestart && block->byteend >= byteend)
+ // if not found there, look in the allocated blocks
+ for (memory_block *block = m_machine.memory_data->blocklist.first(); block != NULL; block = block->next())
+ if (block->contains(*this, bytestart, byteend))
{
- VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->bytestart, block->byteend, block->data + (bytestart - block->bytestart)));
- return block->data + bytestart - block->bytestart;
+ VPRINTF(("found in allocated memory block %08X-%08X [%p]\n", block->bytestart(), block->byteend(), block->data() + (bytestart - block->bytestart())));
+ return block->data() + bytestart - block->bytestart();
}
VPRINTF(("did not find\n"));
@@ -2235,619 +2558,582 @@ static void *space_find_backing_memory(const address_space *space, offs_t addrst
}
-/*-------------------------------------------------
- space_needs_backing_store - return whether a
- given memory map entry implies the need of
- allocating and registering memory
--------------------------------------------------*/
+//-------------------------------------------------
+// space_needs_backing_store - return whether a
+// given memory map entry implies the need of
+// allocating and registering memory
+//-------------------------------------------------
-static int space_needs_backing_store(const address_space *space, const address_map_entry *entry)
+bool address_space::needs_backing_store(const address_map_entry *entry)
{
- /* if we are asked to provide a base pointer, then yes, we do need backing */
+ // if we are asked to provide a base pointer, then yes, we do need backing
if (entry->m_baseptr != NULL || entry->m_baseptroffs_plus1 != 0 || entry->m_genbaseptroffs_plus1 != 0)
- return TRUE;
+ return true;
- /* if we're writing to any sort of bank or RAM, then yes, we do need backing */
- if (entry->m_write.type == AMH_BANK || entry->m_write.type == AMH_RAM)
- 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 */
- const region_info *region = space->machine->region(space->cpu->tag());
- if (entry->m_read.type == AMH_RAM ||
- (entry->m_read.type == AMH_ROM && (space->spacenum != ADDRESS_SPACE_0 || region == NULL || entry->m_addrstart >= region->bytes())))
- 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
+ const region_info *region = m_machine.region(m_device.tag());
+ if (entry->m_read.m_type == AMH_RAM ||
+ (entry->m_read.m_type == AMH_ROM && (m_spacenum != ADDRESS_SPACE_0 || region == NULL || entry->m_addrstart >= region->bytes())))
+ return true;
- /* all other cases don't need backing */
- return FALSE;
+ // all other cases don't need backing
+ return false;
}
-/***************************************************************************
- BANKING HELPERS
-***************************************************************************/
+//**************************************************************************
+// BANKING HELPERS
+//**************************************************************************
-/*-------------------------------------------------
- bank_find_or_allocate - allocate a new
- bank, or find an existing one, and return the
- read/write handler
--------------------------------------------------*/
+//-------------------------------------------------
+// bank_find_or_allocate - allocate a new
+// bank, or find an existing one, and return the
+// read/write handler
+//-------------------------------------------------
-static genf *bank_find_or_allocate(const address_space *space, const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite)
+memory_bank &address_space::bank_find_or_allocate(const char *tag, offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite)
{
- memory_private *memdata = space->machine->memory_data;
+ memory_private *memdata = m_machine.memory_data;
+
+ // adjust the addresses, handling mirrors and such
offs_t bytemirror = addrmirror;
offs_t bytestart = addrstart;
offs_t bytemask = addrmask;
offs_t byteend = addrend;
- bank_info *bank = NULL;
- char temptag[10];
- char name[30];
-
- /* adjust the addresses, handling mirrors and such */
- adjust_addresses(space, &bytestart, &byteend, &bytemask, &bytemirror);
+ adjust_addresses(bytestart, byteend, bytemask, bytemirror);
- /* if this bank is named, look it up */
+ // if this bank is named, look it up
+ memory_bank *bank = NULL;
if (tag != NULL)
bank = memdata->bankmap.find_hash_only(tag);
- /* else try to find an exact match */
+ // else try to find an exact match
else
- {
- for (bank = memdata->banklist; bank != NULL; bank = bank->next)
- if (bank->tag[0] == '~' && bank->bytestart == bytestart && bank->byteend == byteend && bank->reflist != NULL && bank->reflist->space == space)
+ for (bank = memdata->banklist.first(); bank != NULL; bank = bank->next())
+ if (bank->anonymous() && bank->references_space(*this, ROW_READWRITE) && bank->matches_exactly(bytestart, byteend))
break;
- }
- /* if we don't have a bank yet, find a free one */
+ // if we don't have a bank yet, find a free one
if (bank == NULL)
{
+ // handle failure
int banknum = memdata->banknext++;
-
- /* handle failure */
if (banknum > STATIC_BANKMAX)
{
if (tag != NULL)
- fatalerror("Unable to allocate new bank '%s'", tag);
+ throw emu_fatalerror("Unable to allocate new bank '%s'", tag);
else
- fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", bytestart, byteend);
+ throw emu_fatalerror("Unable to allocate bank for RAM/ROM area %X-%X\n", bytestart, byteend);
}
- /* generate an internal tag if we don't have one */
- if (tag == NULL)
- {
- sprintf(temptag, "~%d~", banknum);
- tag = temptag;
- sprintf(name, "Internal bank #%d", banknum);
- }
- else
- sprintf(name, "Bank '%s'", tag);
-
- /* allocate the bank */
- bank = (bank_info *)auto_alloc_array_clear(space->machine, UINT8, sizeof(bank_info) + strlen(tag) + 1 + strlen(name));
-
- /* populate it */
- bank->index = banknum;
- bank->handler = (void *)(FPTR)(STATIC_BANK1 + banknum - 1);
- bank->bytestart = bytestart;
- bank->byteend = byteend;
- bank->curentry = MAX_BANK_ENTRIES;
- strcpy(bank->tag, tag);
- bank->name = bank->tag + strlen(tag) + 1;
- strcpy(bank->name, name);
-
- /* add us to the list */
- bank->next = memdata->banklist;
- memdata->banklist = bank;
-
- /* for named banks, add to the map and register for save states */
- if (tag[0] != '~')
- {
- memdata->bankmap.add_unique_hash(tag, bank, FALSE);
- if (state_save_registration_allowed(space->machine))
- state_save_register_item(space->machine, "memory", bank->tag, 0, bank->curentry);
- }
- }
+ // allocate the bank
+ bank = auto_alloc(&m_machine, memory_bank(*this, banknum, bytestart, byteend, tag));
+ memdata->banklist.append(*bank);
- /* update the read/write state for this bank */
- if (readorwrite == ROW_READ)
- bank->read = TRUE;
- if (readorwrite == ROW_WRITE)
- bank->write = TRUE;
+ // for named banks, add to the map and register for save states
+ if (tag != NULL)
+ memdata->bankmap.add_unique_hash(tag, bank, false);
+ }
- /* add a reference for this space */
- add_bank_reference(bank, space);
- return (genf *)bank->handler;
+ // add a reference for this space
+ bank->add_reference(*this, readorwrite);
+ return *bank;
}
-/*-------------------------------------------------
- bank_reattach - reconnect banks after a load
--------------------------------------------------*/
-static STATE_POSTLOAD( bank_reattach )
+//**************************************************************************
+// TABLE MANAGEMENT
+//**************************************************************************
+
+//-------------------------------------------------
+// address_table - constructor
+//-------------------------------------------------
+
+address_table::address_table(address_space &space, bool large)
+ : m_table(auto_alloc_array(&space.m_machine, UINT8, 1 << LEVEL1_BITS)),
+ m_live_lookup(m_table),
+ m_space(space),
+ m_large(large),
+ m_subtable(auto_alloc_array(&space.m_machine, subtable_data, SUBTABLE_COUNT)),
+ m_subtable_alloc(0)
{
- memory_private *memdata = machine->memory_data;
- bank_info *bank;
+ // make our static table all watchpoints
+ if (s_watchpoint_table[0] != STATIC_WATCHPOINT)
+ memset(s_watchpoint_table, STATIC_WATCHPOINT, sizeof(s_watchpoint_table));
- /* once this is done, find the starting bases for the banks */
- for (bank = memdata->banklist; bank != NULL; bank = bank->next)
- if (bank->tag[0] != '~')
- {
- /* if this entry has a changed entry, set the appropriate pointer */
- if (bank->curentry != MAX_BANK_ENTRIES)
- memdata->bank_ptr[bank->index] = (UINT8 *)bank->entry[bank->curentry];
- }
+ // initialize everything to unmapped
+ memset(m_table, STATIC_UNMAP, 1 << LEVEL1_BITS);
}
+//-------------------------------------------------
+// ~address_table - destructor
+//-------------------------------------------------
-/***************************************************************************
- TABLE MANAGEMENT
-***************************************************************************/
+address_table::~address_table()
+{
+ auto_free(&m_space.m_machine, m_table);
+ auto_free(&m_space.m_machine, m_subtable);
+}
-/*-------------------------------------------------
- table_assign_handler - finds the index of a
- handler, or allocates a new one as necessary
--------------------------------------------------*/
-static UINT8 table_assign_handler(const address_space *space, handler_data **table, void *object, genf *handler, const char *handler_name, offs_t bytestart, offs_t byteend, offs_t bytemask)
-{
- int entry;
+//-------------------------------------------------
+// map_range - finds an approprite handler entry
+// and requests to populate the address map with
+// it
+//-------------------------------------------------
- /* all static handlers are hardcoded */
- if (HANDLER_IS_STATIC(handler))
- {
- entry = (FPTR)handler;
+UINT8 address_table::map_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, UINT8 staticentry)
+{
+ // convert addresses to bytes
+ offs_t bytestart = addrstart;
+ offs_t byteend = addrend;
+ offs_t bytemask = addrmask;
+ offs_t bytemirror = addrmirror;
+ m_space.adjust_addresses(bytestart, byteend, bytemask, bytemirror);
- /* if it is a bank, copy in the relevant information */
- if (HANDLER_IS_BANK(handler))
- {
- handler_data *hdata = table[entry];
- hdata->bytestart = bytestart;
- hdata->byteend = byteend;
- hdata->bytemask = bytemask;
- hdata->bankbaseptr = &space->machine->memory_data->bank_ptr[entry];
- hdata->name = handler_name;
- }
- return entry;
- }
+ // validity checks
+ assert_always(addrstart <= addrend, "address_table::map_range called with start greater than end");
+ assert_always((bytestart & (m_space.data_width() / 8 - 1)) == 0, "address_table::map_range called with misaligned start address");
+ assert_always((byteend & (m_space.data_width() / 8 - 1)) == (m_space.data_width() / 8 - 1), "address_table::map_range called with misaligned end address");
- /* otherwise, we have to search */
- for (entry = STATIC_COUNT; entry < SUBTABLE_BASE; entry++)
+ // if we weren't given an explicit entry, find a free one
+ UINT8 entry = staticentry;
+ if (entry == STATIC_INVALID)
{
- handler_data *hdata = table[entry];
-
- /* if we hit a NULL hdata, then we need to allocate this one as a new one */
- if (hdata->handler.generic == NULL)
+ // two attempts to find an empty
+ for (int attempt = 0; attempt < 2; attempt++)
{
- hdata->handler.generic = handler;
- hdata->bytestart = bytestart;
- hdata->byteend = byteend;
- hdata->bytemask = bytemask;
- hdata->name = handler_name;
- hdata->object = object;
- return entry;
+ // scan all possible assigned entries for something unpopulated, or for an exact match
+ for (UINT8 scanentry = STATIC_COUNT; scanentry < SUBTABLE_BASE; scanentry++)
+ {
+ handler_entry &curentry = handler(scanentry);
+
+ // exact match takes precedence, and in fact doesn't need any
+ // further configuration or population
+ if (curentry.matches_exactly(bytestart, byteend, bytemask))
+ return scanentry;
+
+ // unpopulated is our second choice
+ if (entry == STATIC_INVALID && !curentry.populated())
+ entry = scanentry;
+ }
+
+ // if we didn't find anything, find something to depopulate
+ if (entry != STATIC_INVALID)
+ break;
+ depopulate_unused();
}
- /* if we find a perfect match, return a duplicate entry */
- if (hdata->handler.generic == handler && hdata->bytestart == bytestart && hdata->bytemask == bytemask && hdata->object == object)
- return entry;
+ // if we utterly failed, it's fatal
+ if (entry == STATIC_INVALID)
+ throw emu_fatalerror("Out of handler entries in address table");
}
- return 0;
-}
-
-
-/*-------------------------------------------------
- table_compute_subhandler - compute data for
- a subhandler
--------------------------------------------------*/
-
-static void table_compute_subhandler(handler_data **table, UINT8 entry, read_or_write readorwrite, int spacebits, int spaceendian, int handlerbits, int handlerunitmask)
-{
- int maxunits = spacebits / handlerbits;
- handler_data *hdata = table[entry];
- int unitnum;
-
- assert_always(!HANDLER_IS_STATIC(entry), "table_compute_subhandler called with static handlers and mismatched data bus widths");
-
- /* copy raw data to the subhandler data */
- hdata->subobject = hdata->object;
- hdata->subhandler = hdata->handler;
- /* fill in a stub as the real handler */
- hdata->object = hdata;
- hdata->handler = get_stub_handler(readorwrite, spacebits, handlerbits);
+ // configure the entry to our parameters
+ handler_entry &curentry = handler(entry);
+ curentry.configure(bytestart, byteend, bytemask);
- /* compute the number of subunits */
- hdata->subunits = 0;
- for (unitnum = 0; unitnum < maxunits; unitnum++)
- if (handlerunitmask & (1 << unitnum))
- hdata->subunits++;
- assert_always(hdata->subunits > 0, "table_compute_subhandler called with no bytes specified in mask");
-
- /* then fill in the shifts based on the endianness */
- if (spaceendian == ENDIANNESS_LITTLE)
- {
- UINT8 *unitshift = &hdata->subshift[0];
- for (unitnum = 0; unitnum < maxunits; unitnum++)
- if (handlerunitmask & (1 << unitnum))
- *unitshift++ = unitnum * handlerbits;
- }
- else
- {
- UINT8 *unitshift = &hdata->subshift[hdata->subunits];
- for (unitnum = 0; unitnum < maxunits; unitnum++)
- if (handlerunitmask & (1 << unitnum))
- *--unitshift = unitnum * handlerbits;
- }
+ // populate it
+ populate_range_mirrored(bytestart, byteend, bytemirror, entry);
+
+ // recompute any direct access on this space if it is a read modification
+ m_space.m_direct.force_update(entry);
+ return entry;
}
-/*-------------------------------------------------
- table_populate_range - assign a memory handler
- to a range of addresses
--------------------------------------------------*/
+//-------------------------------------------------
+// populate_range - assign a memory handler to a
+// range of addresses
+//-------------------------------------------------
-static void table_populate_range(address_table *tabledata, offs_t bytestart, offs_t byteend, UINT8 handler)
+void address_table::populate_range(offs_t bytestart, offs_t byteend, UINT8 handlerindex)
{
- offs_t l2mask = (1 << LEVEL2_BITS) - 1;
- offs_t l1start = bytestart >> LEVEL2_BITS;
+ offs_t l2mask = (1 << level2_bits()) - 1;
+ offs_t l1start = bytestart >> level2_bits();
offs_t l2start = bytestart & l2mask;
- offs_t l1stop = byteend >> LEVEL2_BITS;
+ offs_t l1stop = byteend >> level2_bits();
offs_t l2stop = byteend & l2mask;
- offs_t l1index;
- /* sanity check */
+ // sanity check
if (bytestart > byteend)
return;
- /* handle the starting edge if it's not on a block boundary */
+ // handle the starting edge if it's not on a block boundary
if (l2start != 0)
{
- UINT8 *subtable = subtable_open(tabledata, l1start);
+ UINT8 *subtable = subtable_open(l1start);
- /* if the start and stop end within the same block, handle that */
+ // if the start and stop end within the same block, handle that
if (l1start == l1stop)
{
- memset(&subtable[l2start], handler, l2stop - l2start + 1);
- subtable_close(tabledata, l1start);
+ memset(&subtable[l2start], handlerindex, l2stop - l2start + 1);
+ subtable_close(l1start);
return;
}
- /* otherwise, fill until the end */
- memset(&subtable[l2start], handler, (1 << LEVEL2_BITS) - l2start);
- subtable_close(tabledata, l1start);
- if (l1start != (offs_t)~0) l1start++;
+ // otherwise, fill until the end
+ memset(&subtable[l2start], handlerindex, (1 << level2_bits()) - l2start);
+ subtable_close(l1start);
+ if (l1start != (offs_t)~0)
+ l1start++;
}
- /* handle the trailing edge if it's not on a block boundary */
+ // handle the trailing edge if it's not on a block boundary
if (l2stop != l2mask)
{
- UINT8 *subtable = subtable_open(tabledata, l1stop);
+ UINT8 *subtable = subtable_open(l1stop);
- /* fill from the beginning */
- memset(&subtable[0], handler, l2stop + 1);
- subtable_close(tabledata, l1stop);
+ // fill from the beginning
+ memset(&subtable[0], handlerindex, l2stop + 1);
+ subtable_close(l1stop);
- /* if the start and stop end within the same block, handle that */
+ // if the start and stop end within the same block, handle that
if (l1start == l1stop)
return;
- if (l1stop != 0) l1stop--;
+ if (l1stop != 0)
+ l1stop--;
}
- /* now fill in the middle tables */
- for (l1index = l1start; l1index <= l1stop; l1index++)
+ // now fill in the middle tables
+ for (offs_t l1index = l1start; l1index <= l1stop; l1index++)
{
- /* if we have a subtable here, release it */
- if (tabledata->table[l1index] >= SUBTABLE_BASE)
- subtable_release(tabledata, tabledata->table[l1index]);
- tabledata->table[l1index] = handler;
+ // if we have a subtable here, release it
+ if (m_table[l1index] >= SUBTABLE_BASE)
+ subtable_release(m_table[l1index]);
+ m_table[l1index] = handlerindex;
}
}
-/*-------------------------------------------------
- table_populate_range_mirrored - assign a
- memory handler to a range of addresses
- including mirrors
--------------------------------------------------*/
+//-------------------------------------------------
+// populate_range_mirrored - assign a memory
+// handler to a range of addresses including
+// mirrors
+//-------------------------------------------------
-static void table_populate_range_mirrored(address_space *space, address_table *tabledata, offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handler)
+void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handlerindex)
{
- offs_t lmirrorbit[LEVEL2_BITS], lmirrorbits, hmirrorbit[32 - LEVEL2_BITS], hmirrorbits, lmirrorcount, hmirrorcount;
+ // determine the mirror bits
+ offs_t lmirrorbits = 0;
+ offs_t lmirrorbit[32];
+ for (int bit = 0; bit < level2_bits(); bit++)
+ if (bytemirror & (1 << bit))
+ lmirrorbit[lmirrorbits++] = 1 << bit;
+
+ offs_t hmirrorbits = 0;
+ offs_t hmirrorbit[32];
+ for (int bit = level2_bits(); bit < 32; bit++)
+ if (bytemirror & (1 << bit))
+ hmirrorbit[hmirrorbits++] = 1 << bit;
+
+ // loop over mirrors in the level 2 table
UINT8 prev_entry = STATIC_INVALID;
- int cur_index, prev_index = 0;
- int i;
-
- /* determine the mirror bits */
- hmirrorbits = lmirrorbits = 0;
- for (i = 0; i < LEVEL2_BITS; i++)
- if (bytemirror & (1 << i))
- lmirrorbit[lmirrorbits++] = 1 << i;
- for (i = LEVEL2_BITS; i < 32; i++)
- if (bytemirror & (1 << i))
- hmirrorbit[hmirrorbits++] = 1 << i;
-
- /* loop over mirrors in the level 2 table */
- for (hmirrorcount = 0; hmirrorcount < (1 << hmirrorbits); hmirrorcount++)
+ int prev_index = 0;
+ for (offs_t hmirrorcount = 0; hmirrorcount < (1 << hmirrorbits); hmirrorcount++)
{
- /* compute the base of this mirror */
+ // compute the base of this mirror
offs_t hmirrorbase = 0;
- for (i = 0; i < hmirrorbits; i++)
- if (hmirrorcount & (1 << i))
- hmirrorbase |= hmirrorbit[i];
+ for (int bit = 0; bit < hmirrorbits; bit++)
+ if (hmirrorcount & (1 << bit))
+ hmirrorbase |= hmirrorbit[bit];
- /* invalidate any intersecting cached ranges */
- for (lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++)
+ // invalidate any intersecting cached ranges
+ for (offs_t lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++)
{
- /* compute the base of this mirror */
+ // compute the base of this mirror
offs_t lmirrorbase = hmirrorbase;
- for (i = 0; i < lmirrorbits; i++)
- if (lmirrorcount & (1 << i))
- lmirrorbase |= lmirrorbit[i];
- direct_range_remove_intersecting(space, bytestart + lmirrorbase, byteend + lmirrorbase);
+ for (int bit = 0; bit < lmirrorbits; bit++)
+ if (lmirrorcount & (1 << bit))
+ lmirrorbase |= lmirrorbit[bit];
+ m_space.m_direct.remove_intersecting_ranges(bytestart + lmirrorbase, byteend + lmirrorbase);
}
- /* if this is not our first time through, and the level 2 entry matches the previous
- level 2 entry, just do a quick map and get out; note that this only works for entries
- which don't span multiple level 1 table entries */
- cur_index = LEVEL1_INDEX(bytestart + hmirrorbase);
- if (cur_index == LEVEL1_INDEX(byteend + hmirrorbase))
+ // if this is not our first time through, and the level 2 entry matches the previous
+ // level 2 entry, just do a quick map and get out; note that this only works for entries
+ // which don't span multiple level 1 table entries
+ int cur_index = level1_index(bytestart + hmirrorbase);
+ if (cur_index == level1_index(byteend + hmirrorbase))
{
- if (hmirrorcount != 0 && prev_entry == tabledata->table[cur_index])
+ if (hmirrorcount != 0 && prev_entry == m_table[cur_index])
{
- VPRINTF(("Quick mapping subtable at %08X to match subtable at %08X\n", cur_index << LEVEL2_BITS, prev_index << LEVEL2_BITS));
+ VPRINTF(("Quick mapping subtable at %08X to match subtable at %08X\n", cur_index << level2_bits(), prev_index << level2_bits()));
- /* release the subtable if the old value was a subtable */
- if (tabledata->table[cur_index] >= SUBTABLE_BASE)
- subtable_release(tabledata, tabledata->table[cur_index]);
+ // release the subtable if the old value was a subtable
+ if (m_table[cur_index] >= SUBTABLE_BASE)
+ subtable_release(m_table[cur_index]);
- /* reallocate the subtable if the new value is a subtable */
- if (tabledata->table[prev_index] >= SUBTABLE_BASE)
- subtable_realloc(tabledata, tabledata->table[prev_index]);
+ // reallocate the subtable if the new value is a subtable
+ if (m_table[prev_index] >= SUBTABLE_BASE)
+ subtable_realloc(m_table[prev_index]);
- /* set the new value and short-circuit the mapping step */
- tabledata->table[cur_index] = tabledata->table[prev_index];
+ // set the new value and short-circuit the mapping step
+ m_table[cur_index] = m_table[prev_index];
continue;
}
prev_index = cur_index;
- prev_entry = tabledata->table[cur_index];
+ prev_entry = m_table[cur_index];
}
- /* loop over mirrors in the level 1 table */
- for (lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++)
+ // loop over mirrors in the level 1 table
+ for (offs_t lmirrorcount = 0; lmirrorcount < (1 << lmirrorbits); lmirrorcount++)
{
- /* compute the base of this mirror */
+ // compute the base of this mirror
offs_t lmirrorbase = hmirrorbase;
- for (i = 0; i < lmirrorbits; i++)
- if (lmirrorcount & (1 << i))
- lmirrorbase |= lmirrorbit[i];
+ for (int bit = 0; bit < lmirrorbits; bit++)
+ if (lmirrorcount & (1 << bit))
+ lmirrorbase |= lmirrorbit[bit];
- /* populate the tables */
- table_populate_range(tabledata, bytestart + lmirrorbase, byteend + lmirrorbase, handler);
+ // populate the tables
+ populate_range(bytestart + lmirrorbase, byteend + lmirrorbase, handlerindex);
}
}
}
-/*-------------------------------------------------
- table_derive_range - look up the entry for
- a memory range, and then compute the extent
- of that range based on the lookup tables
--------------------------------------------------*/
+//-------------------------------------------------
+// depopulate_unused - scan the table and
+// eliminate entries that are no longer used
+//-------------------------------------------------
-static UINT8 table_derive_range(const address_table *table, offs_t byteaddress, offs_t *bytestart, offs_t *byteend)
+void address_table::depopulate_unused()
{
- UINT32 curentry, entry, curl1entry, l1entry;
- const handler_data *handler;
- offs_t minscan, maxscan;
+ assert(false);
+}
- /* look up the initial address to get the entry we care about */
- entry = l1entry = table->table[LEVEL1_INDEX(byteaddress)];
+
+//-------------------------------------------------
+// derive_range - look up the entry for a memory
+// range, and then compute the extent of that
+// range based on the lookup tables
+//-------------------------------------------------
+
+UINT8 address_table::derive_range(offs_t byteaddress, offs_t &bytestart, offs_t &byteend) const
+{
+ // look up the initial address to get the entry we care about
+ UINT8 l1entry;
+ UINT8 entry = l1entry = m_table[level1_index(byteaddress)];
if (l1entry >= SUBTABLE_BASE)
- entry = table->table[LEVEL2_INDEX(l1entry, byteaddress)];
- handler = table->handlers[entry];
+ entry = m_table[level2_index(l1entry, byteaddress)];
- /* use the bytemask of the entry to set minimum and maximum bounds */
- minscan = handler->bytestart | ((byteaddress - handler->bytestart) & ~handler->bytemask);
- maxscan = handler->byteend | ((byteaddress - handler->bytestart) & ~handler->bytemask);
+ // use the bytemask of the entry to set minimum and maximum bounds
+ offs_t minscan, maxscan;
+ handler(entry).mirrored_start_end(byteaddress, minscan, maxscan);
- /* first scan backwards to find the start address */
- curl1entry = l1entry;
- curentry = entry;
- *bytestart = byteaddress;
+ // first scan backwards to find the start address
+ UINT8 curl1entry = l1entry;
+ UINT8 curentry = entry;
+ bytestart = byteaddress;
while (1)
{
- /* if we need to scan the subtable, do it */
+ // if we need to scan the subtable, do it
if (curentry != curl1entry)
{
- UINT32 minindex = LEVEL2_INDEX(curl1entry, 0);
+ UINT32 minindex = level2_index(curl1entry, 0);
UINT32 index;
- /* scan backwards from the current address, until the previous entry doesn't match */
- for (index = LEVEL2_INDEX(curl1entry, *bytestart); index > minindex; index--, *bytestart -= 1)
- if (table->table[index - 1] != entry)
+ // scan backwards from the current address, until the previous entry doesn't match
+ for (index = level2_index(curl1entry, bytestart); index > minindex; index--, bytestart -= 1)
+ if (m_table[index - 1] != entry)
break;
- /* if we didn't hit the beginning, then we're finished scanning */
+ // if we didn't hit the beginning, then we're finished scanning
if (index != minindex)
break;
}
- /* move to the beginning of this L1 entry; stop at the minimum address */
- *bytestart &= ~((1 << LEVEL2_BITS) - 1);
- if (*bytestart <= minscan)
+ // move to the beginning of this L1 entry; stop at the minimum address
+ bytestart &= ~((1 << level2_bits()) - 1);
+ if (bytestart <= minscan)
break;
- /* look up the entry of the byte at the end of the previous L1 entry; if it doesn't match, stop */
- curentry = curl1entry = table->table[LEVEL1_INDEX(*bytestart - 1)];
+ // look up the entry of the byte at the end of the previous L1 entry; if it doesn't match, stop
+ curentry = curl1entry = m_table[level1_index(bytestart - 1)];
if (curl1entry >= SUBTABLE_BASE)
- curentry = table->table[LEVEL2_INDEX(curl1entry, *bytestart - 1)];
+ curentry = m_table[level2_index(curl1entry, bytestart - 1)];
if (curentry != entry)
break;
- /* move into the previous entry and resume searching */
- *bytestart -= 1;
+ // move into the previous entry and resume searching
+ bytestart -= 1;
}
- /* then scan forwards to find the end address */
+ // then scan forwards to find the end address
curl1entry = l1entry;
curentry = entry;
- *byteend = byteaddress;
+ byteend = byteaddress;
while (1)
{
- /* if we need to scan the subtable, do it */
+ // if we need to scan the subtable, do it
if (curentry != curl1entry)
{
- UINT32 maxindex = LEVEL2_INDEX(curl1entry, ~0);
+ UINT32 maxindex = level2_index(curl1entry, ~0);
UINT32 index;
- /* scan forwards from the current address, until the next entry doesn't match */
- for (index = LEVEL2_INDEX(curl1entry, *byteend); index < maxindex; index++, *byteend += 1)
- if (table->table[index + 1] != entry)
+ // scan forwards from the current address, until the next entry doesn't match
+ for (index = level2_index(curl1entry, byteend); index < maxindex; index++, byteend += 1)
+ if (m_table[index + 1] != entry)
break;
- /* if we didn't hit the end, then we're finished scanning */
+ // if we didn't hit the end, then we're finished scanning
if (index != maxindex)
break;
}
- /* move to the end of this L1 entry; stop at the maximum address */
- *byteend |= (1 << LEVEL2_BITS) - 1;
- if (*byteend >= maxscan)
+ // move to the end of this L1 entry; stop at the maximum address
+ byteend |= (1 << level2_bits()) - 1;
+ if (byteend >= maxscan)
break;
- /* look up the entry of the byte at the start of the next L1 entry; if it doesn't match, stop */
- curentry = curl1entry = table->table[LEVEL1_INDEX(*byteend + 1)];
+ // look up the entry of the byte at the start of the next L1 entry; if it doesn't match, stop
+ curentry = curl1entry = m_table[level1_index(byteend + 1)];
if (curl1entry >= SUBTABLE_BASE)
- curentry = table->table[LEVEL2_INDEX(curl1entry, *byteend + 1)];
+ curentry = m_table[level2_index(curl1entry, byteend + 1)];
if (curentry != entry)
break;
- /* move into the next entry and resume searching */
- *byteend += 1;
+ // move into the next entry and resume searching
+ byteend += 1;
}
return entry;
}
+//-------------------------------------------------
+// mask_all_handlers - apply a mask to all
+// address handlers
+//-------------------------------------------------
-/***************************************************************************
- SUBTABLE MANAGEMENT
-***************************************************************************/
+void address_table::mask_all_handlers(offs_t mask)
+{
+ // we don't loop over map entries because the mask applies to static handlers as well
+ for (int entrynum = 0; entrynum < ENTRY_COUNT; entrynum++)
+ handler(entrynum).apply_mask(mask);
+}
-/*-------------------------------------------------
- subtable_alloc - allocate a fresh subtable
- and set its usecount to 1
--------------------------------------------------*/
-static UINT8 subtable_alloc(address_table *tabledata)
+
+//**************************************************************************
+// SUBTABLE MANAGEMENT
+//**************************************************************************
+
+//-------------------------------------------------
+// subtable_alloc - allocate a fresh subtable
+// and set its usecount to 1
+//-------------------------------------------------
+
+UINT8 address_table::subtable_alloc()
{
- /* loop */
+ // loop
while (1)
{
- UINT8 subindex;
-
- /* find a subtable with a usecount of 0 */
- for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
- if (tabledata->subtable[subindex].usecount == 0)
+ // find a subtable with a usecount of 0
+ for (UINT8 subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
+ if (m_subtable[subindex].m_usecount == 0)
{
- /* if this is past our allocation budget, allocate some more */
- if (subindex >= tabledata->subtable_alloc)
+ // if this is past our allocation budget, allocate some more
+ if (subindex >= m_subtable_alloc)
{
- UINT32 oldsize = (1 << LEVEL1_BITS) + (tabledata->subtable_alloc << LEVEL2_BITS);
- tabledata->subtable_alloc += SUBTABLE_ALLOC;
- UINT32 newsize = (1 << LEVEL1_BITS) + (tabledata->subtable_alloc << LEVEL2_BITS);
-
- UINT8 *newtable = auto_alloc_array(tabledata->machine, UINT8, newsize);
- memcpy(newtable, tabledata->table, oldsize);
- auto_free(tabledata->machine, tabledata->table);
- tabledata->table = newtable;
+ UINT32 oldsize = (1 << LEVEL1_BITS) + (m_subtable_alloc << level2_bits());
+ m_subtable_alloc += SUBTABLE_ALLOC;
+ UINT32 newsize = (1 << LEVEL1_BITS) + (m_subtable_alloc << level2_bits());
+
+ UINT8 *newtable = auto_alloc_array_clear(&m_space.m_machine, UINT8, newsize);
+ memcpy(newtable, m_table, oldsize);
+ if (m_live_lookup == m_table)
+ m_live_lookup = newtable;
+ auto_free(&m_space.m_machine, m_table);
+ m_table = newtable;
}
- /* bump the usecount and return */
- tabledata->subtable[subindex].usecount++;
+ // bump the usecount and return
+ m_subtable[subindex].m_usecount++;
return subindex + SUBTABLE_BASE;
}
- /* merge any subtables we can */
- if (!subtable_merge(tabledata))
+ // merge any subtables we can
+ if (!subtable_merge())
fatalerror("Ran out of subtables!");
}
}
-/*-------------------------------------------------
- subtable_realloc - increment the usecount on
- a subtable
--------------------------------------------------*/
+//-------------------------------------------------
+// subtable_realloc - increment the usecount on
+// a subtable
+//-------------------------------------------------
-static void subtable_realloc(address_table *tabledata, UINT8 subentry)
+void address_table::subtable_realloc(UINT8 subentry)
{
UINT8 subindex = subentry - SUBTABLE_BASE;
- /* sanity check */
- if (tabledata->subtable[subindex].usecount <= 0)
+ // sanity check
+ if (m_subtable[subindex].m_usecount <= 0)
fatalerror("Called subtable_realloc on a table with a usecount of 0");
- /* increment the usecount */
- tabledata->subtable[subindex].usecount++;
+ // increment the usecount
+ m_subtable[subindex].m_usecount++;
}
-/*-------------------------------------------------
- subtable_merge - merge any duplicate
- subtables
--------------------------------------------------*/
+//-------------------------------------------------
+// subtable_merge - merge any duplicate
+// subtables
+//-------------------------------------------------
-static int subtable_merge(address_table *tabledata)
+int address_table::subtable_merge()
{
int merged = 0;
UINT8 subindex;
VPRINTF(("Merging subtables....\n"));
- /* okay, we failed; update all the checksums and merge tables */
+ // okay, we failed; update all the checksums and merge tables
for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
- if (!tabledata->subtable[subindex].checksum_valid && tabledata->subtable[subindex].usecount != 0)
+ if (!m_subtable[subindex].m_checksum_valid && m_subtable[subindex].m_usecount != 0)
{
- UINT32 *subtable = (UINT32 *)SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE);
+ UINT32 *subtable = reinterpret_cast<UINT32 *>(subtable_ptr(subindex + SUBTABLE_BASE));
UINT32 checksum = 0;
- int l2index;
- /* update the checksum */
- for (l2index = 0; l2index < (1 << LEVEL2_BITS)/4; l2index++)
+ // update the checksum
+ for (int l2index = 0; l2index < (1 << level2_bits())/4; l2index++)
checksum += subtable[l2index];
- tabledata->subtable[subindex].checksum = checksum;
- tabledata->subtable[subindex].checksum_valid = 1;
+ m_subtable[subindex].m_checksum = checksum;
+ m_subtable[subindex].m_checksum_valid = true;
}
- /* see if there's a matching checksum */
+ // see if there's a matching checksum
for (subindex = 0; subindex < SUBTABLE_COUNT; subindex++)
- if (tabledata->subtable[subindex].usecount != 0)
+ if (m_subtable[subindex].m_usecount != 0)
{
- UINT8 *subtable = SUBTABLE_PTR(tabledata, subindex + SUBTABLE_BASE);
- UINT32 checksum = tabledata->subtable[subindex].checksum;
+ UINT8 *subtable = subtable_ptr(subindex + SUBTABLE_BASE);
+ UINT32 checksum = m_subtable[subindex].m_checksum;
UINT8 sumindex;
for (sumindex = subindex + 1; sumindex < SUBTABLE_COUNT; sumindex++)
- if (tabledata->subtable[sumindex].usecount != 0 &&
- tabledata->subtable[sumindex].checksum == checksum &&
- !memcmp(subtable, SUBTABLE_PTR(tabledata, sumindex + SUBTABLE_BASE), 1 << LEVEL2_BITS))
+ if (m_subtable[sumindex].m_usecount != 0 &&
+ m_subtable[sumindex].m_checksum == checksum &&
+ !memcmp(subtable, subtable_ptr(sumindex + SUBTABLE_BASE), 1 << level2_bits()))
{
int l1index;
VPRINTF(("Merging subtable %d and %d....\n", subindex, sumindex));
- /* find all the entries in the L1 tables that pointed to the old one, and point them to the merged table */
- for (l1index = 0; l1index <= (0xffffffffUL >> LEVEL2_BITS); l1index++)
- if (tabledata->table[l1index] == sumindex + SUBTABLE_BASE)
+ // find all the entries in the L1 tables that pointed to the old one, and point them to the merged table
+ for (l1index = 0; l1index <= (0xffffffffUL >> level2_bits()); l1index++)
+ if (m_table[l1index] == sumindex + SUBTABLE_BASE)
{
- subtable_release(tabledata, sumindex + SUBTABLE_BASE);
- subtable_realloc(tabledata, subindex + SUBTABLE_BASE);
- tabledata->table[l1index] = subindex + SUBTABLE_BASE;
+ subtable_release(sumindex + SUBTABLE_BASE);
+ subtable_realloc(subindex + SUBTABLE_BASE);
+ m_table[l1index] = subindex + SUBTABLE_BASE;
merged++;
}
}
@@ -2857,499 +3143,87 @@ static int subtable_merge(address_table *tabledata)
}
-/*-------------------------------------------------
- subtable_release - decrement the usecount on
- a subtable and free it if we're done
--------------------------------------------------*/
+//-------------------------------------------------
+// subtable_release - decrement the usecount on
+// a subtable and free it if we're done
+//-------------------------------------------------
-static void subtable_release(address_table *tabledata, UINT8 subentry)
+void address_table::subtable_release(UINT8 subentry)
{
UINT8 subindex = subentry - SUBTABLE_BASE;
- /* sanity check */
- if (tabledata->subtable[subindex].usecount <= 0)
+ // sanity check
+ if (m_subtable[subindex].m_usecount <= 0)
fatalerror("Called subtable_release on a table with a usecount of 0");
- /* decrement the usecount and clear the checksum if we're at 0 */
- tabledata->subtable[subindex].usecount--;
- if (tabledata->subtable[subindex].usecount == 0)
- tabledata->subtable[subindex].checksum = 0;
+ // decrement the usecount and clear the checksum if we're at 0
+ m_subtable[subindex].m_usecount--;
+ if (m_subtable[subindex].m_usecount == 0)
+ m_subtable[subindex].m_checksum = 0;
}
-/*-------------------------------------------------
- subtable_open - gain access to a subtable for
- modification
--------------------------------------------------*/
+//-------------------------------------------------
+// subtable_open - gain access to a subtable for
+// modification
+//-------------------------------------------------
-static UINT8 *subtable_open(address_table *tabledata, offs_t l1index)
+UINT8 *address_table::subtable_open(offs_t l1index)
{
- UINT8 subentry = tabledata->table[l1index];
+ UINT8 subentry = m_table[l1index];
- /* if we don't have a subtable yet, allocate a new one */
+ // if we don't have a subtable yet, allocate a new one
if (subentry < SUBTABLE_BASE)
{
- UINT8 newentry = subtable_alloc(tabledata);
- memset(SUBTABLE_PTR(tabledata, newentry), subentry, 1 << LEVEL2_BITS);
- tabledata->table[l1index] = newentry;
- tabledata->subtable[newentry - SUBTABLE_BASE].checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << LEVEL2_BITS)/4);
+ UINT8 newentry = subtable_alloc();
+ memset(subtable_ptr(newentry), subentry, 1 << level2_bits());
+ m_table[l1index] = newentry;
+ m_subtable[newentry - SUBTABLE_BASE].m_checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << level2_bits())/4);
subentry = newentry;
}
- /* if we're sharing this subtable, we also need to allocate a fresh copy */
- else if (tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1)
+ // if we're sharing this subtable, we also need to allocate a fresh copy
+ else if (m_subtable[subentry - SUBTABLE_BASE].m_usecount > 1)
{
- UINT8 newentry = subtable_alloc(tabledata);
+ UINT8 newentry = subtable_alloc();
- /* allocate may cause some additional merging -- look up the subentry again */
- /* when we're done; it should still require a split */
- subentry = tabledata->table[l1index];
+ // allocate may cause some additional merging -- look up the subentry again
+ // when we're done; it should still require a split
+ subentry = m_table[l1index];
assert(subentry >= SUBTABLE_BASE);
- assert(tabledata->subtable[subentry - SUBTABLE_BASE].usecount > 1);
+ assert(m_subtable[subentry - SUBTABLE_BASE].m_usecount > 1);
- memcpy(SUBTABLE_PTR(tabledata, newentry), SUBTABLE_PTR(tabledata, subentry), 1 << LEVEL2_BITS);
- subtable_release(tabledata, subentry);
- tabledata->table[l1index] = newentry;
- tabledata->subtable[newentry - SUBTABLE_BASE].checksum = tabledata->subtable[subentry - SUBTABLE_BASE].checksum;
+ memcpy(subtable_ptr(newentry), subtable_ptr(subentry), 1 << level2_bits());
+ subtable_release(subentry);
+ m_table[l1index] = newentry;
+ m_subtable[newentry - SUBTABLE_BASE].m_checksum = m_subtable[subentry - SUBTABLE_BASE].m_checksum;
subentry = newentry;
}
- /* mark the table dirty */
- tabledata->subtable[subentry - SUBTABLE_BASE].checksum_valid = 0;
-
- /* return the pointer to the subtable */
- return SUBTABLE_PTR(tabledata, subentry);
-}
-
-
-/*-------------------------------------------------
- subtable_close - stop access to a subtable
--------------------------------------------------*/
-
-static void subtable_close(address_table *tabledata, offs_t l1index)
-{
- /* defer any merging until we run out of tables */
-}
-
-
-
-/***************************************************************************
- DIRECT MEMORY RANGES
-***************************************************************************/
-
-/*-------------------------------------------------
- direct_range_find - find a byte address in
- a range
--------------------------------------------------*/
-
-static direct_range *direct_range_find(address_space *space, offs_t byteaddress, UINT8 *entry)
-{
- direct_range **rangelistptr;
- direct_range **rangeptr;
- direct_range *range;
-
- /* determine which entry */
- byteaddress &= space->bytemask;
- *entry = space->read.table[LEVEL1_INDEX(byteaddress)];
- if (*entry >= SUBTABLE_BASE)
- *entry = space->read.table[LEVEL2_INDEX(*entry, byteaddress)];
- rangelistptr = &space->direct.rangelist[*entry];
-
- /* scan our table */
- for (rangeptr = rangelistptr; *rangeptr != NULL; rangeptr = &(*rangeptr)->next)
- if (byteaddress >= (*rangeptr)->bytestart && byteaddress <= (*rangeptr)->byteend)
- {
- /* found a match; move us to the head of the list if we're not already there */
- range = *rangeptr;
- if (range != *rangelistptr)
- {
- *rangeptr = range->next;
- range->next = *rangelistptr;
- *rangelistptr = range;
- }
- return range;
- }
-
- /* didn't find out; allocate a new one */
- range = space->direct.freerangelist;
- if (range != NULL)
- space->direct.freerangelist = range->next;
- else
- range = auto_alloc(space->machine, direct_range);
-
- /* fill in the range */
- table_derive_range(&space->read, byteaddress, &range->bytestart, &range->byteend);
- range->next = *rangelistptr;
- *rangelistptr = range;
-
- return range;
-}
-
-
-/*-------------------------------------------------
- direct_range_remove_intersecting - remove
- all cached ranges that intersect the given
- address range
--------------------------------------------------*/
-
-static void direct_range_remove_intersecting(address_space *space, offs_t bytestart, offs_t byteend)
-{
- int entry;
-
- /* loop over all entries */
- for (entry = 0; entry < ARRAY_LENGTH(space->read.handlers); entry++)
- {
- direct_range **rangeptr, **nextrangeptr;
-
- /* loop over all ranges in this entry's list */
- for (nextrangeptr = rangeptr = &space->direct.rangelist[entry]; *rangeptr != NULL; rangeptr = nextrangeptr)
- {
- /* if we intersect, remove and add to the free range list */
- if (bytestart <= (*rangeptr)->byteend && byteend >= (*rangeptr)->bytestart)
- {
- direct_range *range = *rangeptr;
- *rangeptr = range->next;
- range->next = space->direct.freerangelist;
- space->direct.freerangelist = range;
- }
-
- /* otherwise advance to the next in the list */
- else
- nextrangeptr = &(*rangeptr)->next;
- }
- }
-}
-
-
-
-/***************************************************************************
- MEMORY BLOCK ALLOCATION
-***************************************************************************/
-
-/*-------------------------------------------------
- block_allocate - allocate a single
- memory block of data
--------------------------------------------------*/
-
-static void *block_allocate(const address_space *space, offs_t bytestart, offs_t byteend, void *memory)
-{
- memory_private *memdata = space->machine->memory_data;
- int allocatemem = (memory == NULL);
- memory_block *block;
- size_t bytestoalloc;
- const region_info *region;
-
- VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space->cpu->tag(), space->name, bytestart, byteend, memory));
-
- /* determine how much memory to allocate for this */
- bytestoalloc = sizeof(*block);
- if (allocatemem)
- bytestoalloc += byteend - bytestart + 1;
-
- /* allocate and clear the memory */
- block = (memory_block *)auto_alloc_array_clear(space->machine, UINT8, bytestoalloc);
- if (allocatemem)
- memory = block + 1;
-
- /* register for saving, but only if we're not part of a memory region */
- for (region = space->machine->m_regionlist.first(); region != NULL; region = region->next())
- {
- if ((UINT8 *)memory >= region->base() && ((UINT8 *)memory + (byteend - bytestart + 1)) < region->end())
- {
- VPRINTF(("skipping save of this memory block as it is covered by a memory region\n"));
- break;
- }
- }
-
- /* if we didn't find a match, register */
- if (region == NULL)
- {
- int bytes_per_element = space->dbits/8;
- char name[256];
-
- sprintf(name, "%08x-%08x", bytestart, byteend);
- state_save_register_memory(space->machine, "memory", space->cpu->tag(), space->spacenum, name, memory, bytes_per_element, (UINT32)(byteend - bytestart + 1) / bytes_per_element, __FILE__, __LINE__);
- }
-
- /* fill in the tracking block */
- block->space = space;
- block->isallocated = allocatemem;
- block->bytestart = bytestart;
- block->byteend = byteend;
- block->data = (UINT8 *)memory;
-
- /* attach us to the head of the list */
- block->next = memdata->memory_block_list;
- memdata->memory_block_list = block;
-
- return memory;
-}
-
-
-/*-------------------------------------------------
- block_assign_intersecting - find all
- intersecting blocks and assign their pointers
--------------------------------------------------*/
-
-static address_map_entry *block_assign_intersecting(address_space *space, offs_t bytestart, offs_t byteend, UINT8 *base)
-{
- memory_private *memdata = space->machine->memory_data;
- address_map_entry *entry, *unassigned = NULL;
-
- /* loop over the adjusted map and assign memory to any blocks we can */
- for (entry = space->map->m_entrylist; entry != NULL; entry = entry->m_next)
- {
- /* if we haven't assigned this block yet, see if we have a mapped shared pointer for it */
- if (entry->m_memory == NULL && entry->m_share != NULL)
- {
- void *shareptr = memdata->sharemap.find(entry->m_share);
- if (shareptr != UNMAPPED_SHARE_PTR)
- {
- entry->m_memory = shareptr;
- VPRINTF(("memory range %08X-%08X -> shared_ptr '%s' [%p]\n", entry->m_addrstart, entry->m_addrend, entry->m_share, entry->m_memory));
- }
- }
-
- /* otherwise, look for a match in this block */
- if (entry->m_memory == NULL && entry->m_bytestart >= bytestart && entry->m_byteend <= byteend)
- {
- entry->m_memory = base + (entry->m_bytestart - bytestart);
- VPRINTF(("memory range %08X-%08X -> found in block from %08X-%08X [%p]\n", entry->m_addrstart, entry->m_addrend, bytestart, byteend, entry->m_memory));
- }
-
- /* if we're the first match on a shared pointer, assign it now */
- if (entry->m_memory != NULL && entry->m_share != NULL)
- {
- void *shareptr = memdata->sharemap.find(entry->m_share);
- if (shareptr == UNMAPPED_SHARE_PTR)
- memdata->sharemap.add(entry->m_share, entry->m_memory, TRUE);
- }
-
- /* keep track of the first unassigned entry */
- if (entry->m_memory == NULL && unassigned == NULL && space_needs_backing_store(space, entry))
- unassigned = entry;
- }
-
- return unassigned;
-}
-
-
-
-/***************************************************************************
- INTERNAL HANDLERS
-***************************************************************************/
-
-/*-------------------------------------------------
- unmapped memory handlers
--------------------------------------------------*/
-
-static READ8_HANDLER( unmap_read8 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory byte read from %s\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset), space->addrchars));
- return space->unmap;
-}
-static READ16_HANDLER( unmap_read16 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory word read from %s & %04X\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*2), space->addrchars), mem_mask);
- return space->unmap;
-}
-static READ32_HANDLER( unmap_read32 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory dword read from %s & %08X\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*4), space->addrchars), mem_mask);
- return space->unmap;
-}
-static READ64_HANDLER( unmap_read64 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory qword read from %s & %s\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*8), space->addrchars), core_i64_hex_format(mem_mask, 16));
- return space->unmap;
-}
-
-static WRITE8_HANDLER( unmap_write8 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory byte write to %s = %02X\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset), space->addrchars), data);
-}
-static WRITE16_HANDLER( unmap_write16 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory word write to %s = %04X & %04X\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*2), space->addrchars), data, mem_mask);
-}
-static WRITE32_HANDLER( unmap_write32 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory dword write to %s = %08X & %08X\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*4), space->addrchars), data, mem_mask);
-}
-static WRITE64_HANDLER( unmap_write64 )
-{
- if (space->log_unmap && !space->debugger_access) logerror("%s: unmapped %s memory qword write to %s = %s & %s\n", cpuexec_describe_context(space->machine), space->name, core_i64_hex_format(memory_byte_to_address(space, offset*8), space->addrchars), core_i64_hex_format(data, 16), core_i64_hex_format(mem_mask, 16));
-}
-
-
-/*-------------------------------------------------
- no-op memory handlers
--------------------------------------------------*/
-
-static READ8_HANDLER( nop_read8 ) { return space->unmap; }
-static READ16_HANDLER( nop_read16 ) { return space->unmap; }
-static READ32_HANDLER( nop_read32 ) { return space->unmap; }
-static READ64_HANDLER( nop_read64 ) { return space->unmap; }
-
-static WRITE8_HANDLER( nop_write8 ) { }
-static WRITE16_HANDLER( nop_write16 ) { }
-static WRITE32_HANDLER( nop_write32 ) { }
-static WRITE64_HANDLER( nop_write64 ) { }
-
-
-/*-------------------------------------------------
- watchpoint memory handlers
--------------------------------------------------*/
-
-static READ8_HANDLER( watchpoint_read8 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->readlookup;
- UINT8 result;
-
- spacerw->cpu->debug()->memory_read_hook(*spacerw, offset, 0xff);
- spacerw->readlookup = space->read.table;
- result = read_byte_generic(spacerw, offset);
- spacerw->readlookup = oldtable;
- return result;
-}
-
-static READ16_HANDLER( watchpoint_read16 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->readlookup;
- UINT16 result;
-
- spacerw->cpu->debug()->memory_read_hook(*spacerw, offset << 1, mem_mask);
- spacerw->readlookup = spacerw->read.table;
- result = read_word_generic(spacerw, offset << 1, mem_mask);
- spacerw->readlookup = oldtable;
- return result;
-}
-
-static READ32_HANDLER( watchpoint_read32 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->readlookup;
- UINT32 result;
-
- spacerw->cpu->debug()->memory_read_hook(*spacerw, offset << 2, mem_mask);
- spacerw->readlookup = spacerw->read.table;
- result = read_dword_generic(spacerw, offset << 2, mem_mask);
- spacerw->readlookup = oldtable;
- return result;
-}
-
-static READ64_HANDLER( watchpoint_read64 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->readlookup;
- UINT64 result;
-
- spacerw->cpu->debug()->memory_read_hook(*spacerw, offset << 3, mem_mask);
- spacerw->readlookup = spacerw->read.table;
- result = read_qword_generic(spacerw, offset << 3, mem_mask);
- spacerw->readlookup = oldtable;
- return result;
-}
-
-static WRITE8_HANDLER( watchpoint_write8 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->writelookup;
-
- spacerw->cpu->debug()->memory_write_hook(*spacerw, offset, data, 0xff);
- spacerw->writelookup = spacerw->write.table;
- write_byte_generic(spacerw, offset, data);
- spacerw->writelookup = oldtable;
-}
-
-static WRITE16_HANDLER( watchpoint_write16 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->writelookup;
-
- spacerw->cpu->debug()->memory_write_hook(*spacerw, offset << 1, data, mem_mask);
- spacerw->writelookup = spacerw->write.table;
- write_word_generic(spacerw, offset << 1, data, mem_mask);
- spacerw->writelookup = oldtable;
-}
-
-static WRITE32_HANDLER( watchpoint_write32 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->writelookup;
-
- spacerw->cpu->debug()->memory_write_hook(*spacerw, offset << 2, data, mem_mask);
- spacerw->writelookup = spacerw->write.table;
- write_dword_generic(spacerw, offset << 2, data, mem_mask);
- spacerw->writelookup = oldtable;
-}
-
-static WRITE64_HANDLER( watchpoint_write64 )
-{
- address_space *spacerw = (address_space *)space;
- UINT8 *oldtable = spacerw->writelookup;
+ // mark the table dirty
+ m_subtable[subentry - SUBTABLE_BASE].m_checksum_valid = false;
- spacerw->cpu->debug()->memory_write_hook(*spacerw, offset << 3, data, mem_mask);
- spacerw->writelookup = spacerw->write.table;
- write_qword_generic(spacerw, offset << 3, data, mem_mask);
- spacerw->writelookup = oldtable;
+ // return the pointer to the subtable
+ return subtable_ptr(subentry);
}
-/*-------------------------------------------------
- get_static_handler - returns points to static
- memory handlers
--------------------------------------------------*/
+//-------------------------------------------------
+// subtable_close - stop access to a subtable
+//-------------------------------------------------
-static genf *get_static_handler(int handlerbits, int readorwrite, int which)
+void address_table::subtable_close(offs_t l1index)
{
- static const struct
- {
- UINT8 handlerbits;
- UINT8 handlernum;
- genf * read;
- genf * write;
- } static_handler_list[] =
- {
- { 8, STATIC_UNMAP, (genf *)unmap_read8, (genf *)unmap_write8 },
- { 8, STATIC_NOP, (genf *)nop_read8, (genf *)nop_write8 },
- { 8, STATIC_WATCHPOINT, (genf *)watchpoint_read8, (genf *)watchpoint_write8 },
-
- { 16, STATIC_UNMAP, (genf *)unmap_read16, (genf *)unmap_write16 },
- { 16, STATIC_NOP, (genf *)nop_read16, (genf *)nop_write16 },
- { 16, STATIC_WATCHPOINT, (genf *)watchpoint_read16, (genf *)watchpoint_write16 },
-
- { 32, STATIC_UNMAP, (genf *)unmap_read32, (genf *)unmap_write32 },
- { 32, STATIC_NOP, (genf *)nop_read32, (genf *)nop_write32 },
- { 32, STATIC_WATCHPOINT, (genf *)watchpoint_read32, (genf *)watchpoint_write32 },
-
- { 64, STATIC_UNMAP, (genf *)unmap_read64, (genf *)unmap_write64 },
- { 64, STATIC_NOP, (genf *)nop_read64, (genf *)nop_write64 },
- { 64, STATIC_WATCHPOINT, (genf *)watchpoint_read64, (genf *)watchpoint_write64 },
- };
- int tablenum;
-
- for (tablenum = 0; tablenum < sizeof(static_handler_list) / sizeof(static_handler_list[0]); tablenum++)
- if (static_handler_list[tablenum].handlerbits == handlerbits && static_handler_list[tablenum].handlernum == which)
- return readorwrite ? static_handler_list[tablenum].write : static_handler_list[tablenum].read;
-
- return NULL;
+ // defer any merging until we run out of tables
}
+//-------------------------------------------------
+// handler_name - return friendly string
+// description of a handler
+//-------------------------------------------------
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
-
-/*-------------------------------------------------
- handler_to_string - return friendly string
- description of a handler
--------------------------------------------------*/
-
-static const char *handler_to_string(const address_space *space, const address_table *table, UINT8 entry)
+const char *address_table::handler_name(UINT8 entry) const
{
static const char *const strings[] =
{
@@ -3387,1204 +3261,1342 @@ static const char *handler_to_string(const address_space *space, const address_t
"rom", "nop", "unmapped", "watchpoint"
};
- /* banks have names */
+ // banks have names
if (entry >= STATIC_BANK1 && entry <= STATIC_BANKMAX)
- {
- bank_info *info;
- for (info = space->machine->memory_data->banklist; info != NULL; info = info->next)
- if (info->index == entry)
- return info->name;
- }
+ for (memory_bank *info = m_space.m_machine.memory_data->banklist.first(); info != NULL; info = info->next())
+ if (info->index() == entry)
+ return info->name();
- /* constant strings for lower entries */
- if (entry < STATIC_COUNT)
+ // constant strings for lower entries
+ if (entry < ARRAY_LENGTH(strings))
return strings[entry];
+ else if (handler(entry).name() != NULL)
+ return handler(entry).name();
else
- return (table->handlers[entry]->name != NULL) ? table->handlers[entry]->name : "???";
+ return "???";
}
-/*-------------------------------------------------
- dump_map - dump the contents of a single
- address space
--------------------------------------------------*/
+//-------------------------------------------------
+// address_table_read - constructor
+//-------------------------------------------------
-static void dump_map(FILE *file, const address_space *space, const address_table *table)
+address_table_read::address_table_read(address_space &space, bool large)
+ : address_table(space, large)
{
- offs_t byteaddress, bytestart, byteend;
-
- /* dump generic information */
- fprintf(file, " Address bits = %d\n", space->abits);
- fprintf(file, " Data bits = %d\n", space->dbits);
- fprintf(file, " L1 bits = %d\n", LEVEL1_BITS);
- fprintf(file, " L2 bits = %d\n", LEVEL2_BITS);
- fprintf(file, " Address mask = %X\n", space->bytemask);
- fprintf(file, "\n");
-
- /* iterate over addresses */
- for (byteaddress = 0; byteaddress <= space->bytemask; byteaddress = byteend + 1)
+ // allocate handlers for each entry, prepopulating the bankptrs for banks
+ for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++)
{
- UINT8 entry = table_derive_range(table, byteaddress, &bytestart, &byteend);
- fprintf(file, "%08X-%08X = %02X: %s [offset=%08X]\n",
- bytestart, byteend, entry, handler_to_string(space, table, entry), table->handlers[entry]->bytestart);
+ UINT8 **bankptr = (entrynum >= STATIC_BANK1 && entrynum <= STATIC_BANKMAX) ? &space.m_machine.memory_data->bank_ptr[entrynum] : NULL;
+ m_handlers[entrynum] = auto_alloc(&space.m_machine, handler_entry_read(space.data_width(), space.endianness(), bankptr));
}
-}
+ // we have to allocate different object types based on the data bus width
+ switch (space.data_width())
+ {
+ // 8-bit case
+ case 8:
+ m_handlers[STATIC_UNMAP]->set_delegate(read8_delegate_create(address_table_read, unmap_r<UINT8>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(read8_delegate_create(address_table_read, nop_r<UINT8>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(read8_delegate_create(address_table_read, watchpoint_r<UINT8>, *this));
+ break;
-/*-------------------------------------------------
- mem_dump - internal memory dump
--------------------------------------------------*/
+ // 16-bit case
+ case 16:
+ m_handlers[STATIC_UNMAP]->set_delegate(read16_delegate_create(address_table_read, unmap_r<UINT16>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(read16_delegate_create(address_table_read, nop_r<UINT16>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(read16_delegate_create(address_table_read, watchpoint_r<UINT16>, *this));
+ break;
-static void mem_dump(running_machine *machine)
-{
- FILE *file;
+ // 32-bit case
+ case 32:
+ m_handlers[STATIC_UNMAP]->set_delegate(read32_delegate_create(address_table_read, unmap_r<UINT32>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(read32_delegate_create(address_table_read, nop_r<UINT32>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(read32_delegate_create(address_table_read, watchpoint_r<UINT32>, *this));
+ break;
- if (MEM_DUMP)
- {
- file = fopen("memdump.log", "w");
- if (file)
- {
- memory_dump(machine, file);
- fclose(file);
- }
+ // 64-bit case
+ case 64:
+ m_handlers[STATIC_UNMAP]->set_delegate(read64_delegate_create(address_table_read, unmap_r<UINT64>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(read64_delegate_create(address_table_read, nop_r<UINT64>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(read64_delegate_create(address_table_read, watchpoint_r<UINT64>, *this));
+ break;
}
-}
-
+ // reset the byte masks on the special handlers to open up the full address space for proper reporting
+ m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0);
+}
-/***************************************************************************
- INPUT PORT READ HANDLERS
-***************************************************************************/
-/*-------------------------------------------------
- input port handlers
--------------------------------------------------*/
+//-------------------------------------------------
+// address_table_read - destructor
+//-------------------------------------------------
-static UINT8 input_port_read8(const input_port_config *port, offs_t offset)
+address_table_read::~address_table_read()
{
- return input_port_read_direct(port);
+ for (int handnum = 0; handnum < ARRAY_LENGTH(m_handlers); handnum++)
+ auto_free(&m_space.m_machine, m_handlers[handnum]);
}
-static UINT16 input_port_read16(const input_port_config *port, offs_t offset, UINT16 mem_mask)
-{
- return input_port_read_direct(port);
-}
-static UINT32 input_port_read32(const input_port_config *port, offs_t offset, UINT32 mem_mask)
-{
- return input_port_read_direct(port);
-}
+//-------------------------------------------------
+// handler - return the generic handler entry for
+// this index
+//-------------------------------------------------
-static UINT64 input_port_read64(const input_port_config *port, offs_t offset, UINT64 mem_mask)
+handler_entry &address_table_read::handler(UINT32 index) const
{
- return input_port_read_direct(port);
+ assert(index < ARRAY_LENGTH(m_handlers));
+ return *m_handlers[index];
}
+//-------------------------------------------------
+// address_table_write - constructor
+//-------------------------------------------------
-/*-------------------------------------------------
- output port handlers
--------------------------------------------------*/
-
-static void input_port_write8(const input_port_config *port, offs_t offset, UINT8 data)
+address_table_write::address_table_write(address_space &space, bool large)
+ : address_table(space, large)
{
- input_port_write_direct(port, data, 0xff);
-}
+ // allocate handlers for each entry, prepopulating the bankptrs for banks
+ for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++)
+ {
+ UINT8 **bankptr = (entrynum >= STATIC_BANK1 && entrynum <= STATIC_BANKMAX) ? &space.m_machine.memory_data->bank_ptr[entrynum] : NULL;
+ m_handlers[entrynum] = auto_alloc(&space.m_machine, handler_entry_write(space.data_width(), space.endianness(), bankptr));
+ }
-static void input_port_write16(const input_port_config *port, offs_t offset, UINT16 data, UINT16 mem_mask)
-{
- input_port_write_direct(port, data, mem_mask);
-}
+ // we have to allocate different object types based on the data bus width
+ switch (space.data_width())
+ {
+ // 8-bit case
+ case 8:
+ m_handlers[STATIC_UNMAP]->set_delegate(write8_delegate_create(address_table_write, unmap_w<UINT8>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(write8_delegate_create(address_table_write, nop_w<UINT8>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(write8_delegate_create(address_table_write, watchpoint_w<UINT8>, *this));
+ break;
-static void input_port_write32(const input_port_config *port, offs_t offset, UINT32 data, UINT32 mem_mask)
-{
- input_port_write_direct(port, data, mem_mask);
-}
+ // 16-bit case
+ case 16:
+ m_handlers[STATIC_UNMAP]->set_delegate(write16_delegate_create(address_table_write, unmap_w<UINT16>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(write16_delegate_create(address_table_write, nop_w<UINT16>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(write16_delegate_create(address_table_write, watchpoint_w<UINT16>, *this));
+ break;
-static void input_port_write64(const input_port_config *port, offs_t offset, UINT64 data, UINT64 mem_mask)
-{
- input_port_write_direct(port, data, mem_mask);
-}
+ // 32-bit case
+ case 32:
+ m_handlers[STATIC_UNMAP]->set_delegate(write32_delegate_create(address_table_write, unmap_w<UINT32>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(write32_delegate_create(address_table_write, nop_w<UINT32>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(write32_delegate_create(address_table_write, watchpoint_w<UINT32>, *this));
+ break;
+ // 64-bit case
+ case 64:
+ m_handlers[STATIC_UNMAP]->set_delegate(write64_delegate_create(address_table_write, unmap_w<UINT64>, *this));
+ m_handlers[STATIC_NOP]->set_delegate(write64_delegate_create(address_table_write, nop_w<UINT64>, *this));
+ m_handlers[STATIC_WATCHPOINT]->set_delegate(write64_delegate_create(address_table_write, watchpoint_w<UINT64>, *this));
+ break;
+ }
+ // reset the byte masks on the special handlers to open up the full address space for proper reporting
+ m_handlers[STATIC_UNMAP]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
+ m_handlers[STATIC_WATCHPOINT]->configure(0, space.bytemask(), ~0);
+}
-/***************************************************************************
- STUB HANDLERS THAT MAP TO BYTE READS
-***************************************************************************/
-/*-------------------------------------------------
- stub_read8_from_16 - return a 16-bit
- value combined from one or more byte accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// address_table_write - destructor
+//-------------------------------------------------
-static READ16_HANDLER( stub_read8_from_16 )
+address_table_write::~address_table_write()
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT16 result = 0;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- result |= (*handler->subhandler.read.shandler8)((const address_space *)handler->subobject, offset) << shift;
- offset++;
- }
- return result;
+ for (int handnum = 0; handnum < ARRAY_LENGTH(m_handlers); handnum++)
+ auto_free(&m_space.m_machine, m_handlers[handnum]);
}
-/*-------------------------------------------------
- stub_read8_from_32 - return a 32-bit
- value combined from one or more byte accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// handler - return the generic handler entry for
+// this index
+//-------------------------------------------------
-static READ32_HANDLER( stub_read8_from_32 )
+handler_entry &address_table_write::handler(UINT32 index) const
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT32 result = 0;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- result |= (*handler->subhandler.read.shandler8)((const address_space *)handler->subobject, offset) << shift;
- offset++;
- }
- return result;
+ assert(index < ARRAY_LENGTH(m_handlers));
+ return *m_handlers[index];
}
-/*-------------------------------------------------
- stub_read8_from_64 - return a 64-bit
- value combined from one or more byte accesses
--------------------------------------------------*/
-static READ64_HANDLER( stub_read8_from_64 )
-{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT64 result = 0;
+//**************************************************************************
+// DIRECT MEMORY RANGES
+//**************************************************************************
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- result |= (UINT64)(*handler->subhandler.read.shandler8)((const address_space *)handler->subobject, offset) << shift;
- offset++;
- }
- return result;
-}
+//-------------------------------------------------
+// direct_read_data - constructor
+//-------------------------------------------------
+direct_read_data::direct_read_data(address_space &space)
+ : m_space(space),
+ m_raw(NULL),
+ m_decrypted(NULL),
+ m_bytemask(space.bytemask()),
+ m_bytestart(1),
+ m_byteend(0),
+ m_entry(STATIC_UNMAP)
+{
+}
+
-/*-------------------------------------------------
- stub_read16_from_32 - return a 32-bit
- value combined from one or more word accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// ~direct_read_data - destructor
+//-------------------------------------------------
-static READ32_HANDLER( stub_read16_from_32 )
+direct_read_data::~direct_read_data()
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT32 result = 0;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT16)(mem_mask >> shift) != 0)
- result |= (*handler->subhandler.read.shandler16)((const address_space *)handler->subobject, offset, mem_mask >> shift) << shift;
- offset++;
- }
- return result;
}
-/*-------------------------------------------------
- stub_read16_from_64 - return a 64-bit
- value combined from one or more word accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// set_direct_region - called by device cores to
+// update the opcode base for the given address
+//-------------------------------------------------
-static READ64_HANDLER( stub_read16_from_64 )
+bool direct_read_data::set_direct_region(offs_t &byteaddress)
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT64 result = 0;
-
- offset *= subunits;
- while (subunits-- != 0)
+ // allow overrides
+ offs_t overrideaddress = byteaddress;
+ if (!m_directupdate.isnull())
{
- int shift = *subshift++;
- if ((UINT16)(mem_mask >> shift) != 0)
- result |= (UINT64)(*handler->subhandler.read.shandler16)((const address_space *)handler->subobject, offset, mem_mask >> shift) << shift;
- offset++;
- }
- return result;
-}
+ overrideaddress = m_directupdate(*this, overrideaddress);
+ if (overrideaddress == ~0)
+ return true;
+ byteaddress = overrideaddress;
+ }
-/*-------------------------------------------------
- stub_read32_from_64 - return a 64-bit
- value combined from one or more dword accesses
--------------------------------------------------*/
+ // remove the masked bits (we'll put them back later)
+ offs_t maskedbits = overrideaddress & ~m_bytemask;
-static READ64_HANDLER( stub_read32_from_64 )
-{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
- UINT64 result = 0;
+ // find or allocate a matching range
+ direct_range *range = find_range(overrideaddress, m_entry);
- offset *= subunits;
- while (subunits-- != 0)
+ // if we don't map to a bank, return FALSE
+ if (m_entry < STATIC_BANK1 || m_entry >= STATIC_RAM)
{
- int shift = *subshift++;
- if ((UINT32)(mem_mask >> shift) != 0)
- result |= (UINT64)(*handler->subhandler.read.shandler32)((const address_space *)handler->subobject, offset, mem_mask >> shift) << shift;
- offset++;
+ // ensure future updates to land here as well until we get back into a bank
+ m_byteend = 0;
+ m_bytestart = 1;
+ return false;
}
- return result;
-}
+ // if no decrypted opcodes, point to the same base
+ UINT8 *base = m_space.m_machine.memory_data->bank_ptr[m_entry];
+ UINT8 *based = m_space.m_machine.memory_data->bankd_ptr[m_entry];
+ if (based == NULL)
+ based = base;
+ // compute the adjusted base
+ const handler_entry_read &handler = m_space.read().handler_read(m_entry);
+ m_bytemask = handler.bytemask();
+ m_raw = base - (handler.bytestart() & m_bytemask);
+ m_decrypted = based - (handler.bytestart() & m_bytemask);
+ m_bytestart = maskedbits | range->m_bytestart;
+ m_byteend = maskedbits | range->m_byteend;
+ return true;
+}
-/***************************************************************************
- STUB HANDLERS THAT MAP TO BYTE WRITES
-***************************************************************************/
-/*-------------------------------------------------
- stub_write8_from_16 - convert a 16-bit
- write to one or more byte accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// find_range - find a byte address in a range
+//-------------------------------------------------
-static WRITE16_HANDLER( stub_write8_from_16 )
+direct_read_data::direct_range *direct_read_data::find_range(offs_t byteaddress, UINT8 &entry)
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
+ // determine which entry
+ byteaddress &= m_space.m_bytemask;
+ entry = m_space.read().lookup_live(byteaddress);
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler8)((const address_space *)handler->subobject, offset, data >> shift);
- offset++;
- }
+ // scan our table
+ for (direct_range *range = m_rangelist[entry].first(); range != NULL; range = range->next())
+ if (byteaddress >= range->m_bytestart && byteaddress <= range->m_byteend)
+ return range;
+
+ // didn't find out; allocate a new one
+ direct_range *range = m_freerangelist.first();
+ if (range != NULL)
+ m_freerangelist.detach(*range);
+ else
+ range = auto_alloc(&m_space.m_machine, direct_range);
+
+ // fill in the range
+ m_space.read().derive_range(byteaddress, range->m_bytestart, range->m_byteend);
+ m_rangelist[entry].prepend(*range);
+
+ return range;
}
-/*-------------------------------------------------
- stub_write8_from_32 - convert a 32-bit
- write to one or more byte accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// remove_intersecting_ranges - remove all cached
+// ranges that intersect the given address range
+//-------------------------------------------------
-static WRITE32_HANDLER( stub_write8_from_32 )
+void direct_read_data::remove_intersecting_ranges(offs_t bytestart, offs_t byteend)
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
-
- offset *= subunits;
- while (subunits-- != 0)
+ // loop over all entries
+ for (int entry = 0; entry < ARRAY_LENGTH(m_rangelist); entry++)
{
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler8)((const address_space *)handler->subobject, offset, data >> shift);
- offset++;
+ // loop over all ranges in this entry's list
+ direct_range *nextrange;
+ for (direct_range *range = m_rangelist[entry].first(); range != NULL; range = nextrange)
+ {
+ nextrange = range->next();
+
+ // if we intersect, remove and add to the free range list
+ if (bytestart <= range->m_byteend && byteend >= range->m_bytestart)
+ {
+ m_rangelist[entry].detach(*range);
+ m_freerangelist.prepend(*range);
+ }
+ }
}
}
-/*-------------------------------------------------
- stub_write8_from_64 - convert a 64-bit
- write to one or more byte accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// set_direct_update - set a custom direct range
+// update callback
+//-------------------------------------------------
-static WRITE64_HANDLER( stub_write8_from_64 )
+direct_update_delegate direct_read_data::set_direct_update(direct_update_delegate function)
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT8)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler8)((const address_space *)handler->subobject, offset, data >> shift);
- offset++;
- }
+ direct_update_delegate old = m_directupdate;
+ m_directupdate = function;
+ return old;
}
-/*-------------------------------------------------
- stub_write16_from_32 - convert a 32-bit
- write to one or more word accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// explicit_configure - explicitly configure
+// the start/end/mask and the pointers from
+// within a custom callback
+//-------------------------------------------------
-static WRITE32_HANDLER( stub_write16_from_32 )
+void direct_read_data::explicit_configure(offs_t bytestart, offs_t byteend, offs_t bytemask, void *raw, void *decrypted)
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT16)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler16)((const address_space *)handler->subobject, offset, data >> shift, mem_mask >> shift);
- offset++;
- }
+ m_bytestart = bytestart;
+ m_byteend = byteend;
+ m_bytemask = bytemask;
+ m_raw = reinterpret_cast<UINT8 *>(raw);
+ m_decrypted = reinterpret_cast<UINT8 *>((decrypted == NULL) ? raw : decrypted);
+ m_raw -= bytestart & bytemask;
+ m_decrypted -= bytestart & bytemask;
}
-/*-------------------------------------------------
- stub_write16_from_64 - convert a 64-bit
- write to one or more word accesses
--------------------------------------------------*/
-static WRITE64_HANDLER( stub_write16_from_64 )
+//**************************************************************************
+// MEMORY BLOCK
+//**************************************************************************
+
+//-------------------------------------------------
+// memory_block - constructor
+//-------------------------------------------------
+
+memory_block::memory_block(address_space &space, offs_t bytestart, offs_t byteend, void *memory)
+ : m_next(NULL),
+ m_machine(space.m_machine),
+ m_space(space),
+ m_isallocated(memory == NULL),
+ m_bytestart(bytestart),
+ m_byteend(byteend),
+ m_data((memory != NULL) ? reinterpret_cast<UINT8 *>(memory) : auto_alloc_array_clear(&space.m_machine, UINT8, byteend + 1 - bytestart))
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
+ VPRINTF(("block_allocate('%s',%s,%08X,%08X,%p)\n", space.device().tag(), space.name(), bytestart, byteend, memory));
+
+ // register for saving, but only if we're not part of a memory region
+ const region_info *region;
+ for (region = space.m_machine.m_regionlist.first(); region != NULL; region = region->next())
+ if (m_data >= region->base() && (m_data + (byteend - bytestart + 1)) < region->end())
+ {
+ VPRINTF(("skipping save of this memory block as it is covered by a memory region\n"));
+ break;
+ }
- offset *= subunits;
- while (subunits-- != 0)
+ // if we didn't find a match, register
+ if (region == NULL)
{
- int shift = *subshift++;
- if ((UINT16)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler16)((const address_space *)handler->subobject, offset, data >> shift, mem_mask >> shift);
- offset++;
+ int bytes_per_element = space.data_width() / 8;
+ astring name;
+ name.printf("%08x-%08x", bytestart, byteend);
+ state_save_register_memory(&space.m_machine, "memory", space.device().tag(), space.spacenum(), name, m_data, bytes_per_element, (UINT32)(byteend + 1 - bytestart) / bytes_per_element, __FILE__, __LINE__);
}
}
-/*-------------------------------------------------
- stub_write32_from_64 - convert a 64-bit
- write to one or more word accesses
--------------------------------------------------*/
+//-------------------------------------------------
+// memory_block - destructor
+//-------------------------------------------------
-static WRITE64_HANDLER( stub_write32_from_64 )
+memory_block::~memory_block()
{
- const handler_data *handler = (const handler_data *)space;
- const UINT8 *subshift = handler->subshift;
- int subunits = handler->subunits;
-
- offset *= subunits;
- while (subunits-- != 0)
- {
- int shift = *subshift++;
- if ((UINT32)(mem_mask >> shift) != 0)
- (*handler->subhandler.write.shandler32)((const address_space *)handler->subobject, offset, data >> shift, mem_mask >> shift);
- offset++;
- }
+ if (m_isallocated)
+ auto_free(&m_machine, m_data);
}
-/***************************************************************************
- STUB ACCESSORS
-***************************************************************************/
+//**************************************************************************
+// MEMORY BANK
+//**************************************************************************
-/*-------------------------------------------------
- get_stub_handler - return the appropriate
- stub handler
--------------------------------------------------*/
+//-------------------------------------------------
+// memory_bank - constructor
+//-------------------------------------------------
-static memory_handler get_stub_handler(read_or_write readorwrite, int spacedbits, int handlerdbits)
+memory_bank::memory_bank(address_space &space, int index, offs_t bytestart, offs_t byteend, const char *tag)
+ : m_next(NULL),
+ m_machine(space.m_machine),
+ m_baseptr(&space.m_machine.memory_data->bank_ptr[index]),
+ m_basedptr(&space.m_machine.memory_data->bankd_ptr[index]),
+ m_index(index),
+ m_anonymous(tag == NULL),
+ m_bytestart(bytestart),
+ m_byteend(byteend),
+ m_curentry(BANK_ENTRY_UNSPECIFIED),
+ m_entry(NULL),
+ m_entry_count(0)
{
- memory_handler result = { 0 };
-
- /* read stubs */
- if (readorwrite == ROW_READ)
+ // generate an internal tag if we don't have one
+ if (tag == NULL)
{
- /* 16-bit read stubs */
- if (spacedbits == 16)
- {
- if (handlerdbits == 8)
- result.read.shandler16 = stub_read8_from_16;
- }
-
- /* 32-bit read stubs */
- else if (spacedbits == 32)
- {
- if (handlerdbits == 8)
- result.read.shandler32 = stub_read8_from_32;
- else if (handlerdbits == 16)
- result.read.shandler32 = stub_read16_from_32;
- }
-
- /* 64-bit read stubs */
- else if (spacedbits == 64)
- {
- if (handlerdbits == 8)
- result.read.shandler64 = stub_read8_from_64;
- else if (handlerdbits == 16)
- result.read.shandler64 = stub_read16_from_64;
- else if (handlerdbits == 32)
- result.read.shandler64 = stub_read32_from_64;
- }
+ m_tag.printf("~%d~", index);
+ m_name.printf("Internal bank #%d", index);
}
-
- /* write stubs */
- else if (readorwrite == ROW_WRITE)
+ else
{
- /* 16-bit write stubs */
- if (spacedbits == 16)
- {
- if (handlerdbits == 8)
- result.write.shandler16 = stub_write8_from_16;
- }
-
- /* 32-bit write stubs */
- else if (spacedbits == 32)
- {
- if (handlerdbits == 8)
- result.write.shandler32 = stub_write8_from_32;
- else if (handlerdbits == 16)
- result.write.shandler32 = stub_write16_from_32;
- }
-
- /* 64-bit write stubs */
- else if (spacedbits == 64)
- {
- if (handlerdbits == 8)
- result.write.shandler64 = stub_write8_from_64;
- else if (handlerdbits == 16)
- result.write.shandler64 = stub_write16_from_64;
- else if (handlerdbits == 32)
- result.write.shandler64 = stub_write32_from_64;
- }
+ m_tag.cpy(tag);
+ m_name.printf("Bank '%s'", tag);
}
- assert(result.read.generic != NULL);
- return result;
+ if (!m_anonymous && state_save_registration_allowed(&space.m_machine))
+ state_save_register_item(&space.m_machine, "memory", m_tag, 0, m_curentry);
}
+//-------------------------------------------------
+// memory_bank - destructor
+//-------------------------------------------------
-/***************************************************************************
- 8-BIT READ HANDLERS
-***************************************************************************/
-
-UINT8 memory_read_byte_8le(const address_space *space, offs_t address)
+memory_bank::~memory_bank()
{
- return read_byte_generic(space, address);
+ auto_free(&m_machine, m_entry);
}
-UINT8 memory_read_byte_8be(const address_space *space, offs_t address)
-{
- return read_byte_generic(space, address);
-}
-UINT16 memory_read_word_8le(const address_space *space, offs_t address)
-{
- UINT16 result = memory_read_byte_8le(space, address + 0) << 0;
- return result | (memory_read_byte_8le(space, address + 1) << 8);
-}
+//-------------------------------------------------
+// references_space - walk the list of references
+// to find a match against the provided space
+// and read/write
+//-------------------------------------------------
-UINT16 memory_read_word_masked_8le(const address_space *space, offs_t address, UINT16 mask)
+bool memory_bank::references_space(address_space &space, read_or_write readorwrite) const
{
- UINT16 result = 0;
- if (mask & 0x00ff) result |= memory_read_byte_8le(space, address + 0) << 0;
- if (mask & 0xff00) result |= memory_read_byte_8le(space, address + 1) << 8;
- return result;
+ for (bank_reference *ref = m_reflist.first(); ref != NULL; ref = ref->next())
+ if (ref->matches(space, readorwrite))
+ return true;
+ return false;
}
-UINT16 memory_read_word_8be(const address_space *space, offs_t address)
-{
- UINT16 result = memory_read_byte_8be(space, address + 0) << 8;
- return result | (memory_read_byte_8be(space, address + 1) << 0);
-}
-UINT16 memory_read_word_masked_8be(const address_space *space, offs_t address, UINT16 mask)
-{
- UINT16 result = 0;
- if (mask & 0xff00) result |= memory_read_byte_8be(space, address + 0) << 8;
- if (mask & 0x00ff) result |= memory_read_byte_8be(space, address + 1) << 0;
- return result;
-}
+//-------------------------------------------------
+// add_reference - add a new reference to the
+// given space
+//-------------------------------------------------
-UINT32 memory_read_dword_8le(const address_space *space, offs_t address)
+void memory_bank::add_reference(address_space &space, read_or_write readorwrite)
{
- UINT32 result = memory_read_word_8le(space, address + 0) << 0;
- return result | (memory_read_word_8le(space, address + 2) << 16);
+ // if we already have a reference, skip it
+ if (references_space(space, readorwrite))
+ return;
+ m_reflist.append(*auto_alloc(&space.m_machine, bank_reference(space, readorwrite)));
}
-UINT32 memory_read_dword_masked_8le(const address_space *space, offs_t address, UINT32 mask)
-{
- UINT32 result = 0;
- if (mask & 0x0000ffff) result |= memory_read_word_masked_8le(space, address + 0, mask >> 0) << 0;
- if (mask & 0xffff0000) result |= memory_read_word_masked_8le(space, address + 2, mask >> 16) << 16;
- return result;
-}
-UINT32 memory_read_dword_8be(const address_space *space, offs_t address)
-{
- UINT32 result = memory_read_word_8be(space, address + 0) << 16;
- return result | (memory_read_word_8be(space, address + 2) << 0);
-}
+//-------------------------------------------------
+// invalidate_references - force updates on all
+// referencing address spaces
+//-------------------------------------------------
-UINT32 memory_read_dword_masked_8be(const address_space *space, offs_t address, UINT32 mask)
+void memory_bank::invalidate_references()
{
- UINT32 result = 0;
- if (mask & 0xffff0000) result |= memory_read_word_masked_8be(space, address + 0, mask >> 16) << 16;
- if (mask & 0x0000ffff) result |= memory_read_word_masked_8be(space, address + 2, mask >> 0) << 0;
- return result;
+ // invalidate all the direct references to any referenced address spaces
+ for (bank_reference *ref = m_reflist.first(); ref != NULL; ref = ref->next())
+ ref->space().direct().force_update();
}
-UINT64 memory_read_qword_8le(const address_space *space, offs_t address)
-{
- UINT64 result = (UINT64)memory_read_dword_8le(space, address + 0) << 0;
- return result | ((UINT64)memory_read_dword_8le(space, address + 4) << 32);
-}
-UINT64 memory_read_qword_masked_8le(const address_space *space, offs_t address, UINT64 mask)
-{
- UINT64 result = 0;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_8le(space, address + 0, mask >> 0) << 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_8le(space, address + 4, mask >> 32) << 32;
- return result;
-}
+//-------------------------------------------------
+// set_base - set the bank base explicitly
+//-------------------------------------------------
-UINT64 memory_read_qword_8be(const address_space *space, offs_t address)
+void memory_bank::set_base(void *base)
{
- UINT64 result = (UINT64)memory_read_dword_8be(space, address + 0) << 32;
- return result | ((UINT64)memory_read_dword_8be(space, address + 4) << 0);
-}
+ // NULL is not an option
+ if (base == NULL)
+ throw emu_fatalerror("memory_bank::set_base called NULL base");
-UINT64 memory_read_qword_masked_8be(const address_space *space, offs_t address, UINT64 mask)
-{
- UINT64 result = 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_8be(space, address + 0, mask >> 32) << 32;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_8be(space, address + 4, mask >> 0) << 0;
- return result;
+ // set the base and invalidate any referencing spaces
+ *m_baseptr = reinterpret_cast<UINT8 *>(base);
+ invalidate_references();
}
+//-------------------------------------------------
+// set_base_decrypted - set the decrypted base
+// explicitly
+//-------------------------------------------------
-/***************************************************************************
- 8-BIT WRITE HANDLERS
-***************************************************************************/
-
-void memory_write_byte_8le(const address_space *space, offs_t address, UINT8 data)
+void memory_bank::set_base_decrypted(void *base)
{
- write_byte_generic(space, address, data);
-}
+ // NULL is not an option
+ if (base == NULL)
+ throw emu_fatalerror("memory_bank::set_base called NULL base");
-void memory_write_byte_8be(const address_space *space, offs_t address, UINT8 data)
-{
- write_byte_generic(space, address, data);
+ // set the base and invalidate any referencing spaces
+ *m_basedptr = reinterpret_cast<UINT8 *>(base);
+ invalidate_references();
}
-void memory_write_word_8le(const address_space *space, offs_t address, UINT16 data)
-{
- memory_write_byte_8le(space, address + 0, data >> 0);
- memory_write_byte_8le(space, address + 1, data >> 8);
-}
-void memory_write_word_masked_8le(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
-{
- if (mask & 0x00ff) memory_write_byte_8le(space, address + 0, data >> 0);
- if (mask & 0xff00) memory_write_byte_8le(space, address + 1, data >> 8);
-}
+//-------------------------------------------------
+// set_entry - set the base to a pre-configured
+// entry
+//-------------------------------------------------
-void memory_write_word_8be(const address_space *space, offs_t address, UINT16 data)
+void memory_bank::set_entry(int entrynum)
{
- memory_write_byte_8be(space, address + 0, data >> 8);
- memory_write_byte_8be(space, address + 1, data >> 0);
-}
+ // validate
+ if (m_anonymous)
+ throw emu_fatalerror("memory_bank::set_entry called for anonymous bank");
+ if (entrynum < 0 || entrynum >= m_entry_count)
+ throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum);
+ if (m_entry[entrynum].m_raw == NULL)
+ throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag.cstr(), entrynum);
-void memory_write_word_masked_8be(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
-{
- if (mask & 0xff00) memory_write_byte_8be(space, address + 0, data >> 8);
- if (mask & 0x00ff) memory_write_byte_8be(space, address + 1, data >> 0);
-}
+ // set both raw and decrypted values
+ m_curentry = entrynum;
+ *m_baseptr = m_entry[entrynum].m_raw;
+ *m_basedptr = m_entry[entrynum].m_decrypted;
-void memory_write_dword_8le(const address_space *space, offs_t address, UINT32 data)
-{
- memory_write_word_8le(space, address + 0, data >> 0);
- memory_write_word_8le(space, address + 2, data >> 16);
+ // invalidate referencing spaces
+ invalidate_references();
}
-void memory_write_dword_masked_8le(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
-{
- if (mask & 0x0000ffff) memory_write_word_masked_8le(space, address + 0, data >> 0, mask >> 0);
- if (mask & 0xffff0000) memory_write_word_masked_8le(space, address + 2, data >> 16, mask >> 16);
-}
-void memory_write_dword_8be(const address_space *space, offs_t address, UINT32 data)
-{
- memory_write_word_8be(space, address + 0, data >> 16);
- memory_write_word_8be(space, address + 2, data >> 0);
-}
+//-------------------------------------------------
+// expand_entries - expand the allocated array
+// of entries
+//-------------------------------------------------
-void memory_write_dword_masked_8be(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
+void memory_bank::expand_entries(int entrynum)
{
- if (mask & 0xffff0000) memory_write_word_masked_8be(space, address + 0, data >> 16, mask >> 16);
- if (mask & 0x0000ffff) memory_write_word_masked_8be(space, address + 2, data >> 0, mask >> 0);
-}
+ int newcount = entrynum + 1;
+
+ // allocate a new array and copy from the old one; zero out the new entries
+ bank_entry *newentry = auto_alloc_array(&m_machine, bank_entry, newcount);
+ memcpy(newentry, m_entry, sizeof(m_entry[0]) * m_entry_count);
+ memset(&newentry[m_entry_count], 0, (newcount - m_entry_count) * sizeof(m_entry[0]));
-void memory_write_qword_8le(const address_space *space, offs_t address, UINT64 data)
-{
- memory_write_dword_8le(space, address + 0, data >> 0);
- memory_write_dword_8le(space, address + 4, data >> 32);
+ // free the old array and set the updated values
+ auto_free(&m_machine, m_entry);
+ m_entry = newentry;
+ m_entry_count = newcount;
}
-void memory_write_qword_masked_8le(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
-{
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_8le(space, address + 0, data >> 0, mask >> 0);
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_8le(space, address + 4, data >> 32, mask >> 32);
-}
-void memory_write_qword_8be(const address_space *space, offs_t address, UINT64 data)
-{
- memory_write_dword_8be(space, address + 0, data >> 32);
- memory_write_dword_8be(space, address + 4, data >> 0);
-}
+//-------------------------------------------------
+// configure - configure an entry
+//-------------------------------------------------
-void memory_write_qword_masked_8be(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
+void memory_bank::configure(int entrynum, void *base)
{
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_8be(space, address + 0, data >> 32, mask >> 32);
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_8be(space, address + 4, data >> 0, mask >> 0);
-}
-
+ // must be positive
+ if (entrynum < 0)
+ throw emu_fatalerror("memory_bank::configure called with out-of-range entry %d", entrynum);
+ // if we haven't allocated this many entries yet, expand our array
+ if (entrynum >= m_entry_count)
+ expand_entries(entrynum);
-/***************************************************************************
- 16-BIT READ HANDLERS
-***************************************************************************/
+ // set the entry
+ m_entry[entrynum].m_raw = reinterpret_cast<UINT8 *>(base);
-UINT8 memory_read_byte_16le(const address_space *space, offs_t address)
-{
- UINT32 shift = (address & 1) * 8;
- return read_word_generic(space, address, 0xff << shift) >> shift;
+ // if the bank base is not configured, and we're the first entry, set us up
+ if (*m_baseptr == NULL && entrynum == 0)
+ *m_baseptr = m_entry[entrynum].m_raw;
}
-UINT8 memory_read_byte_16be(const address_space *space, offs_t address)
-{
- UINT32 shift = (~address & 1) * 8;
- return read_word_generic(space, address, 0xff << shift) >> shift;
-}
-UINT16 memory_read_word_16le(const address_space *space, offs_t address)
-{
- return read_word_generic(space, address, 0xffff);
-}
+//-------------------------------------------------
+// configure_decrypted - configure a decrypted
+// entry
+//-------------------------------------------------
-UINT16 memory_read_word_masked_16le(const address_space *space, offs_t address, UINT16 mask)
+void memory_bank::configure_decrypted(int entrynum, void *base)
{
- return read_word_generic(space, address, mask);
-}
+ // must be positive
+ if (entrynum < 0)
+ throw emu_fatalerror("memory_bank::configure called with out-of-range entry %d", entrynum);
-UINT16 memory_read_word_16be(const address_space *space, offs_t address)
-{
- return read_word_generic(space, address, 0xffff);
-}
+ // if we haven't allocated this many entries yet, expand our array
+ if (entrynum >= m_entry_count)
+ expand_entries(entrynum);
-UINT16 memory_read_word_masked_16be(const address_space *space, offs_t address, UINT16 mask)
-{
- return read_word_generic(space, address, mask);
-}
+ // set the entry
+ m_entry[entrynum].m_decrypted = reinterpret_cast<UINT8 *>(base);
-UINT32 memory_read_dword_16le(const address_space *space, offs_t address)
-{
- UINT32 result = memory_read_word_16le(space, address + 0) << 0;
- return result | (memory_read_word_16le(space, address + 2) << 16);
+ // if the bank base is not configured, and we're the first entry, set us up
+ if (*m_basedptr == NULL && entrynum == 0)
+ *m_basedptr = m_entry[entrynum].m_decrypted;
}
-UINT32 memory_read_dword_masked_16le(const address_space *space, offs_t address, UINT32 mask)
-{
- UINT32 result = 0;
- if (mask & 0x0000ffff) result |= memory_read_word_masked_16le(space, address + 0, mask >> 0) << 0;
- if (mask & 0xffff0000) result |= memory_read_word_masked_16le(space, address + 2, mask >> 16) << 16;
- return result;
-}
-UINT32 memory_read_dword_16be(const address_space *space, offs_t address)
-{
- UINT32 result = memory_read_word_16be(space, address + 0) << 16;
- return result | (memory_read_word_16be(space, address + 2) << 0);
-}
-UINT32 memory_read_dword_masked_16be(const address_space *space, offs_t address, UINT32 mask)
-{
- UINT32 result = 0;
- if (mask & 0xffff0000) result |= memory_read_word_masked_16be(space, address + 0, mask >> 16) << 16;
- if (mask & 0x0000ffff) result |= memory_read_word_masked_16be(space, address + 2, mask >> 0) << 0;
- return result;
-}
+//**************************************************************************
+// HANDLER ENTRY
+//**************************************************************************
-UINT64 memory_read_qword_16le(const address_space *space, offs_t address)
-{
- UINT64 result = (UINT64)memory_read_dword_16le(space, address + 0) << 0;
- return result | ((UINT64)memory_read_dword_16le(space, address + 4) << 32);
-}
+//-------------------------------------------------
+// handler_entry - constructor
+//-------------------------------------------------
-UINT64 memory_read_qword_masked_16le(const address_space *space, offs_t address, UINT64 mask)
+handler_entry::handler_entry(UINT8 width, endianness_t endianness, UINT8 **rambaseptr)
+ : m_populated(false),
+ m_datawidth(width),
+ m_endianness(endianness),
+ m_bytestart(0),
+ m_byteend(0),
+ m_bytemask(~0),
+ m_rambaseptr(rambaseptr),
+ m_subunits(0)
{
- UINT64 result = 0;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_16le(space, address + 0, mask >> 0) << 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_16le(space, address + 4, mask >> 32) << 32;
- return result;
}
-UINT64 memory_read_qword_16be(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// ~handler_entry - destructor
+//-------------------------------------------------
+
+handler_entry::~handler_entry()
{
- UINT64 result = (UINT64)memory_read_dword_16be(space, address + 0) << 32;
- return result | ((UINT64)memory_read_dword_16be(space, address + 4) << 0);
}
-UINT64 memory_read_qword_masked_16be(const address_space *space, offs_t address, UINT64 mask)
+
+//-------------------------------------------------
+// configure_subunits - configure the subunits
+// and subshift array to represent the provided
+// mask
+//-------------------------------------------------
+
+void handler_entry::configure_subunits(UINT64 handlermask, int handlerbits)
{
- UINT64 result = 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_16be(space, address + 0, mask >> 32) << 32;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_16be(space, address + 4, mask >> 0) << 0;
- return result;
+ UINT64 unitmask = ((UINT64)1 << handlerbits) - 1;
+ assert(handlermask != 0);
+
+ // compute the maximum possible subunits
+ int maxunits = m_datawidth / handlerbits;
+ assert(maxunits > 1);
+ assert(maxunits < ARRAY_LENGTH(m_subshift));
+
+ // walk the handlermask to find out how many we have
+ m_subunits = 0;
+ for (int unitnum = 0; unitnum < maxunits; unitnum++)
+ {
+ UINT64 scanmask = unitmask << (unitnum * handlerbits);
+ assert((handlermask & scanmask) == 0 || (handlermask & scanmask) == scanmask);
+ if ((handlermask & scanmask) != 0)
+ m_subunits++;
+ }
+
+ // then fill in the shifts based on the endianness
+ if (m_endianness == ENDIANNESS_LITTLE)
+ {
+ UINT8 *unitshift = &m_subshift[0];
+ for (int unitnum = 0; unitnum < maxunits; unitnum++)
+ if ((handlermask & (unitmask << (unitnum * handlerbits))) != 0)
+ *unitshift++ = unitnum * handlerbits;
+ }
+ else
+ {
+ UINT8 *unitshift = &m_subshift[m_subunits];
+ for (int unitnum = 0; unitnum < maxunits; unitnum++)
+ if ((handlermask & (unitmask << (unitnum * handlerbits))) != 0)
+ *--unitshift = unitnum * handlerbits;
+ }
}
-/***************************************************************************
- 16-BIT WRITE HANDLERS
-***************************************************************************/
+//**************************************************************************
+// HANDLER ENTRY READ
+//**************************************************************************
-void memory_write_byte_16le(const address_space *space, offs_t address, UINT8 data)
-{
- UINT32 shift = (address & 1) * 8;
- write_word_generic(space, address, data << shift, 0xff << shift);
-}
+//-------------------------------------------------
+// name - return the handler name, from the
+// appropriately-sized delegate
+//-------------------------------------------------
-void memory_write_byte_16be(const address_space *space, offs_t address, UINT8 data)
+const char *handler_entry_read::name() const
{
- UINT32 shift = (~address & 1) * 8;
- write_word_generic(space, address, data << shift, 0xff << shift);
+ switch (m_datawidth)
+ {
+ case 8: return m_read8.name();
+ case 16: return m_read16.name();
+ case 32: return m_read32.name();
+ case 64: return m_read64.name();
+ }
+ return NULL;
}
-void memory_write_word_16le(const address_space *space, offs_t address, UINT16 data)
-{
- write_word_generic(space, address, data, 0xffff);
-}
-void memory_write_word_masked_16le(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
-{
- write_word_generic(space, address, data, mask);
-}
+//-------------------------------------------------
+// set_delegate - set an 8-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
-void memory_write_word_16be(const address_space *space, offs_t address, UINT16 data)
+void handler_entry_read::set_delegate(read8_delegate delegate, UINT64 mask)
{
- write_word_generic(space, address, data, 0xffff);
-}
+ // error if no object
+ if (!delegate.has_object())
+ throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name());
-void memory_write_word_masked_16be(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
-{
- write_word_generic(space, address, data, mask);
+ // make sure this is a valid size
+ assert(m_datawidth >= 8);
+ m_read8 = delegate;
+
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 8)
+ {
+ configure_subunits(mask, 8);
+ if (m_datawidth == 16)
+ set_delegate(read16_delegate(read16_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_16_from_8>(delegate.name()), *this));
+ else if (m_datawidth == 32)
+ set_delegate(read32_delegate(read32_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_32_from_8>(delegate.name()), *this));
+ else if (m_datawidth == 64)
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_64_from_8>(delegate.name()), *this));
+ }
}
-void memory_write_dword_16le(const address_space *space, offs_t address, UINT32 data)
-{
- memory_write_word_16le(space, address + 0, data >> 0);
- memory_write_word_16le(space, address + 2, data >> 16);
-}
-void memory_write_dword_masked_16le(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
-{
- if (mask & 0x0000ffff) memory_write_word_masked_16le(space, address + 0, data >> 0, mask >> 0);
- if (mask & 0xffff0000) memory_write_word_masked_16le(space, address + 2, data >> 16, mask >> 16);
-}
+//-------------------------------------------------
+// set_delegate - set a 16-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
-void memory_write_dword_16be(const address_space *space, offs_t address, UINT32 data)
+void handler_entry_read::set_delegate(read16_delegate delegate, UINT64 mask)
{
- memory_write_word_16be(space, address + 0, data >> 16);
- memory_write_word_16be(space, address + 2, data >> 0);
-}
+ // error if no object
+ if (!delegate.has_object())
+ throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name());
-void memory_write_dword_masked_16be(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
-{
- if (mask & 0xffff0000) memory_write_word_masked_16be(space, address + 0, data >> 16, mask >> 16);
- if (mask & 0x0000ffff) memory_write_word_masked_16be(space, address + 2, data >> 0, mask >> 0);
-}
+ // make sure this is a valid size
+ assert(m_datawidth >= 16);
+ m_read16 = delegate;
-void memory_write_qword_16le(const address_space *space, offs_t address, UINT64 data)
-{
- memory_write_dword_16le(space, address + 0, data >> 0);
- memory_write_dword_16le(space, address + 4, data >> 32);
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 16)
+ {
+ configure_subunits(mask, 16);
+ if (m_datawidth == 32)
+ set_delegate(read32_delegate(read32_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_32_from_16>(delegate.name()), *this));
+ else if (m_datawidth == 64)
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_64_from_16>(delegate.name()), *this));
+ }
}
-void memory_write_qword_masked_16le(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
-{
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_16le(space, address + 0, data >> 0, mask >> 0);
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_16le(space, address + 4, data >> 32, mask >> 32);
-}
-void memory_write_qword_16be(const address_space *space, offs_t address, UINT64 data)
-{
- memory_write_dword_16be(space, address + 0, data >> 32);
- memory_write_dword_16be(space, address + 4, data >> 0);
-}
+//-------------------------------------------------
+// set_delegate - set a 32-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
-void memory_write_qword_masked_16be(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
+void handler_entry_read::set_delegate(read32_delegate delegate, UINT64 mask)
{
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_16be(space, address + 0, data >> 32, mask >> 32);
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_16be(space, address + 4, data >> 0, mask >> 0);
-}
+ // error if no object
+ if (!delegate.has_object())
+ throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name());
+ // make sure this is a valid size
+ assert(m_datawidth >= 32);
+ m_read32 = delegate;
+
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 32)
+ {
+ configure_subunits(mask, 16);
+ if (m_datawidth == 64)
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_64_from_32>(delegate.name()), *this));
+ }
+}
-/***************************************************************************
- 32-BIT READ HANDLERS
-***************************************************************************/
+//-------------------------------------------------
+// set_delegate - set a 64-bit delegate
+//-------------------------------------------------
-UINT8 memory_read_byte_32le(const address_space *space, offs_t address)
+void handler_entry_read::set_delegate(read64_delegate delegate, UINT64 mask)
{
- UINT32 shift = (address & 3) * 8;
- return read_dword_generic(space, address, 0xff << shift) >> shift;
-}
+ // error if no object
+ if (!delegate.has_object())
+ throw emu_fatalerror("Attempted to install delegate '%s' without a bound object", delegate.name());
-UINT8 memory_read_byte_32be(const address_space *space, offs_t address)
-{
- UINT32 shift = (~address & 3) * 8;
- return read_dword_generic(space, address, 0xff << shift) >> shift;
+ // make sure this is a valid size
+ assert(m_datawidth >= 64);
+ m_read64 = delegate;
}
-UINT16 memory_read_word_32le(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_legacy_func - configure a legacy address
+// space stub of the appropriate size
+//-------------------------------------------------
+
+void handler_entry_read::set_legacy_func(const address_space &space, read8_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (address & 2) * 8;
- return read_dword_generic(space, address, 0xffff << shift) >> shift;
+ m_legacy_handler.space8 = func;
+ m_legacy_object.space = &space;
+ set_delegate(read8_delegate(read8_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT16 memory_read_word_masked_32le(const address_space *space, offs_t address, UINT16 mask)
+void handler_entry_read::set_legacy_func(const address_space &space, read16_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (address & 2) * 8;
- return read_dword_generic(space, address, mask << shift) >> shift;
+ m_legacy_handler.space16 = func;
+ m_legacy_object.space = &space;
+ set_delegate(read16_delegate(read16_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT16 memory_read_word_32be(const address_space *space, offs_t address)
+void handler_entry_read::set_legacy_func(const address_space &space, read32_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (~address & 2) * 8;
- return read_dword_generic(space, address, 0xffff << shift) >> shift;
+ m_legacy_handler.space32 = func;
+ m_legacy_object.space = &space;
+ set_delegate(read32_delegate(read32_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT16 memory_read_word_masked_32be(const address_space *space, offs_t address, UINT16 mask)
+void handler_entry_read::set_legacy_func(const address_space &space, read64_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (~address & 2) * 8;
- return read_dword_generic(space, address, mask << shift) >> shift;
+ m_legacy_handler.space64 = func;
+ m_legacy_object.space = &space;
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_32le(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_legacy_func - configure a legacy device
+// stub of the appropriate size
+//-------------------------------------------------
+
+void handler_entry_read::set_legacy_func(device_t &device, read8_device_func func, const char *name, UINT64 mask)
{
- return read_dword_generic(space, address, 0xffffffff);
+ m_legacy_handler.device8 = func;
+ m_legacy_object.device = &device;
+ set_delegate(read8_delegate(read8_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_masked_32le(const address_space *space, offs_t address, UINT32 mask)
+void handler_entry_read::set_legacy_func(device_t &device, read16_device_func func, const char *name, UINT64 mask)
{
- return read_dword_generic(space, address, mask);
+ m_legacy_handler.device16 = func;
+ m_legacy_object.device = &device;
+ set_delegate(read16_delegate(read16_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_32be(const address_space *space, offs_t address)
+void handler_entry_read::set_legacy_func(device_t &device, read32_device_func func, const char *name, UINT64 mask)
{
- return read_dword_generic(space, address, 0xffffffff);
+ m_legacy_handler.device32 = func;
+ m_legacy_object.device = &device;
+ set_delegate(read32_delegate(read32_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_masked_32be(const address_space *space, offs_t address, UINT32 mask)
+void handler_entry_read::set_legacy_func(device_t &device, read64_device_func func, const char *name, UINT64 mask)
{
- return read_dword_generic(space, address, mask);
+ m_legacy_handler.device64 = func;
+ m_legacy_object.device = &device;
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_legacy>(name), *this), mask);
}
-UINT64 memory_read_qword_32le(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_ioport - configure an I/O port read stub
+// of the appropriate size
+//-------------------------------------------------
+
+void handler_entry_read::set_ioport(const input_port_config &ioport)
{
- UINT64 result = (UINT64)memory_read_dword_32le(space, address + 0) << 0;
- return result | ((UINT64)memory_read_dword_32le(space, address + 4) << 32);
+ m_ioport = &ioport;
+ if (m_datawidth == 8)
+ set_delegate(read8_delegate(read8_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_ioport<UINT8> >(ioport.tag), *this));
+ else if (m_datawidth == 16)
+ set_delegate(read16_delegate(read16_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_ioport<UINT16> >(ioport.tag), *this));
+ else if (m_datawidth == 32)
+ set_delegate(read32_delegate(read32_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_ioport<UINT32> >(ioport.tag), *this));
+ else if (m_datawidth == 64)
+ set_delegate(read64_delegate(read64_proto_delegate::_create_member<handler_entry_read, &handler_entry_read::read_stub_ioport<UINT64> >(ioport.tag), *this));
}
-UINT64 memory_read_qword_masked_32le(const address_space *space, offs_t address, UINT64 mask)
+
+//-------------------------------------------------
+// read_stub_16_from_8 - construct a 16-bit read
+// from 8-bit sources
+//-------------------------------------------------
+
+UINT16 handler_entry_read::read_stub_16_from_8(address_space &space, offs_t offset, UINT16 mask)
{
- UINT64 result = 0;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_32le(space, address + 0, mask >> 0) << 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_32le(space, address + 4, mask >> 32) << 32;
+ UINT16 result = 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ result |= m_read8(space, offset * m_subunits + index, mask8) << shift;
+ }
return result;
}
-UINT64 memory_read_qword_32be(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// read_stub_32_from_8 - construct a 32-bit read
+// from 8-bit sources
+//-------------------------------------------------
+
+UINT32 handler_entry_read::read_stub_32_from_8(address_space &space, offs_t offset, UINT32 mask)
{
- UINT64 result = (UINT64)memory_read_dword_32be(space, address + 0) << 32;
- return result | ((UINT64)memory_read_dword_32be(space, address + 4) << 0);
+ UINT32 result = 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ result |= m_read8(space, offset * m_subunits + index, mask8) << shift;
+ }
+ return result;
}
-UINT64 memory_read_qword_masked_32be(const address_space *space, offs_t address, UINT64 mask)
+
+//-------------------------------------------------
+// read_stub_64_from_8 - construct a 64-bit read
+// from 8-bit sources
+//-------------------------------------------------
+
+UINT64 handler_entry_read::read_stub_64_from_8(address_space &space, offs_t offset, UINT64 mask)
{
UINT64 result = 0;
- if (mask & U64(0xffffffff00000000)) result |= (UINT64)memory_read_dword_masked_32be(space, address + 0, mask >> 32) << 32;
- if (mask & U64(0x00000000ffffffff)) result |= (UINT64)memory_read_dword_masked_32be(space, address + 4, mask >> 0) << 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ result |= (UINT64)m_read8(space, offset * m_subunits + index, mask8) << shift;
+ }
return result;
}
+//-------------------------------------------------
+// read_stub_32_from_16 - construct a 32-bit read
+// from 16-bit sources
+//-------------------------------------------------
-/***************************************************************************
- 32-BIT WRITE HANDLERS
-***************************************************************************/
-
-void memory_write_byte_32le(const address_space *space, offs_t address, UINT8 data)
+UINT32 handler_entry_read::read_stub_32_from_16(address_space &space, offs_t offset, UINT32 mask)
{
- UINT32 shift = (address & 3) * 8;
- write_dword_generic(space, address, data << shift, 0xff << shift);
+ UINT32 result = 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT16 mask16 = mask >> shift;
+ if (mask16 != 0)
+ result |= m_read16(space, offset * m_subunits + index, mask16) << shift;
+ }
+ return result;
}
-void memory_write_byte_32be(const address_space *space, offs_t address, UINT8 data)
-{
- UINT32 shift = (~address & 3) * 8;
- write_dword_generic(space, address, data << shift, 0xff << shift);
-}
-void memory_write_word_32le(const address_space *space, offs_t address, UINT16 data)
-{
- UINT32 shift = (address & 2) * 8;
- write_dword_generic(space, address, data << shift, 0xffff << shift);
-}
+//-------------------------------------------------
+// read_stub_64_from_16 - construct a 64-bit read
+// from 16-bit sources
+//-------------------------------------------------
-void memory_write_word_masked_32le(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
+UINT64 handler_entry_read::read_stub_64_from_16(address_space &space, offs_t offset, UINT64 mask)
{
- UINT32 shift = (address & 2) * 8;
- write_dword_generic(space, address, data << shift, mask << shift);
+ UINT64 result = 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT16 mask16 = mask >> shift;
+ if (mask16 != 0)
+ result |= (UINT64)m_read16(space, offset * m_subunits + index, mask16) << shift;
+ }
+ return result;
}
-void memory_write_word_32be(const address_space *space, offs_t address, UINT16 data)
-{
- UINT32 shift = (~address & 2) * 8;
- write_dword_generic(space, address, data << shift, 0xffff << shift);
-}
-void memory_write_word_masked_32be(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
-{
- UINT32 shift = (~address & 2) * 8;
- write_dword_generic(space, address, data << shift, mask << shift);
-}
+//-------------------------------------------------
+// read_stub_64_from_32 - construct a 64-bit read
+// from 32-bit sources
+//-------------------------------------------------
-void memory_write_dword_32le(const address_space *space, offs_t address, UINT32 data)
+UINT64 handler_entry_read::read_stub_64_from_32(address_space &space, offs_t offset, UINT64 mask)
{
- write_dword_generic(space, address, data, 0xffffffff);
+ UINT64 result = 0;
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT32 mask32 = mask >> shift;
+ if (mask32 != 0)
+ result |= (UINT64)m_read32(space, offset * m_subunits + index, mask32) << shift;
+ }
+ return result;
}
-void memory_write_dword_masked_32le(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
-{
- write_dword_generic(space, address, data, mask);
-}
-void memory_write_dword_32be(const address_space *space, offs_t address, UINT32 data)
-{
- write_dword_generic(space, address, data, 0xffffffff);
-}
+//-------------------------------------------------
+// read_stub_legacy - perform a read using legacy
+// handler callbacks
+//-------------------------------------------------
-void memory_write_dword_masked_32be(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
+UINT8 handler_entry_read::read_stub_legacy(address_space &space, offs_t offset, UINT8 mask)
{
- write_dword_generic(space, address, data, mask);
+ return m_legacy_handler.space8(m_legacy_object.space, offset);
}
-void memory_write_qword_32le(const address_space *space, offs_t address, UINT64 data)
+UINT16 handler_entry_read::read_stub_legacy(address_space &space, offs_t offset, UINT16 mask)
{
- memory_write_dword_32le(space, address + 0, data >> 0);
- memory_write_dword_32le(space, address + 4, data >> 32);
+ return m_legacy_handler.space16(m_legacy_object.space, offset, mask);
}
-void memory_write_qword_masked_32le(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
+UINT32 handler_entry_read::read_stub_legacy(address_space &space, offs_t offset, UINT32 mask)
{
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_32le(space, address + 0, data >> 0, mask >> 0);
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_32le(space, address + 4, data >> 32, mask >> 32);
+ return m_legacy_handler.space32(m_legacy_object.space, offset, mask);
}
-void memory_write_qword_32be(const address_space *space, offs_t address, UINT64 data)
+UINT64 handler_entry_read::read_stub_legacy(address_space &space, offs_t offset, UINT64 mask)
{
- memory_write_dword_32be(space, address + 0, data >> 32);
- memory_write_dword_32be(space, address + 4, data >> 0);
+ return m_legacy_handler.space64(m_legacy_object.space, offset, mask);
}
-void memory_write_qword_masked_32be(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
-{
- if (mask & U64(0xffffffff00000000)) memory_write_dword_masked_32be(space, address + 0, data >> 32, mask >> 32);
- if (mask & U64(0x00000000ffffffff)) memory_write_dword_masked_32be(space, address + 4, data >> 0, mask >> 0);
-}
+//**************************************************************************
+// HANDLER ENTRY WRITE
+//**************************************************************************
-/***************************************************************************
- 64-BIT READ HANDLERS
-***************************************************************************/
+//-------------------------------------------------
+// name - return the handler name, from the
+// appropriately-sized delegate
+//-------------------------------------------------
-UINT8 memory_read_byte_64le(const address_space *space, offs_t address)
+const char *handler_entry_write::name() const
{
- UINT32 shift = (address & 7) * 8;
- return read_qword_generic(space, address, (UINT64)0xff << shift) >> shift;
+ switch (m_datawidth)
+ {
+ case 8: return m_write8.name();
+ case 16: return m_write16.name();
+ case 32: return m_write32.name();
+ case 64: return m_write64.name();
+ }
+ return NULL;
}
-UINT8 memory_read_byte_64be(const address_space *space, offs_t address)
-{
- UINT32 shift = (~address & 7) * 8;
- return read_qword_generic(space, address, (UINT64)0xff << shift) >> shift;
-}
-UINT16 memory_read_word_64le(const address_space *space, offs_t address)
+//-------------------------------------------------
+// set_delegate - set an 8-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
+
+void handler_entry_write::set_delegate(write8_delegate delegate, UINT64 mask)
{
- UINT32 shift = (address & 6) * 8;
- return read_qword_generic(space, address, (UINT64)0xffff << shift) >> shift;
+ assert(m_datawidth >= 8);
+ m_write8 = delegate;
+
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 8)
+ {
+ configure_subunits(mask, 8);
+ if (m_datawidth == 16)
+ set_delegate(write16_delegate(write16_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_16_from_8>(delegate.name()), *this));
+ else if (m_datawidth == 32)
+ set_delegate(write32_delegate(write32_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_32_from_8>(delegate.name()), *this));
+ else if (m_datawidth == 64)
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_64_from_8>(delegate.name()), *this));
+ }
}
-UINT16 memory_read_word_masked_64le(const address_space *space, offs_t address, UINT16 mask)
+
+//-------------------------------------------------
+// set_delegate - set a 16-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
+
+void handler_entry_write::set_delegate(write16_delegate delegate, UINT64 mask)
{
- UINT32 shift = (address & 6) * 8;
- return read_qword_generic(space, address, (UINT64)mask << shift) >> shift;
+ assert(m_datawidth >= 16);
+ m_write16 = delegate;
+
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 16)
+ {
+ configure_subunits(mask, 16);
+ if (m_datawidth == 32)
+ set_delegate(write32_delegate(write32_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_32_from_16>(delegate.name()), *this));
+ else if (m_datawidth == 64)
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_64_from_16>(delegate.name()), *this));
+ }
}
-UINT16 memory_read_word_64be(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_delegate - set a 32-bit delegate, and
+// configure a stub if necessary
+//-------------------------------------------------
+
+void handler_entry_write::set_delegate(write32_delegate delegate, UINT64 mask)
{
- UINT32 shift = (~address & 6) * 8;
- return read_qword_generic(space, address, (UINT64)0xffff << shift) >> shift;
+ assert(m_datawidth >= 32);
+ m_write32 = delegate;
+
+ // if mismatched bus width, configure a stub
+ if (m_datawidth != 32)
+ {
+ configure_subunits(mask, 16);
+ if (m_datawidth == 64)
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_64_from_32>(delegate.name()), *this));
+ }
}
-UINT16 memory_read_word_masked_64be(const address_space *space, offs_t address, UINT16 mask)
+
+//-------------------------------------------------
+// set_delegate - set a 64-bit delegate
+//-------------------------------------------------
+
+void handler_entry_write::set_delegate(write64_delegate delegate, UINT64 mask)
{
- UINT32 shift = (~address & 6) * 8;
- return read_qword_generic(space, address, (UINT64)mask << shift) >> shift;
+ assert(m_datawidth >= 64);
+ m_write64 = delegate;
}
-UINT32 memory_read_dword_64le(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_legacy_func - configure a legacy address
+// space stub of the appropriate size
+//-------------------------------------------------
+
+void handler_entry_write::set_legacy_func(const address_space &space, write8_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (address & 4) * 8;
- return read_qword_generic(space, address, (UINT64)0xffffffff << shift) >> shift;
+ m_legacy_handler.space8 = func;
+ m_legacy_object.space = &space;
+ set_delegate(write8_delegate(write8_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_masked_64le(const address_space *space, offs_t address, UINT32 mask)
+void handler_entry_write::set_legacy_func(const address_space &space, write16_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (address & 4) * 8;
- return read_qword_generic(space, address, (UINT64)mask << shift) >> shift;
+ m_legacy_handler.space16 = func;
+ m_legacy_object.space = &space;
+ set_delegate(write16_delegate(write16_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_64be(const address_space *space, offs_t address)
+void handler_entry_write::set_legacy_func(const address_space &space, write32_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (~address & 4) * 8;
- return read_qword_generic(space, address, (UINT64)0xffffffff << shift) >> shift;
+ m_legacy_handler.space32 = func;
+ m_legacy_object.space = &space;
+ set_delegate(write32_delegate(write32_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT32 memory_read_dword_masked_64be(const address_space *space, offs_t address, UINT32 mask)
+void handler_entry_write::set_legacy_func(const address_space &space, write64_space_func func, const char *name, UINT64 mask)
{
- UINT32 shift = (~address & 4) * 8;
- return read_qword_generic(space, address, (UINT64)mask << shift) >> shift;
+ m_legacy_handler.space64 = func;
+ m_legacy_object.space = &space;
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT64 memory_read_qword_64le(const address_space *space, offs_t address)
+
+//-------------------------------------------------
+// set_legacy_func - configure a legacy device
+// stub of the appropriate size
+//-------------------------------------------------
+
+void handler_entry_write::set_legacy_func(device_t &device, write8_device_func func, const char *name, UINT64 mask)
{
- return read_qword_generic(space, address, U64(0xffffffffffffffff));
+ m_legacy_handler.device8 = func;
+ m_legacy_object.device = &device;
+ set_delegate(write8_delegate(write8_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT64 memory_read_qword_masked_64le(const address_space *space, offs_t address, UINT64 mask)
+void handler_entry_write::set_legacy_func(device_t &device, write16_device_func func, const char *name, UINT64 mask)
{
- return read_qword_generic(space, address, mask);
+ m_legacy_handler.device16 = func;
+ m_legacy_object.device = &device;
+ set_delegate(write16_delegate(write16_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT64 memory_read_qword_64be(const address_space *space, offs_t address)
+void handler_entry_write::set_legacy_func(device_t &device, write32_device_func func, const char *name, UINT64 mask)
{
- return read_qword_generic(space, address, U64(0xffffffffffffffff));
+ m_legacy_handler.device32 = func;
+ m_legacy_object.device = &device;
+ set_delegate(write32_delegate(write32_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
-UINT64 memory_read_qword_masked_64be(const address_space *space, offs_t address, UINT64 mask)
+void handler_entry_write::set_legacy_func(device_t &device, write64_device_func func, const char *name, UINT64 mask)
{
- return read_qword_generic(space, address, mask);
+ m_legacy_handler.device64 = func;
+ m_legacy_object.device = &device;
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_legacy>(name), *this), mask);
}
+//-------------------------------------------------
+// set_ioport - configure an I/O port read stub
+// of the appropriate size
+//-------------------------------------------------
-/***************************************************************************
- 64-BIT WRITE HANDLERS
-***************************************************************************/
-
-void memory_write_byte_64le(const address_space *space, offs_t address, UINT8 data)
+void handler_entry_write::set_ioport(const input_port_config &ioport)
{
- UINT32 shift = (address & 7) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xff << shift);
+ m_ioport = &ioport;
+ if (m_datawidth == 8)
+ set_delegate(write8_delegate(write8_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_ioport<UINT8> >(ioport.tag), *this));
+ else if (m_datawidth == 16)
+ set_delegate(write16_delegate(write16_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_ioport<UINT16> >(ioport.tag), *this));
+ else if (m_datawidth == 32)
+ set_delegate(write32_delegate(write32_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_ioport<UINT32> >(ioport.tag), *this));
+ else if (m_datawidth == 64)
+ set_delegate(write64_delegate(write64_proto_delegate::_create_member<handler_entry_write, &handler_entry_write::write_stub_ioport<UINT64> >(ioport.tag), *this));
}
-void memory_write_byte_64be(const address_space *space, offs_t address, UINT8 data)
-{
- UINT32 shift = (~address & 7) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xff << shift);
-}
-void memory_write_word_64le(const address_space *space, offs_t address, UINT16 data)
-{
- UINT32 shift = (address & 6) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xffff << shift);
-}
+//-------------------------------------------------
+// write_stub_16_from_8 - construct a 16-bit write
+// from 8-bit sources
+//-------------------------------------------------
-void memory_write_word_masked_64le(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
+void handler_entry_write::write_stub_16_from_8(address_space &space, offs_t offset, UINT16 data, UINT16 mask)
{
- UINT32 shift = (address & 6) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)mask << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ m_write8(space, offset * m_subunits + index, data >> shift, mask8);
+ }
}
-void memory_write_word_64be(const address_space *space, offs_t address, UINT16 data)
-{
- UINT32 shift = (~address & 6) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xffff << shift);
-}
-void memory_write_word_masked_64be(const address_space *space, offs_t address, UINT16 data, UINT16 mask)
+//-------------------------------------------------
+// write_stub_32_from_8 - construct a 32-bit write
+// from 8-bit sources
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_32_from_8(address_space &space, offs_t offset, UINT32 data, UINT32 mask)
{
- UINT32 shift = (~address & 6) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)mask << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ m_write8(space, offset * m_subunits + index, data >> shift, mask8);
+ }
}
-void memory_write_dword_64le(const address_space *space, offs_t address, UINT32 data)
+
+//-------------------------------------------------
+// write_stub_64_from_8 - construct a 64-bit write
+// from 8-bit sources
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_64_from_8(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
{
- UINT32 shift = (address & 4) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xffffffff << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT8 mask8 = mask >> shift;
+ if (mask8 != 0)
+ m_write8(space, offset * m_subunits + index, data >> shift, mask8);
+ }
}
-void memory_write_dword_masked_64le(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
+
+//-------------------------------------------------
+// write_stub_32_from_16 - construct a 32-bit
+// write from 16-bit sources
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_32_from_16(address_space &space, offs_t offset, UINT32 data, UINT32 mask)
{
- UINT32 shift = (address & 4) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)mask << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT16 mask16 = mask >> shift;
+ if (mask16 != 0)
+ m_write16(space, offset * m_subunits + index, data >> shift, mask16);
+ }
}
-void memory_write_dword_64be(const address_space *space, offs_t address, UINT32 data)
+
+//-------------------------------------------------
+// write_stub_64_from_16 - construct a 64-bit
+// write from 16-bit sources
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_64_from_16(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
{
- UINT32 shift = (~address & 4) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)0xffffffff << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT16 mask16 = mask >> shift;
+ if (mask16 != 0)
+ m_write16(space, offset * m_subunits + index, data >> shift, mask16);
+ }
}
-void memory_write_dword_masked_64be(const address_space *space, offs_t address, UINT32 data, UINT32 mask)
+
+//-------------------------------------------------
+// write_stub_64_from_32 - construct a 64-bit
+// write from 32-bit sources
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_64_from_32(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
{
- UINT32 shift = (~address & 4) * 8;
- write_qword_generic(space, address, (UINT64)data << shift, (UINT64)mask << shift);
+ for (int index = 0; index < m_subunits; index++)
+ {
+ int shift = m_subshift[index];
+ UINT32 mask32 = mask >> shift;
+ if (mask32 != 0)
+ m_write32(space, offset * m_subunits + index, data >> shift, mask32);
+ }
}
-void memory_write_qword_64le(const address_space *space, offs_t address, UINT64 data)
+
+//-------------------------------------------------
+// write_stub_legacy - perform a write using
+// legacy handler callbacks
+//-------------------------------------------------
+
+void handler_entry_write::write_stub_legacy(address_space &space, offs_t offset, UINT8 data, UINT8 mask)
{
- write_qword_generic(space, address, data, U64(0xffffffffffffffff));
+ m_legacy_handler.space8(m_legacy_object.space, offset, data);
}
-void memory_write_qword_masked_64le(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
+void handler_entry_write::write_stub_legacy(address_space &space, offs_t offset, UINT16 data, UINT16 mask)
{
- write_qword_generic(space, address, data, mask);
+ m_legacy_handler.space16(m_legacy_object.space, offset, data, mask);
}
-void memory_write_qword_64be(const address_space *space, offs_t address, UINT64 data)
+void handler_entry_write::write_stub_legacy(address_space &space, offs_t offset, UINT32 data, UINT32 mask)
{
- write_qword_generic(space, address, data, U64(0xffffffffffffffff));
+ m_legacy_handler.space32(m_legacy_object.space, offset, data, mask);
}
-void memory_write_qword_masked_64be(const address_space *space, offs_t address, UINT64 data, UINT64 mask)
+void handler_entry_write::write_stub_legacy(address_space &space, offs_t offset, UINT64 data, UINT64 mask)
{
- write_qword_generic(space, address, data, mask);
+ m_legacy_handler.space64(m_legacy_object.space, offset, data, mask);
}