mirror of
https://github.com/holub/mame
synced 2025-07-05 09:57:47 +03:00
New AM_(DEV)SETOFFSET feature for address maps.
This commit is contained in:
parent
67328a0ccd
commit
e93e197bb1
@ -472,6 +472,21 @@ void address_map_entry::internal_set_handler(device_t &device, read64_delegate r
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// set_handler - handler setter for setoffset
|
||||
//-------------------------------------------------
|
||||
|
||||
void address_map_entry::set_handler(device_t &device, setoffset_delegate func)
|
||||
{
|
||||
assert(!func.isnull());
|
||||
m_setoffsethd.m_type = AMH_DEVICE_DELEGATE;
|
||||
m_setoffsethd.m_bits = 0;
|
||||
m_setoffsethd.m_mask = 0;
|
||||
m_setoffsethd.m_name = func.name();
|
||||
m_setoffsethd.m_devbase = &device;
|
||||
m_soproto = func;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// unitmask_is_appropriate - verify that the
|
||||
// provided unitmask is valid and expected
|
||||
@ -809,9 +824,9 @@ void address_map::uplift_submaps(running_machine &machine, device_t &device, dev
|
||||
subentry->m_addrmirror |= entry->m_addrmirror;
|
||||
|
||||
// Twiddle the unitmask on the data accessors that need it
|
||||
for (int data_entry = 0; data_entry < 2; data_entry++)
|
||||
for (int data_entry = 0; data_entry < 3; data_entry++)
|
||||
{
|
||||
map_handler_data &mdata = data_entry ? subentry->m_write : subentry->m_read;
|
||||
map_handler_data &mdata = (data_entry==0)? subentry->m_read : ((data_entry==1)? subentry->m_write : subentry->m_setoffsethd);
|
||||
|
||||
if (mdata.m_type == AMH_NONE)
|
||||
continue;
|
||||
|
@ -127,6 +127,9 @@ public:
|
||||
void set_write_bank(device_t &device, const char *tag);
|
||||
void set_readwrite_bank(device_t &device, const char *tag);
|
||||
|
||||
// set offset handler (only one version, since there is no data width to consider)
|
||||
void set_handler(device_t &device, setoffset_delegate func);
|
||||
|
||||
// submap referencing
|
||||
void set_submap(device_t &device, const char *tag, address_map_delegate func, int bits, UINT64 mask);
|
||||
|
||||
@ -142,6 +145,7 @@ public:
|
||||
offs_t m_addrmask; // mask bits
|
||||
map_handler_data m_read; // data for read handler
|
||||
map_handler_data m_write; // data for write handler
|
||||
map_handler_data m_setoffsethd; // data for setoffset handler
|
||||
const char * m_share; // tag of a shared memory block
|
||||
const char * m_region; // tag of region containing the memory backing this entry
|
||||
offs_t m_rgnoffs; // offset within the region
|
||||
@ -164,6 +168,7 @@ public:
|
||||
write32_space_func m_wspace32; // 32-bit legacy address space handler
|
||||
write64_space_func m_wspace64; // 64-bit legacy address space handler
|
||||
|
||||
setoffset_delegate m_soproto; // set offset proto-delegate
|
||||
address_map_delegate m_submap_delegate;
|
||||
int m_submap_bits;
|
||||
|
||||
@ -495,6 +500,11 @@ void _class :: _name(::address_map &map, device_t &device) \
|
||||
#define AM_READWRITE32(_rhandler, _whandler, _unitmask) \
|
||||
curentry->set_handler(device, read32_delegate(&drivdata_class::_rhandler, "driver_data::" #_rhandler, DEVICE_SELF, (drivdata_class *)0), write32_delegate(&drivdata_class::_whandler, "driver_data::" #_whandler, DEVICE_SELF, (drivdata_class *)0), _unitmask);
|
||||
|
||||
// driver set offset. Upcast to base class because there are no data width variants,
|
||||
// and the compiler complains if we don't do it explicitly
|
||||
#define AM_SETOFFSET(_handler) \
|
||||
((address_map_entry*)curentry)->set_handler(device, setoffset_delegate(&drivdata_class::_handler, "driver_data::" #_handler, DEVICE_SELF, (drivdata_class *)0));
|
||||
|
||||
// device reads
|
||||
#define AM_DEVREAD(_tag, _class, _handler) \
|
||||
curentry->set_handler(device, read_delegate(&_class::_handler, #_class "::" #_handler, _tag, (_class *)0));
|
||||
@ -525,6 +535,11 @@ void _class :: _name(::address_map &map, device_t &device) \
|
||||
#define AM_DEVREADWRITE32(_tag, _class, _rhandler, _whandler, _unitmask) \
|
||||
curentry->set_handler(device, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, _tag, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, _tag, (_class *)0), _unitmask);
|
||||
|
||||
// device set offset
|
||||
#define AM_DEVSETOFFSET(_tag, _class, _handler) \
|
||||
((address_map_entry*)curentry)->set_handler(device, setoffset_delegate(&_class::_handler, #_class "::" #_handler, _tag, (_class *)0));
|
||||
|
||||
|
||||
// device mapping
|
||||
#define AM_DEVICE(_tag, _class, _handler) \
|
||||
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 0, 0);
|
||||
|
143
src/emu/memory.c
143
src/emu/memory.c
@ -178,6 +178,25 @@
|
||||
specify the share 'tag' will use its memory as backing for all
|
||||
future buckets that specify AM_SHARE with the same 'tag'.
|
||||
|
||||
AM_SETOFFSET(setoffset)
|
||||
Specifies a handler for a 'set address' operation. The intended use case
|
||||
for this operation is to emulate a split-phase memory access: The caller
|
||||
(usually a CPU) sets the address bus lines using set_address. Some
|
||||
component may then react, for instance, by asserting a control line
|
||||
like WAIT before delivering the data on the data bus. The data bits are
|
||||
then sampled on the read operation or delivered on the write operation
|
||||
that must be called subsequently.
|
||||
It is not checked whether the address of the set_address operation
|
||||
matches the address of the subsequent read/write operation.
|
||||
The address map translates the address to a bucket and an offset,
|
||||
hence the name of the macro. If no handler is specified for a bucket,
|
||||
a set_address operation hitting that bucket returns silently.
|
||||
|
||||
AM_DEVSETOFFSET(tag, setoffset)
|
||||
Specifies a handler for a set_address operation, bound to the device
|
||||
specified by 'tag'.
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include <list>
|
||||
@ -521,6 +540,34 @@ private:
|
||||
legacy_info m_sublegacy_info[8];
|
||||
};
|
||||
|
||||
// ======================> handler_entry_setoffset
|
||||
// a setoffset-access-specific extension of handler_entry
|
||||
class handler_entry_setoffset : public handler_entry
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
handler_entry_setoffset()
|
||||
: handler_entry(0, ENDIANNESS_LITTLE, NULL)
|
||||
{
|
||||
}
|
||||
|
||||
const char *name() const { return m_setoffset.name(); }
|
||||
const char *subunit_name(int entry) const { return "no subunit"; }
|
||||
|
||||
// Call through only if the setoffset handler has been late-bound before
|
||||
// (i.e. if it was declared in the address map)
|
||||
void setoffset(address_space &space, offs_t offset) const { if (m_setoffset.has_object()) m_setoffset(space, offset); }
|
||||
|
||||
// configure delegate callbacks
|
||||
void set_delegate(setoffset_delegate delegate, UINT64 mask = 0) { m_setoffset = delegate; }
|
||||
|
||||
private:
|
||||
setoffset_delegate m_setoffset;
|
||||
// We do not have subunits for setoffset
|
||||
// Accordingly, we need not implement unused functions.
|
||||
void remove_subunit(int entry) { }
|
||||
};
|
||||
|
||||
// ======================> handler_entry_proxy
|
||||
|
||||
// A proxy class that contains an handler_entry_read or _write and forwards the setter calls
|
||||
@ -823,6 +870,60 @@ private:
|
||||
handler_entry_write * m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers
|
||||
};
|
||||
|
||||
// ======================> address_table_setoffset
|
||||
// setoffset access-specific version of an address table
|
||||
class address_table_setoffset : public address_table
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
address_table_setoffset(address_space &space, bool large)
|
||||
: address_table(space, large)
|
||||
{
|
||||
// allocate handlers for each entry, prepopulating the bankptrs for banks
|
||||
for (int entrynum = 0; entrynum < ARRAY_LENGTH(m_handlers); entrynum++)
|
||||
{
|
||||
m_handlers[entrynum] = auto_alloc(space.machine(), handler_entry_setoffset());
|
||||
}
|
||||
|
||||
// Watchpoints and unmap states do not make sense for setoffset
|
||||
m_handlers[STATIC_NOP]->set_delegate(setoffset_delegate(FUNC(address_table_setoffset::nop_so), this));
|
||||
m_handlers[STATIC_NOP]->configure(0, space.bytemask(), ~0);
|
||||
}
|
||||
|
||||
~address_table_setoffset()
|
||||
{
|
||||
for (int handnum = 0; handnum < ARRAY_LENGTH(m_handlers); handnum++)
|
||||
auto_free(m_space.machine(), m_handlers[handnum]);
|
||||
}
|
||||
|
||||
handler_entry &handler(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
|
||||
handler_entry_setoffset &handler_setoffset(UINT32 index) const { assert(index < ARRAY_LENGTH(m_handlers)); return *m_handlers[index]; }
|
||||
|
||||
// range getter
|
||||
handler_entry_proxy<handler_entry_setoffset> handler_map_range(offs_t bytestart, offs_t byteend, offs_t bytemask, offs_t bytemirror, UINT64 mask = 0) {
|
||||
std::list<UINT32> entries;
|
||||
setup_range(bytestart, byteend, bytemask, bytemirror, mask, entries);
|
||||
std::list<handler_entry_setoffset *> handlers;
|
||||
for (std::list<UINT32>::const_iterator i = entries.begin(); i != entries.end(); i++)
|
||||
handlers.push_back(&handler_setoffset(*i));
|
||||
return handler_entry_proxy<handler_entry_setoffset>(handlers, mask);
|
||||
}
|
||||
|
||||
private:
|
||||
// internal handlers
|
||||
// Setoffset does not allow for watchpoints, since we assume that a
|
||||
// corresponding read/write operation will follow, and the watchpoint will
|
||||
// apply for that operation
|
||||
// For the same reason it does not make sense to put a warning into the log
|
||||
// for unmapped locations, as this will be done by the read/write operation
|
||||
void nop_so(address_space &space, offs_t offset)
|
||||
{
|
||||
}
|
||||
|
||||
// internal state
|
||||
handler_entry_setoffset *m_handlers[TOTAL_MEMORY_BANKS]; // array of user-installed handlers
|
||||
};
|
||||
|
||||
|
||||
// ======================> address_space_specific
|
||||
|
||||
@ -840,13 +941,15 @@ class address_space_specific : public address_space
|
||||
// helpers to simplify core code
|
||||
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); }
|
||||
UINT32 setoffset_lookup(offs_t byteaddress) const { return _Large ? m_setoffset.lookup_live_large(byteaddress) : m_setoffset.lookup_live_small(byteaddress); }
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
address_space_specific(memory_manager &manager, device_memory_interface &memory, address_spacenum spacenum)
|
||||
: address_space(manager, memory, spacenum, _Large),
|
||||
m_read(*this, _Large),
|
||||
m_write(*this, _Large)
|
||||
m_write(*this, _Large),
|
||||
m_setoffset(*this, _Large)
|
||||
{
|
||||
#if (TEST_HANDLER)
|
||||
// test code to verify the read/write handlers are touching the correct bits
|
||||
@ -988,6 +1091,7 @@ public:
|
||||
// accessors
|
||||
virtual address_table_read &read() { return m_read; }
|
||||
virtual address_table_write &write() { return m_write; }
|
||||
virtual address_table_setoffset &setoffset() { return m_setoffset; }
|
||||
|
||||
// watchpoint control
|
||||
virtual void enable_read_watchpoints(bool enable = true) { m_read.enable_watchpoints(enable); }
|
||||
@ -1385,6 +1489,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Allows to announce a pending read or write operation on this address.
|
||||
// The user of the address_space calls a set_address operation which leads
|
||||
// to some particular set_offset operation for an entry in the address map.
|
||||
void set_address(offs_t address)
|
||||
{
|
||||
offs_t byteaddress = address & m_bytemask;
|
||||
UINT32 entry = setoffset_lookup(byteaddress);
|
||||
const handler_entry_setoffset &handler = m_setoffset.handler_setoffset(entry);
|
||||
|
||||
offs_t offset = handler.byteoffset(byteaddress);
|
||||
handler.setoffset(*this, offset / sizeof(_NativeType));
|
||||
}
|
||||
|
||||
// virtual access to these functions
|
||||
UINT8 read_byte(offs_t address) { return (NATIVE_BITS == 8) ? read_native(address & ~NATIVE_MASK) : read_direct<UINT8, true>(address, 0xff); }
|
||||
UINT16 read_word(offs_t address) { return (NATIVE_BITS == 16) ? read_native(address & ~NATIVE_MASK) : read_direct<UINT16, true>(address, 0xffff); }
|
||||
@ -1432,6 +1549,7 @@ public:
|
||||
|
||||
address_table_read m_read; // memory read lookup table
|
||||
address_table_write m_write; // memory write lookup table
|
||||
address_table_setoffset m_setoffset; // memory setoffset lookup table
|
||||
};
|
||||
|
||||
typedef address_space_specific<UINT8, ENDIANNESS_LITTLE, false> address_space_8le_small;
|
||||
@ -1890,6 +2008,7 @@ void address_space::populate_from_map(address_map *map)
|
||||
// map both read and write halves
|
||||
populate_map_entry(*entry, ROW_READ);
|
||||
populate_map_entry(*entry, ROW_WRITE);
|
||||
populate_map_entry_setoffset(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1984,6 +2103,15 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// populate_map_entry_setoffset - special case for setoffset
|
||||
//-------------------------------------------------
|
||||
|
||||
void address_space::populate_map_entry_setoffset(const address_map_entry &entry)
|
||||
{
|
||||
install_setoffset_handler(entry.m_addrstart, entry.m_addrend, entry.m_addrmask,
|
||||
entry.m_addrmirror, setoffset_delegate(entry.m_soproto, *entry.m_setoffsethd.m_devbase), entry.m_setoffsethd.m_mask);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// allocate_memory - determine all neighboring
|
||||
@ -2641,6 +2769,19 @@ UINT64 *address_space::install_legacy_readwrite_handler(offs_t addrstart, offs_t
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// install_setoffset_handler - install set_offset delegate handlers for the space
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void address_space::install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, setoffset_delegate handler, UINT64 unitmask)
|
||||
{
|
||||
VPRINTF(("address_space::install_setoffset_handler(%s-%s mask=%s mirror=%s, %s, %s)\n",
|
||||
core_i64_hex_format(addrstart, m_addrchars), core_i64_hex_format(addrend, m_addrchars),
|
||||
core_i64_hex_format(addrmask, m_addrchars), core_i64_hex_format(addrmirror, m_addrchars),
|
||||
handler.name(), core_i64_hex_format(unitmask, data_width() / 4)));
|
||||
|
||||
setoffset().handler_map_range(addrstart, addrend, addrmask, addrmirror, unitmask).set_delegate(handler);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// MEMORY MAPPING HELPERS
|
||||
|
@ -101,6 +101,7 @@ class address_space;
|
||||
class address_table;
|
||||
class address_table_read;
|
||||
class address_table_write;
|
||||
class address_table_setoffset;
|
||||
|
||||
|
||||
// offsets and addresses are 32-bit (for now...)
|
||||
@ -178,6 +179,10 @@ typedef device_delegate<void (address_space &, offs_t, UINT16, UINT16)> write16_
|
||||
typedef device_delegate<void (address_space &, offs_t, UINT32, UINT32)> write32_delegate;
|
||||
typedef device_delegate<void (address_space &, offs_t, UINT64, UINT64)> write64_delegate;
|
||||
|
||||
// ======================> setoffset_delegate
|
||||
|
||||
typedef device_delegate<void (address_space &, offs_t)> setoffset_delegate;
|
||||
|
||||
|
||||
// ======================> direct_read_data
|
||||
|
||||
@ -304,6 +309,7 @@ class address_space
|
||||
friend class address_table;
|
||||
friend class address_table_read;
|
||||
friend class address_table_write;
|
||||
friend class address_table_setoffset;
|
||||
friend class direct_read_data;
|
||||
friend class simple_list<address_space>;
|
||||
friend resource_pool_object<address_space>::~resource_pool_object();
|
||||
@ -387,6 +393,9 @@ public:
|
||||
virtual void write_qword_unaligned(offs_t byteaddress, UINT64 data) = 0;
|
||||
virtual void write_qword_unaligned(offs_t byteaddress, UINT64 data, UINT64 mask) = 0;
|
||||
|
||||
// Set address. This will invoke setoffset handlers for the respective entries.
|
||||
virtual void set_address(offs_t byteaddress) = 0;
|
||||
|
||||
// address-to-byte conversion helpers
|
||||
offs_t address_to_byte(offs_t address) const { return m_config.addr2byte(address); }
|
||||
offs_t address_to_byte_end(offs_t address) const { return m_config.addr2byte_end(address); }
|
||||
@ -446,6 +455,10 @@ public:
|
||||
|
||||
void install_device_delegate(offs_t addrstart, offs_t addrend, device_t &device, address_map_delegate &map, int bits = 0, UINT64 unitmask = 0);
|
||||
|
||||
// install setoffset handler
|
||||
void install_setoffset_handler(offs_t addrstart, offs_t addrend, setoffset_delegate sohandler, UINT64 unitmask = 0) { return install_setoffset_handler(addrstart, addrend, 0, 0, sohandler, unitmask); }
|
||||
void install_setoffset_handler(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, setoffset_delegate sohandler, UINT64 unitmask = 0);
|
||||
|
||||
// install new-style delegate handlers (short form)
|
||||
UINT8 *install_read_handler(offs_t addrstart, offs_t addrend, read8_delegate rhandler, UINT64 unitmask = 0) { return install_read_handler(addrstart, addrend, 0, 0, rhandler, unitmask); }
|
||||
UINT8 *install_write_handler(offs_t addrstart, offs_t addrend, write8_delegate whandler, UINT64 unitmask = 0) { return install_write_handler(addrstart, addrend, 0, 0, whandler, unitmask); }
|
||||
@ -540,7 +553,10 @@ private:
|
||||
// internal helpers
|
||||
virtual address_table_read &read() = 0;
|
||||
virtual address_table_write &write() = 0;
|
||||
virtual address_table_setoffset &setoffset() = 0;
|
||||
|
||||
void populate_map_entry(const address_map_entry &entry, read_or_write readorwrite);
|
||||
void populate_map_entry_setoffset(const address_map_entry &entry);
|
||||
void unmap_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, bool quiet);
|
||||
void *install_ram_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, read_or_write readorwrite, void *baseptr);
|
||||
void install_bank_generic(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, const char *rtag, const char *wtag);
|
||||
@ -940,6 +956,8 @@ private:
|
||||
#define DECLARE_READ64_MEMBER(name) UINT64 name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 mem_mask = U64(0xffffffffffffffff))
|
||||
#define DECLARE_WRITE64_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT64 data, ATTR_UNUSED UINT64 mem_mask = U64(0xffffffffffffffff))
|
||||
|
||||
#define SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset)
|
||||
#define DECLARE_SETOFFSET_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset)
|
||||
|
||||
// device delegate macros
|
||||
#define READ8_DELEGATE(_class, _member) read8_delegate(FUNC(_class::_member), this)
|
||||
|
Loading…
Reference in New Issue
Block a user