memory: Implement depopulate_unused(). [O. Galibert]

depopulate_unused is essentially the garbage collector for
bottom-level handlers.  The previous code was working around not
having it implemented yet by reusing handlers with the same start
address, end address and address mask.  The problem with that trick is
that it is slightly incorrect.  If you have a memory map with:
  AM_RANGE(0x0000, 0x0fff) AM_READ(up_r)
  AM_RANGE(0x0000, 0x0fff) AM_READ(down_r) AM_MIRROR(0x8000)

then the range 8000..8fff would have called up_r instead of down_r due
to the handler reuse.  The mirror value is not saved, hence not
compared.  New code doesn't use the trick, so doesn't call the wrong
handler, but OTOH eats handlers for breakfast.

It's important to note that such a memory map is so highly improbable
hardware-wise that it wasn't worth worrying about.  But it's a
behaviour change it is interesting to keep in mind.  In particular
since the up_r range can be added through an install_read_handler
instead of a static map.
This commit is contained in:
Olivier Galibert 2011-06-01 07:09:24 +00:00
parent d5370bdafb
commit 459102e95f

View File

@ -475,6 +475,13 @@ public:
// reconfigure the subunits on a base address change
void reconfigure_subunits(offs_t bytestart);
// depopulate an handler
void deconfigure()
{
m_populated = false;
m_subunits = 0;
}
// apply a global mask
void apply_mask(offs_t bytemask) { m_bytemask &= bytemask; }
@ -3543,7 +3550,31 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
void address_table::depopulate_unused()
{
assert(false);
bool used[SUBTABLE_BASE - STATIC_COUNT];
memset(used, 0, sizeof(used));
for (int level1 = 0; level1 != 1 << LEVEL1_BITS; level1++)
{
UINT8 l1_entry = m_table[level1];
if (l1_entry >= SUBTABLE_BASE)
{
assert(m_large);
const UINT8 *subtable = subtable_ptr(l1_entry);
for (int level2 = 0; level2 != 1 << LEVEL2_BITS; level2++)
{
UINT8 l2_entry = subtable[level2];
assert(l2_entry < SUBTABLE_BASE);
if (l2_entry >= STATIC_COUNT)
used[l2_entry - STATIC_COUNT] = true;
}
}
else if (l1_entry >= STATIC_COUNT)
used[l1_entry - STATIC_COUNT] = true;
}
for (int slot=0; slot != SUBTABLE_BASE - STATIC_COUNT; slot++)
if (!used[slot])
handler(slot + STATIC_COUNT).deconfigure();
}