mirror of
https://github.com/holub/mame
synced 2025-04-29 11:30:28 +03:00
1382 lines
43 KiB
C++
1382 lines
43 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Aaron Giles
|
|
/***************************************************************************
|
|
|
|
addrmap.cpp
|
|
|
|
Macros and helper functions for handling address map definitions.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "romload.h"
|
|
#include "validity.h"
|
|
|
|
|
|
//**************************************************************************
|
|
// PARAMETERS
|
|
//**************************************************************************
|
|
|
|
#define DETECT_OVERLAPPING_MEMORY (0)
|
|
|
|
/*-------------------------------------------------
|
|
core_i64_hex_format - i64 format printf helper
|
|
why isn't fatalerror going through the same
|
|
channels as logerror exactly?
|
|
-------------------------------------------------*/
|
|
|
|
static char *core_i64_hex_format(u64 value, u8 mindigits)
|
|
{
|
|
static char buffer[16][64];
|
|
// TODO: this can overflow - e.g. when a lot of unmapped writes are logged
|
|
static int index;
|
|
char *bufbase = &buffer[index++ % 16][0];
|
|
char *bufptr = bufbase;
|
|
s8 curdigit;
|
|
|
|
for (curdigit = 15; curdigit >= 0; curdigit--)
|
|
{
|
|
int nibble = (value >> (curdigit * 4)) & 0xf;
|
|
if (nibble != 0 || curdigit < mindigits)
|
|
{
|
|
mindigits = curdigit;
|
|
*bufptr++ = "0123456789ABCDEF"[nibble];
|
|
}
|
|
}
|
|
if (bufptr == bufbase)
|
|
*bufptr++ = '0';
|
|
*bufptr = 0;
|
|
|
|
return bufbase;
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// ADDRESS MAP ENTRY
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// address_map_entry - constructor
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t start, offs_t end)
|
|
: m_next(nullptr)
|
|
, m_map(map)
|
|
, m_devbase(device)
|
|
, m_addrstart(start)
|
|
, m_addrend(end)
|
|
, m_addrmirror(0)
|
|
, m_addrmask(0)
|
|
, m_addrselect(0)
|
|
, m_mask(0)
|
|
, m_cswidth(0)
|
|
, m_share(nullptr)
|
|
, m_region(nullptr)
|
|
, m_rgnoffs(0)
|
|
, m_rproto8(device)
|
|
, m_rproto16(device)
|
|
, m_rproto32(device)
|
|
, m_rproto64(device)
|
|
, m_wproto8(device)
|
|
, m_wproto16(device)
|
|
, m_wproto32(device)
|
|
, m_wproto64(device)
|
|
, m_rproto8m(device)
|
|
, m_rproto16m(device)
|
|
, m_rproto32m(device)
|
|
, m_rproto64m(device)
|
|
, m_wproto8m(device)
|
|
, m_wproto16m(device)
|
|
, m_wproto32m(device)
|
|
, m_wproto64m(device)
|
|
, m_rproto8s(device)
|
|
, m_rproto16s(device)
|
|
, m_rproto32s(device)
|
|
, m_rproto64s(device)
|
|
, m_wproto8s(device)
|
|
, m_wproto16s(device)
|
|
, m_wproto32s(device)
|
|
, m_wproto64s(device)
|
|
, m_rproto8sm(device)
|
|
, m_rproto16sm(device)
|
|
, m_rproto32sm(device)
|
|
, m_rproto64sm(device)
|
|
, m_wproto8sm(device)
|
|
, m_wproto16sm(device)
|
|
, m_wproto32sm(device)
|
|
, m_wproto64sm(device)
|
|
, m_rproto8mo(device)
|
|
, m_rproto16mo(device)
|
|
, m_rproto32mo(device)
|
|
, m_rproto64mo(device)
|
|
, m_wproto8mo(device)
|
|
, m_wproto16mo(device)
|
|
, m_wproto32mo(device)
|
|
, m_wproto64mo(device)
|
|
, m_rproto8smo(device)
|
|
, m_rproto16smo(device)
|
|
, m_rproto32smo(device)
|
|
, m_rproto64smo(device)
|
|
, m_wproto8smo(device)
|
|
, m_wproto16smo(device)
|
|
, m_wproto32smo(device)
|
|
, m_wproto64smo(device)
|
|
, m_submap_device(nullptr)
|
|
, m_memory(nullptr)
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// mask - set the address mask value
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::mask(offs_t _mask)
|
|
{
|
|
m_addrmask = _mask;
|
|
if (m_map.m_globalmask != 0)
|
|
m_addrmask &= m_map.m_globalmask;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// umask16 - set a 16-bits unitmask value
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::umask16(u16 _mask)
|
|
{
|
|
m_mask = (u64(_mask) << 48) | (u64(_mask) << 32) | (u64(_mask) << 16) | _mask;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// umask32 - set a 32-bits unitmask value
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::umask32(u32 _mask)
|
|
{
|
|
m_mask = (u64(_mask) << 32) | _mask;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// umask64 - set a 64-bits unitmask value
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::umask64(u64 _mask)
|
|
{
|
|
m_mask = _mask;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// m - set up a handler for
|
|
// retrieve a submap from a device
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::m(const char *tag, address_map_constructor func)
|
|
{
|
|
m_read.m_type = AMH_DEVICE_SUBMAP;
|
|
m_read.m_tag = tag;
|
|
m_write.m_type = AMH_DEVICE_SUBMAP;
|
|
m_write.m_tag = tag;
|
|
m_submap_device = nullptr;
|
|
m_submap_delegate = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::m(device_t *device, address_map_constructor func)
|
|
{
|
|
m_read.m_type = AMH_DEVICE_SUBMAP;
|
|
m_read.m_tag = nullptr;
|
|
m_write.m_type = AMH_DEVICE_SUBMAP;
|
|
m_write.m_tag = nullptr;
|
|
m_submap_device = device;
|
|
m_submap_delegate = func;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// r/w/rw - handler setters for
|
|
// 8-bit read/write delegates
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::r(read8_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read8m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read8s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read8sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read8mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read8smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_read.m_bits = 8;
|
|
m_read.m_name = func.name();
|
|
m_rproto8smo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write8smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_write.m_bits = 8;
|
|
m_write.m_name = func.name();
|
|
m_wproto8smo = func;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// r/w/rw - handler setters for
|
|
// 16-bit read/write delegates
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::r(read16_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read16m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read16s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read16sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read16mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read16smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_read.m_bits = 16;
|
|
m_read.m_name = func.name();
|
|
m_rproto16smo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write16smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_write.m_bits = 16;
|
|
m_write.m_name = func.name();
|
|
m_wproto16smo = func;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// r/w/rw - handler setters for
|
|
// 32-bit read/write delegates
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::r(read32_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read32m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read32s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read32sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read32mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read32smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_read.m_bits = 32;
|
|
m_read.m_name = func.name();
|
|
m_rproto32smo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write32smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_write.m_bits = 32;
|
|
m_write.m_name = func.name();
|
|
m_wproto32smo = func;
|
|
return *this;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// r/w/rw - handler setters for
|
|
// 64-bit read/write delegates
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map_entry::r(read64_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64 = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read64m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64m_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_M;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64m = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read64s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64s_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_S;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64s = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read64sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64sm_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SM;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64sm = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read64mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64mo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_MO;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64mo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::r(read64smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_read.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_read.m_bits = 64;
|
|
m_read.m_name = func.name();
|
|
m_rproto64smo = func;
|
|
return *this;
|
|
}
|
|
|
|
address_map_entry &address_map_entry::w(write64smo_delegate func)
|
|
{
|
|
assert(!func.isnull());
|
|
m_write.m_type = AMH_DEVICE_DELEGATE_SMO;
|
|
m_write.m_bits = 64;
|
|
m_write.m_name = func.name();
|
|
m_wproto64smo = func;
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// unitmask_is_appropriate - verify that the
|
|
// provided unitmask is valid and expected
|
|
//-------------------------------------------------
|
|
|
|
bool address_map_entry::unitmask_is_appropriate(u8 width, u64 unitmask, const char *string) const
|
|
{
|
|
#if 0
|
|
// if no mask, this must match the default width of the map
|
|
if (unitmask == 0)
|
|
{
|
|
if (m_map.m_databits != width)
|
|
{
|
|
osd_printf_error("Handler %s is a %d-bit handler but was specified in a %d-bit address map\n", string, width, m_map.m_databits);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// if we have a mask, we must be smaller than the default width of the map
|
|
if (m_map.m_databits < width)
|
|
{
|
|
osd_printf_error("Handler %s is a %d-bit handler and is too wide to be used in a %d-bit address map\n", string, width, m_map.m_databits);
|
|
return false;
|
|
}
|
|
|
|
// if map is narrower than 64 bits, check the mask width as well
|
|
if (m_map.m_databits < 64 && (unitmask >> m_map.m_databits) != 0)
|
|
{
|
|
osd_printf_error("Handler %s specified a mask of %016X, too wide to be used in a %d-bit address map\n", string, unitmask, m_map.m_databits);
|
|
return false;
|
|
}
|
|
|
|
// the mask must represent whole units of width
|
|
u32 basemask = (width == 8) ? 0xff : (width == 16) ? 0xffff : 0xffffffff;
|
|
u64 singlemask = basemask;
|
|
int count = 0;
|
|
while (singlemask != 0)
|
|
{
|
|
if ((unitmask & singlemask) == singlemask)
|
|
count++;
|
|
else if ((unitmask & singlemask) != 0)
|
|
{
|
|
osd_printf_error("Handler %s specified a mask of %016X; needs to be in even chunks of %X\n", string, unitmask, basemask);
|
|
return false;
|
|
}
|
|
singlemask <<= width;
|
|
}
|
|
|
|
#if 0
|
|
// the mask must be symmetrical
|
|
u64 unitmask_bh = unitmask >> 8 & 0x00ff00ff00ff00ffU;
|
|
u64 unitmask_bl = unitmask & 0x00ff00ff00ff00ffU;
|
|
u64 unitmask_wh = unitmask >> 16 & 0x0000ffff0000ffffU;
|
|
u64 unitmask_wl = unitmask & 0x0000ffff0000ffffU;
|
|
u64 unitmask_dh = unitmask >> 32 & 0x00000000ffffffffU;
|
|
u64 unitmask_dl = unitmask & 0x00000000ffffffffU;
|
|
if ((unitmask_bh != 0 && unitmask_bl != 0 && unitmask_bh != unitmask_bl)
|
|
|| (unitmask_wh != 0 && unitmask_wl != 0 && unitmask_wh != unitmask_wl)
|
|
|| (unitmask_dh != 0 && unitmask_dl != 0 && unitmask_dh != unitmask_dl))
|
|
{
|
|
osd_printf_error("Handler %s specified an asymmetrical mask of %016X\n", string, unitmask);
|
|
return false;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
// ADDRESS MAP
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// address_map - constructor
|
|
//-------------------------------------------------
|
|
|
|
address_map::address_map(device_t &device, int spacenum)
|
|
: m_spacenum(spacenum),
|
|
m_device(&device),
|
|
m_unmapval(0),
|
|
m_globalmask(0)
|
|
{
|
|
// get our memory interface
|
|
const device_memory_interface *memintf;
|
|
if (!m_device->interface(memintf))
|
|
throw emu_fatalerror("No memory interface defined for device '%s'\n", m_device->tag());
|
|
|
|
// and then the configuration for the current address space
|
|
const address_space_config *spaceconfig = memintf->space_config(spacenum);
|
|
if (spaceconfig == nullptr)
|
|
throw emu_fatalerror("No memory address space configuration found for device '%s', space %d\n", m_device->tag(), spacenum);
|
|
|
|
// append the map provided by the owner
|
|
if (!memintf->get_addrmap(spacenum).isnull())
|
|
{
|
|
m_device = device.owner();
|
|
memintf->get_addrmap(spacenum)(*this);
|
|
m_device = &device;
|
|
}
|
|
|
|
// construct the internal device map (last so it takes priority)
|
|
if (!spaceconfig->m_internal_map.isnull())
|
|
spaceconfig->m_internal_map(*this);
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------
|
|
// address_map - constructor in the submap case
|
|
//-------------------------------------------------
|
|
|
|
address_map::address_map(device_t &device, address_map_entry *entry)
|
|
: m_spacenum(AS_PROGRAM),
|
|
m_device(&device),
|
|
m_unmapval(0),
|
|
m_globalmask(0)
|
|
{
|
|
// Retrieve the submap
|
|
entry->m_submap_delegate.late_bind(*m_device);
|
|
entry->m_submap_delegate(*this);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------
|
|
// address_map - constructor dynamic device mapping case
|
|
//----------------------------------------------------------
|
|
|
|
address_map::address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate)
|
|
: m_spacenum(space.spacenum()),
|
|
m_device(&device),
|
|
m_unmapval(space.unmap()),
|
|
m_globalmask(space.addrmask())
|
|
{
|
|
(*this)(start, end).m(DEVICE_SELF, submap_delegate).umask64(unitmask).cswidth(cswidth);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// ~address_map - destructor
|
|
//-------------------------------------------------
|
|
|
|
address_map::~address_map()
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// append - append an entry to the end of the
|
|
// list
|
|
//-------------------------------------------------
|
|
|
|
void address_map::global_mask(offs_t mask)
|
|
{
|
|
m_globalmask = mask;
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------
|
|
// add - add a new entry
|
|
//-------------------------------------------------
|
|
|
|
address_map_entry &address_map::operator()(offs_t start, offs_t end)
|
|
{
|
|
address_map_entry *ptr = global_alloc(address_map_entry(*m_device, *this, start, end));
|
|
m_entrylist.append(*ptr);
|
|
return *ptr;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// import_submaps - propagate in the device submaps
|
|
//-------------------------------------------------
|
|
|
|
void address_map::import_submaps(running_machine &machine, device_t &owner, int data_width, endianness_t endian, int addr_shift)
|
|
{
|
|
address_map_entry *prev = nullptr;
|
|
address_map_entry *entry = m_entrylist.first();
|
|
u64 base_unitmask = (~u64(0)) >> (64 - data_width);
|
|
|
|
while (entry)
|
|
{
|
|
if (entry->m_read.m_type == AMH_DEVICE_SUBMAP)
|
|
{
|
|
device_t *mapdevice = entry->m_submap_device;
|
|
if (!mapdevice)
|
|
{
|
|
mapdevice = owner.subdevice(entry->m_read.m_tag);
|
|
if (mapdevice == nullptr)
|
|
throw emu_fatalerror("Attempted to submap a non-existent device '%s' in space %d of device '%s'\n", owner.subtag(entry->m_read.m_tag).c_str(), m_spacenum, m_device->basetag());
|
|
}
|
|
|
|
// Grab the submap
|
|
address_map submap(*mapdevice, entry);
|
|
|
|
// Recursively import if needed
|
|
submap.import_submaps(machine, *mapdevice, data_width, endian, addr_shift);
|
|
|
|
offs_t max_end = entry->m_addrend - entry->m_addrstart;
|
|
|
|
if(!entry->m_mask || (entry->m_mask & base_unitmask) == base_unitmask)
|
|
{
|
|
// Easy case, no unitmask at mapping level - Merge in all the map contents in order
|
|
while (submap.m_entrylist.count())
|
|
{
|
|
address_map_entry *subentry = submap.m_entrylist.detach_head();
|
|
|
|
if (addr_shift > 0)
|
|
{
|
|
subentry->m_addrstart <<= addr_shift;
|
|
subentry->m_addrend = ((subentry->m_addrend + 1) << addr_shift) - 1;
|
|
subentry->m_addrmirror <<= addr_shift;
|
|
subentry->m_addrmask <<= addr_shift;
|
|
subentry->m_addrselect <<= addr_shift;
|
|
}
|
|
else if (addr_shift < 0)
|
|
{
|
|
subentry->m_addrstart >>= -addr_shift;
|
|
subentry->m_addrend >>= -addr_shift;
|
|
subentry->m_addrmirror >>= -addr_shift;
|
|
subentry->m_addrmask >>= -addr_shift;
|
|
subentry->m_addrselect >>= -addr_shift;
|
|
}
|
|
|
|
if (subentry->m_addrend > max_end)
|
|
subentry->m_addrend = max_end;
|
|
|
|
subentry->m_addrstart += entry->m_addrstart;
|
|
subentry->m_addrend += entry->m_addrstart;
|
|
subentry->m_addrmirror |= entry->m_addrmirror;
|
|
subentry->m_addrmask |= entry->m_addrmask;
|
|
subentry->m_addrselect |= entry->m_addrselect;
|
|
|
|
if (subentry->m_addrstart > entry->m_addrend)
|
|
{
|
|
delete subentry;
|
|
continue;
|
|
}
|
|
|
|
// Insert the entry in the map
|
|
m_entrylist.insert_after(*subentry, prev);
|
|
prev = subentry;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// There is a unitmask, calculate its ratio
|
|
int ratio = 0;
|
|
for (int i=0; i != data_width; i++)
|
|
if ((entry->m_mask >> i) & 1)
|
|
ratio ++;
|
|
ratio = data_width / ratio;
|
|
if (addr_shift > 0)
|
|
ratio <<= addr_shift;
|
|
else if (addr_shift < 0)
|
|
max_end = ((max_end + 1) << -addr_shift) - 1;
|
|
max_end = (max_end + 1) / ratio - 1;
|
|
|
|
// Then merge the contents taking the ratio into account
|
|
while (submap.m_entrylist.count())
|
|
{
|
|
address_map_entry *subentry = submap.m_entrylist.detach_head();
|
|
|
|
if (subentry->m_mask && (subentry->m_mask != 0xffffffffffffffffU))
|
|
{
|
|
// Check if the mask can actually fit
|
|
int subentry_ratio = 0;
|
|
for (int i=0; i != data_width; i++)
|
|
if ((subentry->m_mask >> i) & 1)
|
|
subentry_ratio ++;
|
|
subentry_ratio = data_width / subentry_ratio;
|
|
if (ratio * subentry_ratio > data_width / 8)
|
|
fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %s combined with an entry unitmask of %s does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, core_i64_hex_format(entry->m_mask, data_width/4), core_i64_hex_format(subentry->m_mask, data_width/4), data_width);
|
|
|
|
// Regenerate the unitmask
|
|
u64 newmask = 0;
|
|
int bit_in_subentry = 0;
|
|
for (int i=0; i != data_width; i++)
|
|
if ((entry->m_mask >> i) & 1)
|
|
{
|
|
if ((subentry->m_mask >> bit_in_subentry) & 1)
|
|
newmask |= u64(1) << i;
|
|
bit_in_subentry ++;
|
|
}
|
|
subentry->m_mask = newmask;
|
|
}
|
|
else
|
|
subentry->m_mask = entry->m_mask;
|
|
|
|
subentry->m_cswidth = std::max(subentry->m_cswidth, entry->m_cswidth);
|
|
|
|
if (subentry->m_addrend > max_end)
|
|
subentry->m_addrend = max_end;
|
|
|
|
if (addr_shift < 0)
|
|
{
|
|
subentry->m_addrstart = ((subentry->m_addrstart * ratio) >> -addr_shift) + entry->m_addrstart;
|
|
subentry->m_addrend = (((subentry->m_addrend + 1) * ratio - 1) >> -addr_shift) + entry->m_addrstart;
|
|
subentry->m_addrmirror = ((subentry->m_addrmirror / ratio) << -addr_shift) | entry->m_addrmirror;
|
|
subentry->m_addrmask = ((subentry->m_addrmask / ratio) << -addr_shift) | entry->m_addrmask;
|
|
subentry->m_addrselect = ((subentry->m_addrselect / ratio) << -addr_shift) | entry->m_addrselect;
|
|
}
|
|
else
|
|
{
|
|
subentry->m_addrstart = subentry->m_addrstart * ratio + entry->m_addrstart;
|
|
subentry->m_addrend = (subentry->m_addrend + 1) * ratio - 1 + entry->m_addrstart;
|
|
subentry->m_addrmirror = (subentry->m_addrmirror / ratio) | entry->m_addrmirror;
|
|
subentry->m_addrmask = (subentry->m_addrmask / ratio) | entry->m_addrmask;
|
|
subentry->m_addrselect = (subentry->m_addrselect / ratio) | entry->m_addrselect;
|
|
}
|
|
|
|
if (subentry->m_addrstart > entry->m_addrend)
|
|
{
|
|
delete subentry;
|
|
continue;
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// map_validity_check - perform validity checks on
|
|
// one of the device's address maps
|
|
//-------------------------------------------------
|
|
|
|
void address_map::map_validity_check(validity_checker &valid, int spacenum) const
|
|
{
|
|
// it's safe to assume here that the device has a memory interface and a config for this space
|
|
const address_space_config &spaceconfig = *m_device->memory().space_config(spacenum);
|
|
int default_alignunit = spaceconfig.alignment();
|
|
|
|
bool detected_overlap = DETECT_OVERLAPPING_MEMORY ? false : true;
|
|
|
|
// if this is an empty map, just ignore it
|
|
if (m_entrylist.first() == nullptr)
|
|
return;
|
|
|
|
// validate the global map parameters
|
|
if (m_spacenum != spacenum)
|
|
osd_printf_error("Space %d has address space %d handlers!\n", spacenum, m_spacenum);
|
|
|
|
offs_t globalmask = 0xffffffffUL >> (32 - spaceconfig.m_addr_width);
|
|
if (m_globalmask != 0)
|
|
globalmask = m_globalmask;
|
|
|
|
// loop over entries and look for errors
|
|
for (address_map_entry &entry : m_entrylist)
|
|
{
|
|
// look for overlapping entries
|
|
if (!detected_overlap)
|
|
{
|
|
for (address_map_entry &scan : m_entrylist)
|
|
{
|
|
if (&scan == &entry)
|
|
break;
|
|
if (entry.m_addrstart <= scan.m_addrend && entry.m_addrend >= scan.m_addrstart &&
|
|
((entry.m_read.m_type != AMH_NONE && scan.m_read.m_type != AMH_NONE) ||
|
|
(entry.m_write.m_type != AMH_NONE && scan.m_write.m_type != AMH_NONE)))
|
|
{
|
|
osd_printf_warning("%s space has overlapping memory (%X-%X,%d,%d) vs (%X-%X,%d,%d)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_read.m_type, entry.m_write.m_type, scan.m_addrstart, scan.m_addrend, scan.m_read.m_type, scan.m_write.m_type);
|
|
detected_overlap = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// look for inverted start/end pairs
|
|
if (entry.m_addrend < entry.m_addrstart)
|
|
osd_printf_error("Wrong %s memory read handler start = %08x > end = %08x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend);
|
|
|
|
// look for ranges outside the global mask
|
|
if (entry.m_addrstart & ~globalmask)
|
|
osd_printf_error("In %s memory range %x-%x, start address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask);
|
|
if (entry.m_addrend & ~globalmask)
|
|
osd_printf_error("In %s memory range %x-%x, end address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask);
|
|
if (entry.m_addrmask & ~globalmask)
|
|
osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, mask is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrmask & globalmask);
|
|
if ((entry.m_addrmirror & ~globalmask) && (entry.m_addrmirror | globalmask) != 0xffffffff >> (32 - spaceconfig.m_addr_width))
|
|
osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, mirror is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrmirror & globalmask);
|
|
if (entry.m_addrselect & ~globalmask)
|
|
osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, select is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrselect & globalmask);
|
|
|
|
// look for misaligned entries
|
|
if (entry.m_read.m_type != AMH_NONE)
|
|
{
|
|
int alignunit = spaceconfig.byte2addr(entry.m_read.m_bits / 8);
|
|
if (!alignunit)
|
|
alignunit = default_alignunit;
|
|
if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1))
|
|
osd_printf_error("Wrong %s memory read handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit);
|
|
}
|
|
if (entry.m_write.m_type != AMH_NONE)
|
|
{
|
|
int alignunit = spaceconfig.byte2addr(entry.m_write.m_bits / 8);
|
|
if (!alignunit)
|
|
alignunit = default_alignunit;
|
|
if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1))
|
|
osd_printf_error("Wrong %s memory write handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit);
|
|
}
|
|
|
|
// verify mask/mirror/select
|
|
offs_t set_bits = entry.m_addrstart | entry.m_addrend;
|
|
offs_t changing_bits = entry.m_addrstart ^ entry.m_addrend;
|
|
changing_bits |= changing_bits >> 1;
|
|
changing_bits |= changing_bits >> 2;
|
|
changing_bits |= changing_bits >> 4;
|
|
changing_bits |= changing_bits >> 8;
|
|
changing_bits |= changing_bits >> 16;
|
|
|
|
if (entry.m_addrmask & ~changing_bits)
|
|
osd_printf_error("In %s memory range %x-%x, mask %x is trying to unmask an unchanging address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmask & ~changing_bits);
|
|
if (entry.m_addrmirror & changing_bits)
|
|
osd_printf_error("In %s memory range %x-%x, mirror %x touches a changing address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & changing_bits);
|
|
if (entry.m_addrselect & changing_bits)
|
|
osd_printf_error("In %s memory range %x-%x, select %x touches a changing address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrselect, entry.m_addrselect & changing_bits);
|
|
if (entry.m_addrmirror & set_bits)
|
|
osd_printf_error("In %s memory range %x-%x, mirror %x touches a set address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & set_bits);
|
|
if (entry.m_addrselect & set_bits)
|
|
osd_printf_error("In %s memory range %x-%x, select %x touches a set address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrselect, entry.m_addrselect & set_bits);
|
|
if (entry.m_addrmirror & entry.m_addrselect)
|
|
osd_printf_error("In %s memory range %x-%x, mirror %x touches a select bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & entry.m_addrselect);
|
|
|
|
// if this is a program space, auto-assign implicit ROM entries
|
|
if (entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr)
|
|
{
|
|
entry.m_region = m_device->tag();
|
|
entry.m_rgnoffs = entry.m_addrstart;
|
|
}
|
|
|
|
// if this entry references a memory region, validate it
|
|
if (entry.m_region != nullptr && entry.m_share == nullptr)
|
|
{
|
|
// address map entries that reference regions but are NOPs are pointless
|
|
if (entry.m_read.m_type == AMH_NONE && entry.m_write.m_type == AMH_NONE)
|
|
osd_printf_error("%s space references memory region %s, but is noprw()\n", spaceconfig.m_name, entry.m_region);
|
|
|
|
// make sure we can resolve the full path to the region
|
|
bool found = false;
|
|
std::string entry_region = entry.m_devbase.subtag(entry.m_region);
|
|
|
|
// look for the region
|
|
for (device_t &dev : device_iterator(m_device->mconfig().root_device()))
|
|
{
|
|
for (romload::region const ®ion : romload::entries(dev.rom_region()).get_regions())
|
|
{
|
|
if (dev.subtag(region.get_tag()) == entry_region)
|
|
{
|
|
// verify the address range is within the region's bounds
|
|
offs_t const length = region.get_length();
|
|
if (entry.m_rgnoffs + spaceconfig.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > length)
|
|
osd_printf_error("%s space memory map entry %X-%X extends beyond region '%s' size (%X)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, length);
|
|
|
|
device_t *rgndev = dev.subdevice(region.get_tag());
|
|
if (rgndev != m_device)
|
|
{
|
|
int rgnwidth = region.get_width();
|
|
bool rgnisbe = region.is_bigendian();
|
|
|
|
// memory interface sets region width when tags are the same
|
|
device_memory_interface *memintf;
|
|
if (rgndev != nullptr && rgndev->interface(memintf))
|
|
{
|
|
const address_space_config *rgncfg = memintf->space_config(0);
|
|
if (rgncfg != nullptr)
|
|
{
|
|
rgnwidth = rgncfg->data_width();
|
|
rgnisbe = rgncfg->endianness() == ENDIANNESS_BIG;
|
|
}
|
|
}
|
|
|
|
// verify data width
|
|
if (rgnwidth != spaceconfig.data_width())
|
|
osd_printf_error("%s space is %d-bit but references %d-bit region '%s'\n", spaceconfig.m_name, spaceconfig.data_width(), rgnwidth, dev.subtag(region.get_tag()));
|
|
|
|
// verify endianness
|
|
if (rgnwidth != 8)
|
|
{
|
|
if (!rgnisbe && spaceconfig.endianness() == ENDIANNESS_BIG)
|
|
osd_printf_error("%s space is big-endian but references little-endian region '%s'\n", spaceconfig.m_name, dev.subtag(region.get_tag()));
|
|
else if (rgnisbe && spaceconfig.endianness() == ENDIANNESS_LITTLE)
|
|
osd_printf_error("%s space is little-endian but references big-endian region '%s'\n", spaceconfig.m_name, dev.subtag(region.get_tag()));
|
|
}
|
|
}
|
|
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// error if not found
|
|
if (!found)
|
|
osd_printf_error("%s space memory map entry %X-%X references nonexistent region '%s'\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region);
|
|
}
|
|
|
|
// make sure all devices exist
|
|
if (entry.m_read.m_type == AMH_DEVICE_DELEGATE || entry.m_read.m_type == AMH_DEVICE_DELEGATE_M || entry.m_read.m_type == AMH_DEVICE_DELEGATE_S || entry.m_read.m_type == AMH_DEVICE_DELEGATE_SM || entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO || entry.m_read.m_type == AMH_DEVICE_DELEGATE_SMO)
|
|
{
|
|
// extract the device tag from the proto-delegate
|
|
std::pair<std::reference_wrapper<device_t>, const char *> devtag(entry.m_devbase, nullptr);
|
|
switch (entry.m_read.m_bits)
|
|
{
|
|
case 8:
|
|
if (entry.m_read.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_rproto8.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_rproto8m.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_rproto8s.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_rproto8sm.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_rproto8mo.finder_target();
|
|
else
|
|
devtag = entry.m_rproto8smo.finder_target();
|
|
break;
|
|
|
|
case 16:
|
|
if (entry.m_read.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_rproto16.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_rproto16m.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_rproto16s.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_rproto16sm.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_rproto16mo.finder_target();
|
|
else
|
|
devtag = entry.m_rproto16smo.finder_target();
|
|
break;
|
|
|
|
case 32:
|
|
if (entry.m_read.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_rproto32.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_rproto32m.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_rproto32s.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_rproto32sm.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_rproto32mo.finder_target();
|
|
else
|
|
devtag = entry.m_rproto32smo.finder_target();
|
|
break;
|
|
|
|
case 64:
|
|
if (entry.m_read.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_rproto64.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_rproto64m.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_rproto64s.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_rproto64sm.finder_target();
|
|
else if (entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_rproto64mo.finder_target();
|
|
else
|
|
devtag = entry.m_rproto64smo.finder_target();
|
|
break;
|
|
}
|
|
if (devtag.second && !devtag.first.get().subdevice(devtag.second))
|
|
osd_printf_error("%s space memory map entry reads from nonexistent device '%s'\n", spaceconfig.m_name, devtag.first.get().subtag(devtag.second).c_str());
|
|
#ifndef MAME_DEBUG // assert will catch this earlier
|
|
(void)entry.unitmask_is_appropriate(entry.m_read.m_bits, entry.m_mask, entry.m_read.m_name);
|
|
#endif
|
|
}
|
|
if (entry.m_write.m_type == AMH_DEVICE_DELEGATE || entry.m_read.m_type == AMH_DEVICE_DELEGATE_M || entry.m_write.m_type == AMH_DEVICE_DELEGATE_S || entry.m_write.m_type == AMH_DEVICE_DELEGATE_SM || entry.m_read.m_type == AMH_DEVICE_DELEGATE_MO || entry.m_write.m_type == AMH_DEVICE_DELEGATE_SMO)
|
|
{
|
|
// extract the device tag from the proto-delegate
|
|
std::pair<std::reference_wrapper<device_t>, const char *> devtag(entry.m_devbase, nullptr);
|
|
switch (entry.m_write.m_bits)
|
|
{
|
|
case 8:
|
|
if (entry.m_write.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_wproto8.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_wproto8m.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_wproto8s.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_wproto8sm.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_wproto8mo.finder_target();
|
|
else
|
|
devtag = entry.m_wproto8smo.finder_target();
|
|
break;
|
|
|
|
case 16:
|
|
if (entry.m_write.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_wproto16.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_wproto16m.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_wproto16s.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_wproto16sm.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_wproto16mo.finder_target();
|
|
else
|
|
devtag = entry.m_wproto16smo.finder_target();
|
|
break;
|
|
|
|
case 32:
|
|
if (entry.m_write.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_wproto32.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_wproto32m.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_wproto32s.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_wproto32sm.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_wproto32mo.finder_target();
|
|
else
|
|
devtag = entry.m_wproto32smo.finder_target();
|
|
break;
|
|
|
|
case 64:
|
|
if (entry.m_write.m_type == AMH_DEVICE_DELEGATE)
|
|
devtag = entry.m_wproto64.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_M)
|
|
devtag = entry.m_wproto64m.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_S)
|
|
devtag = entry.m_wproto64s.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_SM)
|
|
devtag = entry.m_wproto64sm.finder_target();
|
|
else if (entry.m_write.m_type == AMH_DEVICE_DELEGATE_MO)
|
|
devtag = entry.m_wproto64mo.finder_target();
|
|
else
|
|
devtag = entry.m_wproto64smo.finder_target();
|
|
break;
|
|
}
|
|
if (devtag.second && !devtag.first.get().subdevice(devtag.second))
|
|
osd_printf_error("%s space memory map entry writes to nonexistent device '%s'\n", spaceconfig.m_name, devtag.first.get().subtag(devtag.second).c_str());
|
|
#ifndef MAME_DEBUG // assert will catch this earlier
|
|
(void)entry.unitmask_is_appropriate(entry.m_write.m_bits, entry.m_mask, entry.m_write.m_name);
|
|
#endif
|
|
}
|
|
|
|
// make sure ports exist
|
|
// if ((entry.m_read.m_type == AMH_PORT && entry.m_read.m_tag != nullptr && portlist.find(entry.m_read.m_tag) == nullptr) ||
|
|
// (entry.m_write.m_type == AMH_PORT && entry.m_write.m_tag != nullptr && portlist.find(entry.m_write.m_tag) == nullptr))
|
|
// osd_printf_error("%s space memory map entry references nonexistent port tag '%s'\n", spaceconfig.m_name, entry.m_read.m_tag);
|
|
|
|
// validate bank and share tags
|
|
if (entry.m_read.m_type == AMH_BANK)
|
|
valid.validate_tag(entry.m_read.m_tag);
|
|
if (entry.m_write.m_type == AMH_BANK)
|
|
valid.validate_tag(entry.m_write.m_tag);
|
|
if (entry.m_share != nullptr)
|
|
valid.validate_tag(entry.m_share);
|
|
}
|
|
}
|