mirror of
https://github.com/holub/mame
synced 2025-05-02 20:46:41 +03:00
memory: Change the gc into a refcounter, for speed reasons. [O. Galibert]
This commit is contained in:
parent
55c58f6bdf
commit
87a6c3f7f8
186
src/emu/memory.c
186
src/emu/memory.c
@ -837,7 +837,6 @@ protected:
|
|||||||
// table population/depopulation
|
// table population/depopulation
|
||||||
void populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handler);
|
void populate_range_mirrored(offs_t bytestart, offs_t byteend, offs_t bytemirror, UINT8 handler);
|
||||||
void populate_range(offs_t bytestart, offs_t byteend, UINT8 handler);
|
void populate_range(offs_t bytestart, offs_t byteend, UINT8 handler);
|
||||||
void depopulate_unused();
|
|
||||||
|
|
||||||
// subtable management
|
// subtable management
|
||||||
UINT8 subtable_alloc();
|
UINT8 subtable_alloc();
|
||||||
@ -874,7 +873,30 @@ protected:
|
|||||||
static UINT8 s_watchpoint_table[1 << LEVEL1_BITS];
|
static UINT8 s_watchpoint_table[1 << LEVEL1_BITS];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int handler_refcount[SUBTABLE_BASE-STATIC_COUNT];
|
||||||
|
UINT8 handler_next_free[SUBTABLE_BASE-STATIC_COUNT];
|
||||||
|
UINT8 handler_free;
|
||||||
UINT8 get_free_handler();
|
UINT8 get_free_handler();
|
||||||
|
void verify_reference_counts();
|
||||||
|
|
||||||
|
void handler_ref(UINT8 entry, int count)
|
||||||
|
{
|
||||||
|
assert(entry < SUBTABLE_BASE);
|
||||||
|
if (entry >= STATIC_COUNT)
|
||||||
|
handler_refcount[entry - STATIC_COUNT] += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handler_unref(UINT8 entry)
|
||||||
|
{
|
||||||
|
assert(entry < SUBTABLE_BASE);
|
||||||
|
if (entry >= STATIC_COUNT)
|
||||||
|
if (! --handler_refcount[entry - STATIC_COUNT])
|
||||||
|
{
|
||||||
|
handler(entry).deconfigure();
|
||||||
|
handler_next_free[entry - STATIC_COUNT] = handler_free;
|
||||||
|
handler_free = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3207,6 +3229,15 @@ address_table::address_table(address_space &space, bool large)
|
|||||||
|
|
||||||
// initialize everything to unmapped
|
// initialize everything to unmapped
|
||||||
memset(m_table, STATIC_UNMAP, 1 << LEVEL1_BITS);
|
memset(m_table, STATIC_UNMAP, 1 << LEVEL1_BITS);
|
||||||
|
|
||||||
|
// initialize the handlers freelist
|
||||||
|
for (int i=0; i != SUBTABLE_BASE-STATIC_COUNT-1; i++)
|
||||||
|
handler_next_free[i] = i+STATIC_COUNT+1;
|
||||||
|
handler_next_free[SUBTABLE_BASE-STATIC_COUNT-1] = STATIC_INVALID;
|
||||||
|
handler_free = STATIC_COUNT;
|
||||||
|
|
||||||
|
// initialize the handlers refcounts
|
||||||
|
memset(handler_refcount, 0, sizeof(handler_refcount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3250,22 +3281,18 @@ void address_table::map_range(offs_t addrstart, offs_t addrend, offs_t addrmask,
|
|||||||
|
|
||||||
// recompute any direct access on this space if it is a read modification
|
// recompute any direct access on this space if it is a read modification
|
||||||
m_space.m_direct.force_update(entry);
|
m_space.m_direct.force_update(entry);
|
||||||
|
|
||||||
|
// verify_reference_counts();
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 address_table::get_free_handler()
|
UINT8 address_table::get_free_handler()
|
||||||
{
|
{
|
||||||
// scan all possible assigned entries for something unpopulated
|
if (handler_free == STATIC_INVALID)
|
||||||
for (UINT8 scanentry = STATIC_COUNT; scanentry < SUBTABLE_BASE; scanentry++)
|
throw emu_fatalerror("Out of handler entries in address table");
|
||||||
if (!handler(scanentry).populated())
|
|
||||||
return scanentry;
|
|
||||||
|
|
||||||
// if we didn't find anything, find something to depopulate and try again
|
UINT8 handler = handler_free;
|
||||||
depopulate_unused();
|
handler_free = handler_next_free[handler - STATIC_COUNT];
|
||||||
for (UINT8 scanentry = STATIC_COUNT; scanentry < SUBTABLE_BASE; scanentry++)
|
return handler;
|
||||||
if (!handler(scanentry).populated())
|
|
||||||
return scanentry;
|
|
||||||
|
|
||||||
throw emu_fatalerror("Out of handler entries in address table");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3284,7 +3311,6 @@ namespace {
|
|||||||
|
|
||||||
void address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, UINT64 mask, std::list<UINT32> &entries)
|
void address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmask, offs_t addrmirror, UINT64 mask, std::list<UINT32> &entries)
|
||||||
{
|
{
|
||||||
|
|
||||||
// convert addresses to bytes
|
// convert addresses to bytes
|
||||||
offs_t bytestart = addrstart;
|
offs_t bytestart = addrstart;
|
||||||
offs_t byteend = addrend;
|
offs_t byteend = addrend;
|
||||||
@ -3391,6 +3417,54 @@ void address_table::setup_range(offs_t addrstart, offs_t addrend, offs_t addrmas
|
|||||||
m_space.m_direct.force_update(entry);
|
m_space.m_direct.force_update(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify_reference_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// verify_reference_counts - check how much of a
|
||||||
|
// hash we've made of things
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void address_table::verify_reference_counts()
|
||||||
|
{
|
||||||
|
int actual_refcounts[SUBTABLE_BASE-STATIC_COUNT];
|
||||||
|
memset(actual_refcounts, 0, sizeof(actual_refcounts));
|
||||||
|
|
||||||
|
bool subtable_seen[256 - SUBTABLE_BASE];
|
||||||
|
memset(subtable_seen, 0, sizeof(subtable_seen));
|
||||||
|
|
||||||
|
for (int level1 = 0; level1 != 1 << LEVEL1_BITS; level1++)
|
||||||
|
{
|
||||||
|
UINT8 l1_entry = m_table[level1];
|
||||||
|
if (l1_entry >= SUBTABLE_BASE)
|
||||||
|
{
|
||||||
|
assert(m_large);
|
||||||
|
if (subtable_seen[l1_entry - SUBTABLE_BASE])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
subtable_seen[l1_entry - SUBTABLE_BASE] = true;
|
||||||
|
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)
|
||||||
|
actual_refcounts[l2_entry - STATIC_COUNT]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (l1_entry >= STATIC_COUNT)
|
||||||
|
actual_refcounts[l1_entry - STATIC_COUNT]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(actual_refcounts, handler_refcount, sizeof(handler_refcount)))
|
||||||
|
{
|
||||||
|
logerror("Refcount failure:\n");
|
||||||
|
for(int i = STATIC_COUNT; i != SUBTABLE_BASE; i++)
|
||||||
|
logerror("%02x: %4x .. %4x\n", i, handler_refcount[i-STATIC_COUNT], actual_refcounts[i-STATIC_COUNT]);
|
||||||
|
throw emu_fatalerror("memory.c: refcounts are fucked.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3419,13 +3493,23 @@ void address_table::populate_range(offs_t bytestart, offs_t byteend, UINT8 handl
|
|||||||
// if the start and stop end within the same block, handle that
|
// if the start and stop end within the same block, handle that
|
||||||
if (l1start == l1stop)
|
if (l1start == l1stop)
|
||||||
{
|
{
|
||||||
memset(&subtable[l2start], handlerindex, l2stop - l2start + 1);
|
handler_ref(handlerindex, l2stop-l2start+1);
|
||||||
|
for (int i = l2start; i <= l2stop; i++)
|
||||||
|
{
|
||||||
|
handler_unref(subtable[i]);
|
||||||
|
subtable[i] = handlerindex;
|
||||||
|
}
|
||||||
subtable_close(l1start);
|
subtable_close(l1start);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, fill until the end
|
// otherwise, fill until the end
|
||||||
memset(&subtable[l2start], handlerindex, (1 << level2_bits()) - l2start);
|
handler_ref(handlerindex, l2mask - l2start + 1);
|
||||||
|
for (int i = l2start; i <= l2mask; i++)
|
||||||
|
{
|
||||||
|
handler_unref(subtable[i]);
|
||||||
|
subtable[i] = handlerindex;
|
||||||
|
}
|
||||||
subtable_close(l1start);
|
subtable_close(l1start);
|
||||||
if (l1start != (offs_t)~0)
|
if (l1start != (offs_t)~0)
|
||||||
l1start++;
|
l1start++;
|
||||||
@ -3437,7 +3521,12 @@ void address_table::populate_range(offs_t bytestart, offs_t byteend, UINT8 handl
|
|||||||
UINT8 *subtable = subtable_open(l1stop);
|
UINT8 *subtable = subtable_open(l1stop);
|
||||||
|
|
||||||
// fill from the beginning
|
// fill from the beginning
|
||||||
memset(&subtable[0], handlerindex, l2stop + 1);
|
handler_ref(handlerindex, l2stop+1);
|
||||||
|
for (int i = 0; i <= l2stop; i++)
|
||||||
|
{
|
||||||
|
handler_unref(subtable[i]);
|
||||||
|
subtable[i] = handlerindex;
|
||||||
|
}
|
||||||
subtable_close(l1stop);
|
subtable_close(l1stop);
|
||||||
|
|
||||||
// if the start and stop end within the same block, handle that
|
// if the start and stop end within the same block, handle that
|
||||||
@ -3448,11 +3537,16 @@ void address_table::populate_range(offs_t bytestart, offs_t byteend, UINT8 handl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now fill in the middle tables
|
// now fill in the middle tables
|
||||||
|
handler_ref(handlerindex, l1stop - l1start + 1);
|
||||||
for (offs_t l1index = l1start; l1index <= l1stop; l1index++)
|
for (offs_t l1index = l1start; l1index <= l1stop; l1index++)
|
||||||
{
|
{
|
||||||
|
UINT8 subindex = m_table[l1index];
|
||||||
|
|
||||||
// if we have a subtable here, release it
|
// if we have a subtable here, release it
|
||||||
if (m_table[l1index] >= SUBTABLE_BASE)
|
if (subindex >= SUBTABLE_BASE)
|
||||||
subtable_release(m_table[l1index]);
|
subtable_release(subindex);
|
||||||
|
else
|
||||||
|
handler_unref(subindex);
|
||||||
m_table[l1index] = handlerindex;
|
m_table[l1index] = handlerindex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3514,10 +3608,14 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
|
|||||||
// release the subtable if the old value was a subtable
|
// release the subtable if the old value was a subtable
|
||||||
if (m_table[cur_index] >= SUBTABLE_BASE)
|
if (m_table[cur_index] >= SUBTABLE_BASE)
|
||||||
subtable_release(m_table[cur_index]);
|
subtable_release(m_table[cur_index]);
|
||||||
|
else
|
||||||
|
handler_unref(m_table[cur_index]);
|
||||||
|
|
||||||
// reallocate the subtable if the new value is a subtable
|
// reallocate the subtable if the new value is a subtable
|
||||||
if (m_table[prev_index] >= SUBTABLE_BASE)
|
if (m_table[prev_index] >= SUBTABLE_BASE)
|
||||||
subtable_realloc(m_table[prev_index]);
|
subtable_realloc(m_table[prev_index]);
|
||||||
|
else
|
||||||
|
handler_ref(m_table[prev_index], 1);
|
||||||
|
|
||||||
// set the new value and short-circuit the mapping step
|
// set the new value and short-circuit the mapping step
|
||||||
m_table[cur_index] = m_table[prev_index];
|
m_table[cur_index] = m_table[prev_index];
|
||||||
@ -3543,41 +3641,6 @@ void address_table::populate_range_mirrored(offs_t bytestart, offs_t byteend, of
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// depopulate_unused - scan the table and
|
|
||||||
// eliminate entries that are no longer used
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
void address_table::depopulate_unused()
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// derive_range - look up the entry for a memory
|
// derive_range - look up the entry for a memory
|
||||||
// range, and then compute the extent of that
|
// range, and then compute the extent of that
|
||||||
@ -3826,9 +3889,15 @@ void address_table::subtable_release(UINT8 subentry)
|
|||||||
fatalerror("Called subtable_release on a table with a usecount of 0");
|
fatalerror("Called subtable_release on a table with a usecount of 0");
|
||||||
|
|
||||||
// decrement the usecount and clear the checksum if we're at 0
|
// decrement the usecount and clear the checksum if we're at 0
|
||||||
|
// also unref the subhandlers
|
||||||
m_subtable[subindex].m_usecount--;
|
m_subtable[subindex].m_usecount--;
|
||||||
if (m_subtable[subindex].m_usecount == 0)
|
if (m_subtable[subindex].m_usecount == 0)
|
||||||
|
{
|
||||||
m_subtable[subindex].m_checksum = 0;
|
m_subtable[subindex].m_checksum = 0;
|
||||||
|
UINT8 *subtable = subtable_ptr(subentry);
|
||||||
|
for (int i = 0; i < (1 << LEVEL2_BITS); i++)
|
||||||
|
handler_unref(subtable[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3844,8 +3913,10 @@ UINT8 *address_table::subtable_open(offs_t l1index)
|
|||||||
// if we don't have a subtable yet, allocate a new one
|
// if we don't have a subtable yet, allocate a new one
|
||||||
if (subentry < SUBTABLE_BASE)
|
if (subentry < SUBTABLE_BASE)
|
||||||
{
|
{
|
||||||
|
int size = 1 << level2_bits();
|
||||||
UINT8 newentry = subtable_alloc();
|
UINT8 newentry = subtable_alloc();
|
||||||
memset(subtable_ptr(newentry), subentry, 1 << level2_bits());
|
handler_ref(subentry, size-1);
|
||||||
|
memset(subtable_ptr(newentry), subentry, size);
|
||||||
m_table[l1index] = newentry;
|
m_table[l1index] = newentry;
|
||||||
m_subtable[newentry - SUBTABLE_BASE].m_checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << level2_bits())/4);
|
m_subtable[newentry - SUBTABLE_BASE].m_checksum = (subentry + (subentry << 8) + (subentry << 16) + (subentry << 24)) * ((1 << level2_bits())/4);
|
||||||
subentry = newentry;
|
subentry = newentry;
|
||||||
@ -3862,7 +3933,12 @@ UINT8 *address_table::subtable_open(offs_t l1index)
|
|||||||
assert(subentry >= SUBTABLE_BASE);
|
assert(subentry >= SUBTABLE_BASE);
|
||||||
assert(m_subtable[subentry - SUBTABLE_BASE].m_usecount > 1);
|
assert(m_subtable[subentry - SUBTABLE_BASE].m_usecount > 1);
|
||||||
|
|
||||||
memcpy(subtable_ptr(newentry), subtable_ptr(subentry), 1 << level2_bits());
|
int size = 1 << level2_bits();
|
||||||
|
UINT8 *src = subtable_ptr(subentry);
|
||||||
|
for(int i=0; i != size; i++)
|
||||||
|
handler_ref(src[i], 1);
|
||||||
|
|
||||||
|
memcpy(subtable_ptr(newentry), src, size);
|
||||||
subtable_release(subentry);
|
subtable_release(subentry);
|
||||||
m_table[l1index] = newentry;
|
m_table[l1index] = newentry;
|
||||||
m_subtable[newentry - SUBTABLE_BASE].m_checksum = m_subtable[subentry - SUBTABLE_BASE].m_checksum;
|
m_subtable[newentry - SUBTABLE_BASE].m_checksum = m_subtable[subentry - SUBTABLE_BASE].m_checksum;
|
||||||
|
Loading…
Reference in New Issue
Block a user