mirror of
https://github.com/holub/mame
synced 2025-06-02 10:59:52 +03:00
addrmap: Allow adding device-sourced memory maps in the main map. [O. Galibert]
Device-side, it only works for modern device. Declare the map with DECLARE_ADDRESS_MAP(name, width). It's a method which can be virtual but not static. In the implementation, define ADDRESS_MAP_MODERN, and define the map starting with DEVICE_ADDRESS_MAP_START(name, width, device_class). Rest is like a normal modern map. To include it in the memory map use: AM_DEVICE( "device tag", devicea_class, name ) Or for device with differing widths: AM_DEVICE8( "device tag", devicea_class, name, unitmask ) AM_DEVICE16( "device tag", devicea_class, name, unitmask ) AM_DEVICE32( "device tag", devicea_class, name, unitmask )
This commit is contained in:
parent
153595f716
commit
abc59bb3f8
@ -188,7 +188,7 @@ void address_map_entry::set_write_bank(const device_t &device, const char *tag)
|
|||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// set_readwrite_bank - set up a handler for
|
// set_readwrite_bank - set up a handler for
|
||||||
// writing to a memory bank
|
// reading and writing to a memory bank
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
void address_map_entry::set_readwrite_bank(const device_t &device, const char *tag)
|
void address_map_entry::set_readwrite_bank(const device_t &device, const char *tag)
|
||||||
@ -200,6 +200,29 @@ void address_map_entry::set_readwrite_bank(const device_t &device, const char *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// set_submap - set up a handler for
|
||||||
|
// retrieve a submap from a device
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void address_map_entry::set_submap(const device_t &device, const char *tag, address_map_delegate func, int bits, UINT64 mask)
|
||||||
|
{
|
||||||
|
if(!bits)
|
||||||
|
bits = m_map.m_databits;
|
||||||
|
|
||||||
|
assert(unitmask_is_appropriate(bits, mask, func.name()));
|
||||||
|
|
||||||
|
m_read.m_type = AMH_DEVICE_SUBMAP;
|
||||||
|
m_read.set_tag(device, tag);
|
||||||
|
m_read.m_mask = mask;
|
||||||
|
m_write.m_type = AMH_DEVICE_SUBMAP;
|
||||||
|
m_write.set_tag(device, tag);
|
||||||
|
m_write.m_mask = mask;
|
||||||
|
m_submap_delegate = func;
|
||||||
|
m_submap_bits = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// internal_set_handler - handler setters for
|
// internal_set_handler - handler setters for
|
||||||
// 8-bit read/write handlers
|
// 8-bit read/write handlers
|
||||||
@ -724,6 +747,23 @@ address_map::address_map(const device_t &device, address_spacenum spacenum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// address_map - constructor in the submap case
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
address_map::address_map(const device_t &device, address_map_entry *entry)
|
||||||
|
: m_spacenum(AS_PROGRAM),
|
||||||
|
m_databits(0xff),
|
||||||
|
m_unmapval(0),
|
||||||
|
m_globalmask(0)
|
||||||
|
{
|
||||||
|
// Retrieve the submap
|
||||||
|
entry->m_submap_delegate.late_bind(const_cast<device_t &>(device));
|
||||||
|
entry->m_submap_delegate(*this, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// ~address_map - destructor
|
// ~address_map - destructor
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
@ -797,3 +837,135 @@ address_map_entry64 *address_map::add(offs_t start, offs_t end, address_map_entr
|
|||||||
m_entrylist.append(*ptr);
|
m_entrylist.append(*ptr);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// uplift_submaps - propagate in the device submaps
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void address_map::uplift_submaps(running_machine &machine, device_t &device)
|
||||||
|
{
|
||||||
|
address_map_entry *prev = 0;
|
||||||
|
address_map_entry *entry = m_entrylist.first();
|
||||||
|
while (entry)
|
||||||
|
{
|
||||||
|
if (entry->m_read.m_type == AMH_DEVICE_SUBMAP)
|
||||||
|
{
|
||||||
|
const char *tag = entry->m_read.m_tag;
|
||||||
|
device_t *mapdevice = machine.device(tag);
|
||||||
|
if (mapdevice == NULL)
|
||||||
|
throw emu_fatalerror("Attempted to submap a non-existent device '%s' in space %d of device '%s'\n", tag, m_spacenum, device.tag());
|
||||||
|
// Grab the submap
|
||||||
|
address_map submap(*mapdevice, entry);
|
||||||
|
|
||||||
|
// Recursively uplift it if needed
|
||||||
|
submap.uplift_submaps(machine, *mapdevice);
|
||||||
|
|
||||||
|
// Compute the unit repartition characteristics
|
||||||
|
int entry_bits = entry->m_submap_bits;
|
||||||
|
if (!entry_bits)
|
||||||
|
entry_bits = m_databits;
|
||||||
|
|
||||||
|
int entry_bytes = entry_bits / 8;
|
||||||
|
int databytes = m_databits / 8;
|
||||||
|
|
||||||
|
offs_t mirror_address_mask = (databytes - 1) & ~(entry_bytes - 1);
|
||||||
|
|
||||||
|
UINT64 entry_mask = (2ULL << (entry_bits-1)) - 1;
|
||||||
|
|
||||||
|
int slot_offset[8];
|
||||||
|
int slot_count = 0;
|
||||||
|
int max_slot_count = m_databits / entry_bits;
|
||||||
|
|
||||||
|
UINT64 global_mask = entry->m_read.m_mask;
|
||||||
|
// zero means all
|
||||||
|
if (!global_mask)
|
||||||
|
global_mask = ~global_mask;
|
||||||
|
|
||||||
|
// mask consistency has already been checked in
|
||||||
|
// unitmask_is_appropriate, so one bit is enough
|
||||||
|
for (int slot=0; slot < max_slot_count; slot++)
|
||||||
|
if (global_mask & (1ULL << (slot * entry_bits)))
|
||||||
|
slot_offset[slot_count++] = slot * entry_bits;
|
||||||
|
|
||||||
|
// Merge in all the map contents in order
|
||||||
|
while (submap.m_entrylist.count())
|
||||||
|
{
|
||||||
|
address_map_entry *subentry = submap.m_entrylist.detach_head();
|
||||||
|
|
||||||
|
// Remap start and end
|
||||||
|
|
||||||
|
int start_offset = subentry->m_addrstart / entry_bytes;
|
||||||
|
int start_slot = start_offset % slot_count;
|
||||||
|
subentry->m_addrstart = entry->m_addrstart + (start_offset / slot_count) * databytes;
|
||||||
|
|
||||||
|
// Drop the entry if it ends up outside the range
|
||||||
|
if (subentry->m_addrstart > entry->m_addrend)
|
||||||
|
{
|
||||||
|
global_free(subentry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end_offset = subentry->m_addrend / entry_bytes;
|
||||||
|
int end_slot = end_offset % slot_count;
|
||||||
|
subentry->m_addrend = entry->m_addrstart + (end_offset / slot_count) * databytes + databytes - 1;
|
||||||
|
|
||||||
|
// Clip the entry to the end of the range
|
||||||
|
if (subentry->m_addrend > entry->m_addrend)
|
||||||
|
subentry->m_addrend = entry->m_addrend;
|
||||||
|
|
||||||
|
// Detect special unhandled case (range straddling
|
||||||
|
// slots, requiring splitting in multiple entries and
|
||||||
|
// unimplemented offset-add subunit handler)
|
||||||
|
if (subentry->m_addrstart + databytes - 1 != subentry->m_addrend &&
|
||||||
|
(start_slot != 0 || end_slot != slot_count - 1))
|
||||||
|
throw emu_fatalerror("uplift_submaps unhandled case: range straddling slots.\n");
|
||||||
|
|
||||||
|
if (entry->m_addrmask || subentry->m_addrmask)
|
||||||
|
throw emu_fatalerror("uplift_submaps unhandled case: address masks.\n");
|
||||||
|
|
||||||
|
if (subentry->m_addrmirror & mirror_address_mask)
|
||||||
|
throw emu_fatalerror("uplift_submaps unhandled case: address mirror bit within subentry.\n");
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
map_handler_data &mdata = data_entry ? subentry->m_write : subentry->m_read;
|
||||||
|
|
||||||
|
if (mdata.m_type == AMH_NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mdata.m_type != AMH_DEVICE_DELEGATE)
|
||||||
|
throw emu_fatalerror("Only normal read/write methods are accepted in device submaps.\n");
|
||||||
|
|
||||||
|
if (mdata.m_bits == 0 && entry_bits != m_databits)
|
||||||
|
mdata.m_bits = entry_bits;
|
||||||
|
|
||||||
|
UINT64 mask = 0;
|
||||||
|
if (entry_bits != m_databits)
|
||||||
|
{
|
||||||
|
UINT64 unitmask = mdata.m_mask ? mdata.m_mask : entry_mask;
|
||||||
|
for (int slot = start_slot; slot <= end_slot; slot++)
|
||||||
|
mask |= unitmask << slot_offset[slot];
|
||||||
|
}
|
||||||
|
mdata.m_mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the entry in the map
|
||||||
|
m_entrylist.insert_after(*subentry, prev);
|
||||||
|
prev = subentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
address_map_entry *to_delete = entry;
|
||||||
|
entry = entry->next();
|
||||||
|
m_entrylist.remove(*to_delete);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -64,7 +64,8 @@ enum map_handler_type
|
|||||||
AMH_LEGACY_SPACE_HANDLER,
|
AMH_LEGACY_SPACE_HANDLER,
|
||||||
AMH_LEGACY_DEVICE_HANDLER,
|
AMH_LEGACY_DEVICE_HANDLER,
|
||||||
AMH_PORT,
|
AMH_PORT,
|
||||||
AMH_BANK
|
AMH_BANK,
|
||||||
|
AMH_DEVICE_SUBMAP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -73,6 +74,9 @@ enum map_handler_type
|
|||||||
// TYPE DEFINITIONS
|
// TYPE DEFINITIONS
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
|
||||||
|
// submap retriever delegate
|
||||||
|
typedef delegate<void (address_map &, const device_t &)> address_map_delegate;
|
||||||
|
|
||||||
// address map handler data
|
// address map handler data
|
||||||
class map_handler_data
|
class map_handler_data
|
||||||
{
|
{
|
||||||
@ -133,6 +137,9 @@ public:
|
|||||||
void set_write_bank(const device_t &device, const char *tag);
|
void set_write_bank(const device_t &device, const char *tag);
|
||||||
void set_readwrite_bank(const device_t &device, const char *tag);
|
void set_readwrite_bank(const device_t &device, const char *tag);
|
||||||
|
|
||||||
|
// submap referencing
|
||||||
|
void set_submap(const device_t &device, const char *tag, address_map_delegate func, int bits, UINT64 mask);
|
||||||
|
|
||||||
// public state
|
// public state
|
||||||
address_map_entry * m_next; // pointer to the next entry
|
address_map_entry * m_next; // pointer to the next entry
|
||||||
address_map & m_map; // reference to our owning map
|
address_map & m_map; // reference to our owning map
|
||||||
@ -181,6 +188,9 @@ public:
|
|||||||
write32_device_func m_wdevice32; // 32-bit legacy device handler
|
write32_device_func m_wdevice32; // 32-bit legacy device handler
|
||||||
write64_device_func m_wdevice64; // 64-bit legacy device handler
|
write64_device_func m_wdevice64; // 64-bit legacy device handler
|
||||||
|
|
||||||
|
address_map_delegate m_submap_delegate;
|
||||||
|
int m_submap_bits;
|
||||||
|
|
||||||
// information used during processing
|
// information used during processing
|
||||||
void * m_memory; // pointer to memory backing this entry
|
void * m_memory; // pointer to memory backing this entry
|
||||||
offs_t m_bytestart; // byte-adjusted start address
|
offs_t m_bytestart; // byte-adjusted start address
|
||||||
@ -408,6 +418,7 @@ class address_map
|
|||||||
public:
|
public:
|
||||||
// construction/destruction
|
// construction/destruction
|
||||||
address_map(const device_t &device, address_spacenum spacenum);
|
address_map(const device_t &device, address_spacenum spacenum);
|
||||||
|
address_map(const device_t &device, address_map_entry *entry);
|
||||||
~address_map();
|
~address_map();
|
||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
@ -429,8 +440,9 @@ public:
|
|||||||
UINT8 m_unmapval; // unmapped memory value
|
UINT8 m_unmapval; // unmapped memory value
|
||||||
offs_t m_globalmask; // global mask
|
offs_t m_globalmask; // global mask
|
||||||
simple_list<address_map_entry> m_entrylist; // list of entries
|
simple_list<address_map_entry> m_entrylist; // list of entries
|
||||||
};
|
|
||||||
|
|
||||||
|
void uplift_submaps(running_machine &machine, device_t &device);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
@ -473,6 +485,10 @@ void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device) \
|
|||||||
#define ADDRESS_MAP_EXTERN(_name, _bits) \
|
#define ADDRESS_MAP_EXTERN(_name, _bits) \
|
||||||
extern void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device)
|
extern void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device)
|
||||||
|
|
||||||
|
// use this to declare an address map as a member of a modern device class
|
||||||
|
#define DECLARE_ADDRESS_MAP(_name, _bits) \
|
||||||
|
void _name(address_map &map, const device_t &device)
|
||||||
|
|
||||||
|
|
||||||
// global controls
|
// global controls
|
||||||
#define ADDRESS_MAP_GLOBAL_MASK(_mask) \
|
#define ADDRESS_MAP_GLOBAL_MASK(_mask) \
|
||||||
@ -627,6 +643,21 @@ void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device) \
|
|||||||
curentry->set_handler(device, _tag, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, (_class *)0), _unitmask); \
|
curentry->set_handler(device, _tag, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, (_class *)0), _unitmask); \
|
||||||
|
|
||||||
|
|
||||||
|
// device mapping
|
||||||
|
#define AM_DEVICE(_tag, _class, _handler) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 0, 0); \
|
||||||
|
|
||||||
|
#define AM_DEVICE8(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 8, _unitmask); \
|
||||||
|
|
||||||
|
#define AM_DEVICE16(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 16, _unitmask); \
|
||||||
|
|
||||||
|
#define AM_DEVICE32(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 32, _unitmask); \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// special-case accesses
|
// special-case accesses
|
||||||
#define AM_ROM \
|
#define AM_ROM \
|
||||||
curentry->set_read_type(AMH_ROM); \
|
curentry->set_read_type(AMH_ROM); \
|
||||||
@ -736,6 +767,16 @@ void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device) \
|
|||||||
map.configure(_space, _bits); \
|
map.configure(_space, _bits); \
|
||||||
typedef _class drivdata_class; \
|
typedef _class drivdata_class; \
|
||||||
|
|
||||||
|
#define DEVICE_ADDRESS_MAP_START(_name, _bits, _class) \
|
||||||
|
void _class :: _name(address_map &map, const device_t &device) \
|
||||||
|
{ \
|
||||||
|
typedef read##_bits##_delegate read_delegate; \
|
||||||
|
typedef write##_bits##_delegate write_delegate; \
|
||||||
|
address_map_entry##_bits *curentry = NULL; \
|
||||||
|
(void)curentry; \
|
||||||
|
map.configure(AS_PROGRAM, _bits); \
|
||||||
|
typedef _class drivdata_class; \
|
||||||
|
|
||||||
#define ADDRESS_MAP_END \
|
#define ADDRESS_MAP_END \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,6 +784,10 @@ void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device) \
|
|||||||
#define ADDRESS_MAP_EXTERN(_name, _bits) \
|
#define ADDRESS_MAP_EXTERN(_name, _bits) \
|
||||||
extern void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device)
|
extern void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device)
|
||||||
|
|
||||||
|
// use this to declare an address map as a member of a modern device class
|
||||||
|
#define DECLARE_ADDRESS_MAP(_name, _bits) \
|
||||||
|
void _name(address_map &map, const device_t &device)
|
||||||
|
|
||||||
|
|
||||||
// global controls
|
// global controls
|
||||||
#define ADDRESS_MAP_GLOBAL_MASK(_mask) \
|
#define ADDRESS_MAP_GLOBAL_MASK(_mask) \
|
||||||
@ -981,6 +1026,20 @@ void ADDRESS_MAP_NAME(_name)(address_map &map, const device_t &device) \
|
|||||||
curentry->set_handler(device, _tag, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, (_class *)0), _unitmask); \
|
curentry->set_handler(device, _tag, read32_delegate(&_class::_rhandler, #_class "::" #_rhandler, (_class *)0), write32_delegate(&_class::_whandler, #_class "::" #_whandler, (_class *)0), _unitmask); \
|
||||||
|
|
||||||
|
|
||||||
|
// device mapping
|
||||||
|
#define AM_DEVICE(_tag, _class, _handler) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 0, 0); \
|
||||||
|
|
||||||
|
#define AM_DEVICE8(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 8, _unitmask); \
|
||||||
|
|
||||||
|
#define AM_DEVICE16(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 16, _unitmask); \
|
||||||
|
|
||||||
|
#define AM_DEVICE32(_tag, _class, _handler, _unitmask) \
|
||||||
|
curentry->set_submap(device, _tag, address_map_delegate(&_class::_handler, #_class "::" #_handler, (_class *)0), 32, _unitmask); \
|
||||||
|
|
||||||
|
|
||||||
// special-case accesses
|
// special-case accesses
|
||||||
#define AM_ROM \
|
#define AM_ROM \
|
||||||
curentry->set_read_type(AMH_ROM); \
|
curentry->set_read_type(AMH_ROM); \
|
||||||
|
@ -2154,6 +2154,9 @@ void address_space::prepare_map()
|
|||||||
// allocate the address map
|
// allocate the address map
|
||||||
m_map = global_alloc(address_map(m_device, m_spacenum));
|
m_map = global_alloc(address_map(m_device, m_spacenum));
|
||||||
|
|
||||||
|
// merge in the submaps
|
||||||
|
m_map->uplift_submaps(machine(), m_device);
|
||||||
|
|
||||||
// extract global parameters specified by the map
|
// extract global parameters specified by the map
|
||||||
m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0;
|
m_unmap = (m_map->m_unmapval == 0) ? 0 : ~0;
|
||||||
if (m_map->m_globalmask != 0)
|
if (m_map->m_globalmask != 0)
|
||||||
@ -2366,6 +2369,9 @@ void address_space::populate_map_entry(const address_map_entry &entry, read_or_w
|
|||||||
(readorwrite == ROW_READ) ? data.m_tag : NULL,
|
(readorwrite == ROW_READ) ? data.m_tag : NULL,
|
||||||
(readorwrite == ROW_WRITE) ? data.m_tag : NULL);
|
(readorwrite == ROW_WRITE) ? data.m_tag : NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AMH_DEVICE_SUBMAP:
|
||||||
|
throw emu_fatalerror("Internal mapping error: leftover mapping of '%s'.\n", data.m_tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user