summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/addrmap.cpp
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2017-03-25 17:35:45 -0400
committer AJR <ajrhacker@users.noreply.github.com>2017-03-25 17:35:45 -0400
commit323eb04ded6efbf03ff4355512201a0df0d443a7 (patch)
tree67b13536617fe0ffdfb0b02ecff639e3f8a18f8f /src/emu/addrmap.cpp
parent8ce5aa566f3f8faac454ee875c6495bf475cb6bd (diff)
Memory unit masking and address mirroring fixes (nw)
- Fix a bug which effectively treated AM_MIRROR as AM_SELECT when applied to a single-address range mirrored into a contiguous block. The automatic expansion of zero address masks now only applies to those stemming from (default) configuration, not from optimization. (This allows the assertion in latch8_device to be reinstated.) - Fix a bug where AM_SELECT applied to narrow-width handlers with a submaximal number of subunits would select the wrong address bits or none at all. (This allows rpunch_gga_w to be WRITE8 as intended.) - Add more stringent appropriateness checking of unit masks for narrow-width handlers.
Diffstat (limited to 'src/emu/addrmap.cpp')
-rw-r--r--src/emu/addrmap.cpp26
1 files changed, 25 insertions, 1 deletions
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp
index 5b12f139026..d6e0290e4f0 100644
--- a/src/emu/addrmap.cpp
+++ b/src/emu/addrmap.cpp
@@ -288,15 +288,39 @@ bool address_map_entry::unitmask_is_appropriate(u8 width, u64 unitmask, const ch
if (m_map.m_databits < width)
throw emu_fatalerror("Handler %s is a %d-bit handler and is too wide to be used in a %d-bit address map", string, width, m_map.m_databits);
+ // 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)
+ throw emu_fatalerror("Handler %s specified a mask of %08X%08X, too wide to be used in a %d-bit address map", string, (u32)(unitmask >> 32), (u32)unitmask, m_map.m_databits);
+
// 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) != 0 && (unitmask & singlemask) != singlemask)
+ if ((unitmask & singlemask) == singlemask)
+ count++;
+ else if ((unitmask & singlemask) != 0)
throw emu_fatalerror("Handler %s specified a mask of %08X%08X; needs to be in even chunks of %X", string, (u32)(unitmask >> 32), (u32)unitmask, basemask);
singlemask <<= width;
}
+
+ // subunit count must be a power of 2
+ if (count != 1 && count != 2 && count != 4 && count != 8)
+ throw emu_fatalerror("Handler %s specifies %d subunits with a mask of %08X%08X; needs to be a power of 2", string, count, (u32)(unitmask >> 32), (u32)unitmask);
+
+ // 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))
+ throw emu_fatalerror("Handler %s specified an asymmetrical mask of %08X%08X", string, (u32)(unitmask >> 32), (u32)unitmask);
+
return true;
}