New AM_(DEV)SETOFFSET feature for address maps.

This commit is contained in:
Michael Zapf 2013-09-21 22:35:53 +00:00
parent 67328a0ccd
commit e93e197bb1
4 changed files with 192 additions and 3 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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)