summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/drcbeut.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
committer Miodrag Milanovic <mmicko@gmail.com>2015-09-13 08:41:44 +0200
commitf88cefad27a1737c76e09d99c9fb43e173506081 (patch)
tree2d8167d03579c46e226471747eb4407bd00ed6fa /src/emu/cpu/drcbeut.c
parente92ac9e0fa8e99869894bea00589bbb526be30aa (diff)
Move all devices into separate part of src tree (nw)
Diffstat (limited to 'src/emu/cpu/drcbeut.c')
-rw-r--r--src/emu/cpu/drcbeut.c577
1 files changed, 0 insertions, 577 deletions
diff --git a/src/emu/cpu/drcbeut.c b/src/emu/cpu/drcbeut.c
deleted file mode 100644
index 4df863c8fb5..00000000000
--- a/src/emu/cpu/drcbeut.c
+++ /dev/null
@@ -1,577 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- drcbeut.c
-
- Utility functions for dynamic recompiling backends.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "drcbeut.h"
-
-using namespace uml;
-
-
-//**************************************************************************
-// DEBUGGING
-//**************************************************************************
-
-#define LOG_RECOVER (0)
-
-
-
-//**************************************************************************
-// DRC HASH TABLE
-//**************************************************************************
-
-//-------------------------------------------------
-// drc_hash_table - constructor
-//-------------------------------------------------
-
-drc_hash_table::drc_hash_table(drc_cache &cache, UINT32 modes, UINT8 addrbits, UINT8 ignorebits)
- : m_cache(cache),
- m_modes(modes),
- m_nocodeptr(NULL),
- m_l1bits((addrbits - ignorebits) / 2),
- m_l2bits((addrbits - ignorebits) - m_l1bits),
- m_l1shift(ignorebits + m_l2bits),
- m_l2shift(ignorebits),
- m_l1mask((1 << m_l1bits) - 1),
- m_l2mask((1 << m_l2bits) - 1),
- m_base(reinterpret_cast<drccodeptr ***>(cache.alloc(modes * sizeof(**m_base)))),
- m_emptyl1(NULL),
- m_emptyl2(NULL)
-{
- reset();
-}
-
-
-//-------------------------------------------------
-// reset - flush existing hash tables and create
-// new ones
-//-------------------------------------------------
-
-bool drc_hash_table::reset()
-{
- // allocate an empty l2 hash table
- m_emptyl2 = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits);
- if (m_emptyl2 == NULL)
- return false;
-
- // populate it with pointers to the recompile_exit code
- for (int entry = 0; entry < (1 << m_l2bits); entry++)
- m_emptyl2[entry] = m_nocodeptr;
-
- // allocate an empty l1 hash table
- m_emptyl1 = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits);
- if (m_emptyl1 == NULL)
- return false;
-
- // populate it with pointers to the empty l2 table
- for (int entry = 0; entry < (1 << m_l1bits); entry++)
- m_emptyl1[entry] = m_emptyl2;
-
- // reset the hash tables
- for (int modenum = 0; modenum < m_modes; modenum++)
- m_base[modenum] = m_emptyl1;
-
- return true;
-}
-
-
-//-------------------------------------------------
-// block_begin - note the beginning of a block
-//-------------------------------------------------
-
-void drc_hash_table::block_begin(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst)
-{
- // before generating code, pre-allocate any hash entries; we do this by setting dummy hash values
- for (int inum = 0; inum < numinst; inum++)
- {
- const uml::instruction &inst = instlist[inum];
-
- // if the opcode is a hash, verify that it makes sense and then set a NULL entry
- if (inst.opcode() == OP_HASH)
- {
- assert(inst.numparams() == 2);
-
- // if we fail to allocate, we must abort the block
- if (!set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), NULL))
- block.abort();
- }
-
- // if the opcode is a hashjmp to a fixed location, make sure we preallocate the tables
- if (inst.opcode() == OP_HASHJMP && inst.param(0).is_immediate() && inst.param(1).is_immediate())
- {
- // if we fail to allocate, we must abort the block
- drccodeptr code = get_codeptr(inst.param(0).immediate(), inst.param(1).immediate());
- if (!set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), code))
- block.abort();
- }
- }
-}
-
-
-//-------------------------------------------------
-// block_end - note the end of a block
-//-------------------------------------------------
-
-void drc_hash_table::block_end(drcuml_block &block)
-{
- // nothing to do here, yet
-}
-
-
-//-------------------------------------------------
-// set_default_codeptr - change the default
-// codeptr
-//-------------------------------------------------
-
-void drc_hash_table::set_default_codeptr(drccodeptr nocodeptr)
-{
- // nothing to do if the same
- drccodeptr old = m_nocodeptr;
- if (old == nocodeptr)
- return;
- m_nocodeptr = nocodeptr;
-
- // update the empty L2 table first
- for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++)
- m_emptyl2[l2entry] = nocodeptr;
-
- // now scan all existing hashtables for entries
- for (int modenum = 0; modenum < m_modes; modenum++)
- if (m_base[modenum] != m_emptyl1)
- for (int l1entry = 0; l1entry < (1 << m_l1bits); l1entry++)
- if (m_base[modenum][l1entry] != m_emptyl2)
- for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++)
- if (m_base[modenum][l1entry][l2entry] == old)
- m_base[modenum][l1entry][l2entry] = nocodeptr;
-}
-
-
-//-------------------------------------------------
-// set_codeptr - set the codeptr for the given
-// mode/pc
-//-------------------------------------------------
-
-bool drc_hash_table::set_codeptr(UINT32 mode, UINT32 pc, drccodeptr code)
-{
- // copy-on-write for the l1 hash table
- assert(mode < m_modes);
- if (m_base[mode] == m_emptyl1)
- {
- drccodeptr **newtable = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits);
- if (newtable == NULL)
- return false;
- memcpy(newtable, m_emptyl1, sizeof(drccodeptr *) << m_l1bits);
- m_base[mode] = newtable;
- }
-
- // copy-on-write for the l2 hash table
- UINT32 l1 = (pc >> m_l1shift) & m_l1mask;
- if (m_base[mode][l1] == m_emptyl2)
- {
- drccodeptr *newtable = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits);
- if (newtable == NULL)
- return false;
- memcpy(newtable, m_emptyl2, sizeof(drccodeptr) << m_l2bits);
- m_base[mode][l1] = newtable;
- }
-
- // set the new entry
- UINT32 l2 = (pc >> m_l2shift) & m_l2mask;
- m_base[mode][l1][l2] = code;
- return true;
-}
-
-
-
-//**************************************************************************
-// DRC MAP VARIABLES
-//**************************************************************************
-
-//-------------------------------------------------
-// drc_map_variables - constructor
-//-------------------------------------------------
-
-drc_map_variables::drc_map_variables(drc_cache &cache, UINT64 uniquevalue)
- : m_cache(cache),
- m_uniquevalue(uniquevalue)
-{
- memset(m_mapvalue, 0, sizeof(m_mapvalue));
-}
-
-
-//-------------------------------------------------
-// ~drc_map_variables - destructor
-//-------------------------------------------------
-
-drc_map_variables::~drc_map_variables()
-{
- // must detach all items from the entry list so that the list object
- // doesn't try to free them on exit
- m_entry_list.detach_all();
-}
-
-
-//-------------------------------------------------
-// block_begin - note the beginning of a block
-//-------------------------------------------------
-
-void drc_map_variables::block_begin(drcuml_block &block)
-{
- // release any remaining live entries
- map_entry *entry;
- while ((entry = m_entry_list.detach_head()) != NULL)
- m_cache.dealloc(entry, sizeof(*entry));
-
- // reset the variable values
- memset(m_mapvalue, 0, sizeof(m_mapvalue));
-}
-
-
-//-------------------------------------------------
-// block_end - note the end of a block
-//-------------------------------------------------
-
-void drc_map_variables::block_end(drcuml_block &block)
-{
- // only process if we have data
- if (m_entry_list.first() == NULL)
- return;
-
- // begin "code generation" aligned to an 8-byte boundary
- drccodeptr *top = m_cache.begin_codegen(sizeof(UINT64) + sizeof(UINT32) + 2 * sizeof(UINT32) * m_entry_list.count());
- if (top == NULL)
- block.abort();
- UINT32 *dest = (UINT32 *)(((FPTR)*top + 7) & ~7);
-
- // store the cookie first
- *(UINT64 *)dest = m_uniquevalue;
- dest += 2;
-
- // get the pointer to the first item and store an initial backwards offset
- drccodeptr lastptr = m_entry_list.first()->m_codeptr;
- *dest = (drccodeptr)dest - lastptr;
- dest++;
-
- // now iterate over entries and store them
- UINT32 curvalue[MAPVAR_COUNT] = { 0 };
- bool changed[MAPVAR_COUNT] = { false };
- for (map_entry *entry = m_entry_list.first(); entry != NULL; entry = entry->next())
- {
- // update the current value of the variable and detect changes
- if (curvalue[entry->m_mapvar] != entry->m_newval)
- {
- curvalue[entry->m_mapvar] = entry->m_newval;
- changed[entry->m_mapvar] = true;
- }
-
- // if the next code pointer is different, or if we're at the end, flush changes
- if (entry->next() == NULL || entry->next()->m_codeptr != entry->m_codeptr)
- {
- // build a mask of changed variables
- int numchanged = 0;
- UINT32 varmask = 0;
- for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
- if (changed[varnum])
- {
- changed[varnum] = false;
- varmask |= 1 << varnum;
- numchanged++;
- }
-
- // if nothing really changed, skip it
- if (numchanged == 0)
- continue;
-
- // first word is a code delta plus mask of changed variables
- UINT32 codedelta = entry->m_codeptr - lastptr;
- while (codedelta > 0xffff)
- {
- *dest++ = 0xffff << 16;
- codedelta -= 0xffff;
- }
- *dest++ = (codedelta << 16) | (varmask << 4) | numchanged;
-
- // now output updated variable values
- for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
- if ((varmask >> varnum) & 1)
- *dest++ = curvalue[varnum];
-
- // remember our lastptr
- lastptr = entry->m_codeptr;
- }
- }
-
- // add a terminator
- *dest++ = 0;
-
- // complete codegen
- *top = (drccodeptr)dest;
- m_cache.end_codegen();
-}
-
-
-//-------------------------------------------------
-// set_value - set a map value for the given
-// code pointer
-//-------------------------------------------------
-
-void drc_map_variables::set_value(drccodeptr codebase, UINT32 mapvar, UINT32 newvalue)
-{
- assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END);
-
- // if this value isn't different, skip it
- if (m_mapvalue[mapvar - MAPVAR_M0] == newvalue)
- return;
-
- // allocate a new entry and fill it in
- map_entry *entry = (map_entry *)m_cache.alloc(sizeof(*entry));
- entry->m_next = NULL;
- entry->m_codeptr = codebase;
- entry->m_mapvar = mapvar - MAPVAR_M0;
- entry->m_newval = newvalue;
-
- // hook us into the end of the list
- m_entry_list.append(*entry);
-
- // update our state in the table as well
- m_mapvalue[mapvar - MAPVAR_M0] = newvalue;
-}
-
-
-//-------------------------------------------------
-// get_value - return a map value for the given
-// code pointer
-//-------------------------------------------------
-
-UINT32 drc_map_variables::get_value(drccodeptr codebase, UINT32 mapvar) const
-{
- assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END);
- mapvar -= MAPVAR_M0;
-
- // get an aligned pointer to start scanning
- UINT64 *curscan = (UINT64 *)(((FPTR)codebase | 7) + 1);
- UINT64 *endscan = (UINT64 *)m_cache.top();
-
- // look for the signature
- while (curscan < endscan && *curscan++ != m_uniquevalue) ;
- if (curscan >= endscan)
- return 0;
-
- // switch to 32-bit pointers for processing the rest
- UINT32 *data = (UINT32 *)curscan;
-
- // first get the 32-bit starting offset to the code
- drccodeptr curcode = (drccodeptr)data - *data;
- data++;
-
- // now loop until we advance past our target
- UINT32 varmask = 0x10 << mapvar;
- UINT32 result = 0;
- while (true)
- {
- // a 0 is a terminator
- UINT32 controlword = *data++;
- if (controlword == 0)
- break;
-
- // update the codeptr; if this puts us past the end, we're done
- curcode += (controlword >> 16) & 0xffff;
- if (curcode > codebase)
- break;
-
- // if our mapvar has changed, process this word
- if ((controlword & varmask) != 0)
- {
- // count how many words precede the one we care about
- int dataoffs = 0;
- for (UINT32 skipmask = (controlword & (varmask - 1)) >> 4; skipmask != 0; skipmask = skipmask & (skipmask - 1))
- dataoffs++;
-
- // fetch the one we want
- result = data[dataoffs];
- }
-
- // low 4 bits contain the total number of words of data
- data += controlword & 0x0f;
- }
- if (LOG_RECOVER)
- printf("recover %d @ %p = %08X\n", mapvar, codebase, result);
- return result;
-}
-
-UINT32 drc_map_variables::static_get_value(drc_map_variables &map, drccodeptr codebase, UINT32 mapvar)
-{
- return map.get_value(codebase, mapvar);
-}
-
-
-
-//-------------------------------------------------
-// get_last_value - return the most recently set
-// map value
-//-------------------------------------------------
-
-UINT32 drc_map_variables::get_last_value(UINT32 mapvar)
-{
- assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END);
- return m_mapvalue[mapvar - MAPVAR_M0];
-}
-
-
-
-//**************************************************************************
-// DRC LABEL LIST
-//**************************************************************************
-
-//-------------------------------------------------
-// drc_label_list - constructor
-//-------------------------------------------------
-
-drc_label_list::drc_label_list(drc_cache &cache)
- : m_cache(cache),
- m_oob_callback_delegate(FUNC(drc_label_list::oob_callback), this)
-{
-}
-
-
-//-------------------------------------------------
-// ~drc_label_list - destructor
-//-------------------------------------------------
-
-drc_label_list::~drc_label_list()
-{
- // must detach all items from the entry list so that the list object
- // doesn't try to free them on exit
- m_list.detach_all();
-}
-
-
-//-------------------------------------------------
-// block_begin - note the beginning of a block
-//-------------------------------------------------
-
-void drc_label_list::block_begin(drcuml_block &block)
-{
- // make sure the label list is clear, but don't fatalerror
- reset(false);
-}
-
-
-//-------------------------------------------------
-// block_end - note the end of a block
-//-------------------------------------------------
-
-void drc_label_list::block_end(drcuml_block &block)
-{
- // can't free until the cache is clean of our OOB requests
- assert(!m_cache.generating_code());
-
- // free all of the pending fixup requests
- label_fixup *fixup;
- while ((fixup = m_fixup_list.detach_head()) != NULL)
- m_cache.dealloc(fixup, sizeof(*fixup));
-
- // make sure the label list is clear, and fatalerror if we missed anything
- reset(true);
-}
-
-
-//-------------------------------------------------
-// get_codeptr - find or allocate a new label;
-// returns NULL and requests an OOB callback if
-// undefined
-//-------------------------------------------------
-
-drccodeptr drc_label_list::get_codeptr(uml::code_label label, drc_label_fixup_delegate callback, void *param)
-{
- label_entry *curlabel = find_or_allocate(label);
-
- // if no code pointer, request an OOB callback
- if (curlabel->m_codeptr == NULL && !callback.isnull())
- {
- label_fixup *fixup = reinterpret_cast<label_fixup *>(m_cache.alloc(sizeof(*fixup)));
- fixup->m_callback = callback;
- fixup->m_label = curlabel;
- m_fixup_list.append(*fixup);
- m_cache.request_oob_codegen(m_oob_callback_delegate, fixup, param);
- }
-
- return curlabel->m_codeptr;
-}
-
-
-//-------------------------------------------------
-// set_codeptr - set the pointer to a new label
-//-------------------------------------------------
-
-void drc_label_list::set_codeptr(uml::code_label label, drccodeptr codeptr)
-{
- // set the code pointer
- label_entry *curlabel = find_or_allocate(label);
- assert(curlabel->m_codeptr == NULL);
- curlabel->m_codeptr = codeptr;
-}
-
-
-//-------------------------------------------------
-// reset - reset a label list (add all entries to
-// the free list)
-//-------------------------------------------------
-
-void drc_label_list::reset(bool fatal_on_leftovers)
-{
- // loop until out of labels
- label_entry *curlabel;
- while ((curlabel = m_list.detach_head()) != NULL)
- {
- // fatal if we were a leftover
- if (fatal_on_leftovers && curlabel->m_codeptr == NULL)
- fatalerror("Label %08X never defined!\n", curlabel->m_label.label());
-
- // free the label
- m_cache.dealloc(curlabel, sizeof(*curlabel));
- }
-}
-
-
-//-------------------------------------------------
-// find_or_allocate - look up a label and
-// allocate a new one if not found
-//-------------------------------------------------
-
-drc_label_list::label_entry *drc_label_list::find_or_allocate(uml::code_label label)
-{
- // find the label, or else allocate a new one
- label_entry *curlabel;
- for (curlabel = m_list.first(); curlabel != NULL; curlabel = curlabel->next())
- if (curlabel->m_label == label)
- break;
-
- // if none found, allocate
- if (curlabel == NULL)
- {
- curlabel = (label_entry *)m_cache.alloc(sizeof(*curlabel));
- curlabel->m_label = label;
- curlabel->m_codeptr = NULL;
- m_list.append(*curlabel);
- }
- return curlabel;
-}
-
-
-//-------------------------------------------------
-// oob_callback - out-of-band codegen callback
-// for labels
-//-------------------------------------------------
-
-void drc_label_list::oob_callback(drccodeptr *codeptr, void *param1, void *param2)
-{
- label_fixup *fixup = reinterpret_cast<label_fixup *>(param1);
- fixup->m_callback(param2, fixup->m_label->m_codeptr);
-}