summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2011-06-01 07:09:24 +0000
committer Olivier Galibert <galibert@pobox.com>2011-06-01 07:09:24 +0000
commit459102e95f5ebebd8bbbd38cd763b90489b0317f (patch)
treebd93fab766b4b35601e0e886ba54e1359d4ebda6 /src
parentd5370bdafbb6b71f4352a1f8960fd21f29630a56 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/emu/memory.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/src/emu/memory.c b/src/emu/memory.c
index 6a69ba78434..041a2fd45e2 100644
--- a/src/emu/memory.c
+++ b/src/emu/memory.c
@@ -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();
}