C++-ified the DRC backend utility helpers.

This commit is contained in:
Aaron Giles 2011-01-06 18:24:58 +00:00
parent ed94203e79
commit 159e684763
5 changed files with 521 additions and 650 deletions

View File

@ -217,9 +217,9 @@ struct _drcbe_state
drcuml_state * drcuml; /* pointer back to our owner */ drcuml_state * drcuml; /* pointer back to our owner */
drc_cache * cache; /* pointer to the cache */ drc_cache * cache; /* pointer to the cache */
drcuml_machine_state state; /* state of the machine */ drcuml_machine_state state; /* state of the machine */
drchash_state * hash; /* hash table state */ drc_hash_table * hash; /* hash table state */
drcmap_state * map; /* code map */ drc_map_variables * map; /* code map */
drclabel_list * labels; /* label list */ drc_label_list * labels; /* label list */
}; };
@ -358,19 +358,13 @@ static drcbe_state *drcbec_alloc(drcuml_state *drcuml, drc_cache *cache, device_
drcbe->cache = cache; drcbe->cache = cache;
/* allocate hash tables */ /* allocate hash tables */
drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits); drcbe->hash = auto_alloc(device->machine, drc_hash_table(*cache, modes, addrbits, ignorebits));
if (drcbe->hash == NULL)
return NULL;
/* allocate code map */ /* allocate code map */
drcbe->map = drcmap_alloc(cache, 0); drcbe->map = auto_alloc(device->machine, drc_map_variables(*cache, 0));
if (drcbe->map == NULL)
return NULL;
/* allocate a label tracker */ /* allocate a label tracker */
drcbe->labels = drclabel_list_alloc(cache); drcbe->labels = auto_alloc(device->machine, drc_label_list(*cache));
if (drcbe->labels == NULL)
return NULL;
return drcbe; return drcbe;
} }
@ -392,8 +386,8 @@ static void drcbec_free(drcbe_state *drcbe)
static void drcbec_reset(drcbe_state *drcbe) static void drcbec_reset(drcbe_state *drcbe)
{ {
/* reset our hash tables */ /* reset our hash tables */
drchash_reset(drcbe->hash); drcbe->hash->reset();
drchash_set_default_codeptr(drcbe->hash, NULL); drcbe->hash->set_default_codeptr(NULL);
} }
@ -409,9 +403,9 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
int inum; int inum;
/* tell all of our utility objects that a block is beginning */ /* tell all of our utility objects that a block is beginning */
drchash_block_begin(drcbe->hash, block, instlist, numinst); drcbe->hash->block_begin(*block, instlist, numinst);
drclabel_block_begin(drcbe->labels, block); drcbe->labels->block_begin(*block);
drcmap_block_begin(drcbe->map, block); drcbe->map->block_begin(*block);
/* begin codegen; fail if we can't */ /* begin codegen; fail if we can't */
cachetop = drcbe->cache->begin_codegen(numinst * sizeof(drcbec_instruction) * 4); cachetop = drcbe->cache->begin_codegen(numinst * sizeof(drcbec_instruction) * 4);
@ -445,14 +439,14 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
/* when we hit a HASH opcode, register the current pointer for the mode/PC */ /* when we hit a HASH opcode, register the current pointer for the mode/PC */
case DRCUML_OP_HASH: case DRCUML_OP_HASH:
/* we already verified the parameter count and types above */ /* we already verified the parameter count and types above */
drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, (drccodeptr)dst); drcbe->hash->set_codeptr(inst->param[0].value, inst->param[1].value, (drccodeptr)dst);
break; break;
/* when we hit a LABEL opcode, register the current pointer for the label */ /* when we hit a LABEL opcode, register the current pointer for the label */
case DRCUML_OP_LABEL: case DRCUML_OP_LABEL:
assert(inst->numparams == 1); assert(inst->numparams == 1);
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
drclabel_set_codeptr(drcbe->labels, inst->param[0].value, (drccodeptr)dst); drcbe->labels->set_codeptr(inst->param[0].value, (drccodeptr)dst);
break; break;
/* ignore COMMENT and NOP opcodes */ /* ignore COMMENT and NOP opcodes */
@ -465,7 +459,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
assert(inst->numparams == 2); assert(inst->numparams == 2);
assert(inst->param[0].type == DRCUML_PTYPE_MAPVAR); assert(inst->param[0].type == DRCUML_PTYPE_MAPVAR);
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
drcmap_set_value(drcbe->map, (drccodeptr)dst, inst->param[0].value, inst->param[1].value); drcbe->map->set_value((drccodeptr)dst, inst->param[0].value, inst->param[1].value);
break; break;
/* JMP instructions need to resolve their labels */ /* JMP instructions need to resolve their labels */
@ -473,7 +467,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
assert(inst->numparams == 1); assert(inst->numparams == 1);
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
(dst++)->i = MAKE_OPCODE_FULL(opcode, inst->size, inst->condition, inst->flags, 1); (dst++)->i = MAKE_OPCODE_FULL(opcode, inst->size, inst->condition, inst->flags, 1);
dst->inst = (drcbec_instruction *)drclabel_get_codeptr(drcbe->labels, inst->param[0].value, fixup_label, dst); dst->inst = (drcbec_instruction *)drcbe->labels->get_codeptr(inst->param[0].value, fixup_label, dst);
dst++; dst++;
break; break;
@ -562,9 +556,9 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
drcbe->cache->end_codegen(); drcbe->cache->end_codegen();
/* tell all of our utility objects that the block is finished */ /* tell all of our utility objects that the block is finished */
drchash_block_end(drcbe->hash, block); drcbe->hash->block_end(*block);
drclabel_block_end(drcbe->labels, block); drcbe->labels->block_end(*block);
drcmap_block_end(drcbe->map, block); drcbe->map->block_end(*block);
} }
@ -575,7 +569,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum
static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc) static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc)
{ {
return drchash_code_exists(state->hash, mode, pc); return state->hash->code_exists(mode, pc);
} }
@ -641,7 +635,7 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
case MAKE_OPCODE_SHORT(DRCUML_OP_HASHJMP, 4, 0): /* HASHJMP mode,pc,handle */ case MAKE_OPCODE_SHORT(DRCUML_OP_HASHJMP, 4, 0): /* HASHJMP mode,pc,handle */
sp = 0; sp = 0;
newinst = (const drcbec_instruction *)drchash_get_codeptr(drcbe->hash, PARAM0, PARAM1); newinst = (const drcbec_instruction *)drcbe->hash->get_codeptr(PARAM0, PARAM1);
if (newinst == NULL) if (newinst == NULL)
{ {
assert(sp < ARRAY_LENGTH(callstack)); assert(sp < ARRAY_LENGTH(callstack));
@ -722,7 +716,7 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
case MAKE_OPCODE_SHORT(DRCUML_OP_RECOVER, 4, 0): /* RECOVER dst,mapvar */ case MAKE_OPCODE_SHORT(DRCUML_OP_RECOVER, 4, 0): /* RECOVER dst,mapvar */
assert(sp > 0); assert(sp > 0);
PARAM0 = drcmap_get_value(drcbe->map, (drccodeptr)callstack[0], PARAM1); PARAM0 = drcbe->map->get_value((drccodeptr)callstack[0], PARAM1);
break; break;
@ -2189,7 +2183,7 @@ static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, vo
{ {
/* convert mapvars to immediates */ /* convert mapvars to immediates */
case DRCUML_PTYPE_MAPVAR: case DRCUML_PTYPE_MAPVAR:
temp_param.value = drcmap_get_last_value(drcbe->map, param->value); temp_param.value = drcbe->map->get_last_value(param->value);
param = &temp_param; param = &temp_param;
/* fall through to immediate case */ /* fall through to immediate case */

View File

@ -21,251 +21,172 @@
#define LOG_RECOVER (0) #define LOG_RECOVER (0)
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
/* structure holding information about a single label */
typedef struct _drcmap_entry drcmap_entry;
struct _drcmap_entry
{
drcmap_entry * next; /* pointer to next map entry */
drccodeptr codeptr; /* pointer to the relevant code */
UINT32 mapvar; /* map variable id */
UINT32 newval; /* value of the variable starting at codeptr */
};
/* structure describing the state of the code map */
struct _drcmap_state
{
drc_cache * cache; /* pointer to the cache */
UINT64 uniquevalue; /* unique value used to find the table */
drcmap_entry * head; /* head of the live list */
drcmap_entry ** tailptr; /* pointer to tail of the live list */
UINT32 numvalues; /* number of values in the list */
UINT32 mapvalue[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0]; /* array of current values */
};
/* structure holding information about a single label */
typedef struct _drclabel drclabel;
struct _drclabel
{
drclabel * next; /* pointer to next label */
drcuml_codelabel label; /* the label specified */
drccodeptr codeptr; /* pointer to the relevant code */
};
/* structure holding a live list of labels */
struct _drclabel_list
{
drc_cache * cache; /* pointer to the cache */
drclabel * head; /* head of the live list */
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
static void label_list_reset(drclabel_list *list, int fatal_on_leftovers);
static drclabel *label_find_or_allocate(drclabel_list *list, drcuml_codelabel label);
static void label_oob_callback(drccodeptr *codeptr, void *param1, void *param2, void *param3);
/*************************************************************************** /***************************************************************************
HASH TABLE MANAGEMENT HASH TABLE MANAGEMENT
***************************************************************************/ ***************************************************************************/
/*------------------------------------------------- //-------------------------------------------------
drchash_alloc - allocate memory in the cache // drc_hash_table - constructor
for the hash table tracker (it auto-frees //-------------------------------------------------
with the cache)
-------------------------------------------------*/
drchash_state *drchash_alloc(drc_cache *cache, int modes, int addrbits, int ignorebits) 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)
{ {
int effaddrbits = addrbits - ignorebits; reset();
drchash_state *drchash;
/* allocate permanent state from the cache */
drchash = (drchash_state *)cache->alloc(sizeof(*drchash) + modes * sizeof(drchash->base[0]));
if (drchash == NULL)
return NULL;
memset(drchash, 0, sizeof(*drchash) + modes * sizeof(drchash->base[0]));
/* copy in parameters */
drchash->cache = cache;
drchash->modes = modes;
/* compute the sizes of the tables */
drchash->l1bits = effaddrbits / 2;
drchash->l2bits = effaddrbits - drchash->l1bits;
drchash->l1shift = ignorebits + drchash->l2bits;
drchash->l2shift = ignorebits;
drchash->l1mask = (1 << drchash->l1bits) - 1;
drchash->l2mask = (1 << drchash->l2bits) - 1;
/* reset the hash table, which allocates any subsequent tables */
if (!drchash_reset(drchash))
return NULL;
return drchash;
} }
/*------------------------------------------------- //-------------------------------------------------
drchash_reset - flush existing hash tables and // reset - flush existing hash tables and create
create new ones // new ones
-------------------------------------------------*/ //-------------------------------------------------
int drchash_reset(drchash_state *drchash) bool drc_hash_table::reset()
{ {
int modenum, entry; // allocate an empty l2 hash table
m_emptyl2 = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits);
if (m_emptyl2 == NULL)
return false;
/* allocate an empty l2 hash table */ // populate it with pointers to the recompile_exit code
drchash->emptyl2 = (drccodeptr *)drchash->cache->alloc_temporary(sizeof(drccodeptr) << drchash->l2bits); for (int entry = 0; entry < (1 << m_l2bits); entry++)
if (drchash->emptyl2 == NULL) m_emptyl2[entry] = m_nocodeptr;
return FALSE;
/* populate it with pointers to the recompile_exit code */ // allocate an empty l1 hash table
for (entry = 0; entry < (1 << drchash->l2bits); entry++) m_emptyl1 = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits);
drchash->emptyl2[entry] = drchash->nocodeptr; if (m_emptyl1 == NULL)
return false;
/* allocate an empty l1 hash table */ // populate it with pointers to the empty l2 table
drchash->emptyl1 = (drccodeptr **)drchash->cache->alloc_temporary(sizeof(drccodeptr *) << drchash->l1bits); for (int entry = 0; entry < (1 << m_l1bits); entry++)
if (drchash->emptyl1 == NULL) m_emptyl1[entry] = m_emptyl2;
return FALSE;
/* populate it with pointers to the empty l2 table */ // reset the hash tables
for (entry = 0; entry < (1 << drchash->l1bits); entry++) for (int modenum = 0; modenum < m_modes; modenum++)
drchash->emptyl1[entry] = drchash->emptyl2; m_base[modenum] = m_emptyl1;
/* reset the hash tables */ return true;
for (modenum = 0; modenum < drchash->modes; modenum++)
drchash->base[modenum] = drchash->emptyl1;
return TRUE;
} }
/*------------------------------------------------- //-------------------------------------------------
drchash_block_begin - note the beginning of a // block_begin - note the beginning of a block
block //-------------------------------------------------
-------------------------------------------------*/
void drchash_block_begin(drchash_state *drchash, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst) void drc_hash_table::block_begin(drcuml_block &block, const drcuml_instruction *instlist, UINT32 numinst)
{ {
int inum; // before generating code, pre-allocate any hash entries; we do this by setting dummy hash values
for (int inum = 0; inum < numinst; inum++)
/* before generating code, pre-allocate any hash entries; we do this by setting dummy hash values */
for (inum = 0; inum < numinst; inum++)
{ {
const drcuml_instruction *inst = &instlist[inum]; const drcuml_instruction &inst = instlist[inum];
/* if the opcode is a hash, verify that it makes sense and then set a NULL entry */ // if the opcode is a hash, verify that it makes sense and then set a NULL entry
if (inst->opcode == DRCUML_OP_HASH) if (inst.opcode == DRCUML_OP_HASH)
{ {
assert(inst->numparams == 2); assert(inst.numparams == 2);
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); assert(inst.param[0].type == DRCUML_PTYPE_IMMEDIATE);
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst.param[1].type == DRCUML_PTYPE_IMMEDIATE);
/* if we fail to allocate, we must abort the block */ // if we fail to allocate, we must abort the block
if (!drchash_set_codeptr(drchash, inst->param[0].value, inst->param[1].value, NULL)) if (!set_codeptr(inst.param[0].value, inst.param[1].value, NULL))
drcuml_block_abort(block); drcuml_block_abort(&block);
} }
/* if the opcode is a hashjmp to a fixed location, make sure we preallocate the tables */ // if the opcode is a hashjmp to a fixed location, make sure we preallocate the tables
if (inst->opcode == DRCUML_OP_HASHJMP && inst->param[0].type == DRCUML_PTYPE_IMMEDIATE && inst->param[1].type == DRCUML_PTYPE_IMMEDIATE) if (inst.opcode == DRCUML_OP_HASHJMP && inst.param[0].type == DRCUML_PTYPE_IMMEDIATE && inst.param[1].type == DRCUML_PTYPE_IMMEDIATE)
{ {
/* if we fail to allocate, we must abort the block */ // if we fail to allocate, we must abort the block
drccodeptr code = drchash_get_codeptr(drchash, inst->param[0].value, inst->param[1].value); drccodeptr code = get_codeptr(inst.param[0].value, inst.param[1].value);
if (!drchash_set_codeptr(drchash, inst->param[0].value, inst->param[1].value, code)) if (!set_codeptr(inst.param[0].value, inst.param[1].value, code))
drcuml_block_abort(block); drcuml_block_abort(&block);
} }
} }
} }
/*------------------------------------------------- //-------------------------------------------------
drchash_block_end - note the end of a block // block_end - note the end of a block
-------------------------------------------------*/ //-------------------------------------------------
void drchash_block_end(drchash_state *drchash, drcuml_block *block) void drc_hash_table::block_end(drcuml_block &block)
{ {
/* nothing to do here, yet */ // nothing to do here, yet
} }
/*------------------------------------------------- //-------------------------------------------------
drchash_set_default_codeptr - change the // set_default_codeptr - change the default
default codeptr // codeptr
-------------------------------------------------*/ //-------------------------------------------------
void drchash_set_default_codeptr(drchash_state *drchash, drccodeptr nocodeptr) void drc_hash_table::set_default_codeptr(drccodeptr nocodeptr)
{ {
drccodeptr old = drchash->nocodeptr; // nothing to do if the same
int modenum, l1entry, l2entry; drccodeptr old = m_nocodeptr;
/* nothing to do if the same */
if (old == nocodeptr) if (old == nocodeptr)
return; return;
drchash->nocodeptr = nocodeptr; m_nocodeptr = nocodeptr;
/* update the empty L2 table first */ // update the empty L2 table first
for (l2entry = 0; l2entry < (1 << drchash->l2bits); l2entry++) for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++)
drchash->emptyl2[l2entry] = nocodeptr; m_emptyl2[l2entry] = nocodeptr;
/* now scan all existing hashtables for entries */ // now scan all existing hashtables for entries
for (modenum = 0; modenum < drchash->modes; modenum++) for (int modenum = 0; modenum < m_modes; modenum++)
if (drchash->base[modenum] != drchash->emptyl1) if (m_base[modenum] != m_emptyl1)
for (l1entry = 0; l1entry < (1 << drchash->l1bits); l1entry++) for (int l1entry = 0; l1entry < (1 << m_l1bits); l1entry++)
if (drchash->base[modenum][l1entry] != drchash->emptyl2) if (m_base[modenum][l1entry] != m_emptyl2)
for (l2entry = 0; l2entry < (1 << drchash->l2bits); l2entry++) for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++)
if (drchash->base[modenum][l1entry][l2entry] == old) if (m_base[modenum][l1entry][l2entry] == old)
drchash->base[modenum][l1entry][l2entry] = nocodeptr; m_base[modenum][l1entry][l2entry] = nocodeptr;
} }
/*------------------------------------------------- //-------------------------------------------------
drchash_set_codeptr - set the codeptr for the // set_codeptr - set the codeptr for the given
given mode/pc // mode/pc
-------------------------------------------------*/ //-------------------------------------------------
int drchash_set_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc, drccodeptr code) bool drc_hash_table::set_codeptr(UINT32 mode, UINT32 pc, drccodeptr code)
{ {
UINT32 l1 = (pc >> drchash->l1shift) & drchash->l1mask; // copy-on-write for the l1 hash table
UINT32 l2 = (pc >> drchash->l2shift) & drchash->l2mask; assert(mode < m_modes);
if (m_base[mode] == m_emptyl1)
assert(mode < drchash->modes);
/* copy-on-write for the l1 hash table */
if (drchash->base[mode] == drchash->emptyl1)
{ {
drccodeptr **newtable = (drccodeptr **)drchash->cache->alloc_temporary(sizeof(drccodeptr *) << drchash->l1bits); drccodeptr **newtable = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits);
if (newtable == NULL) if (newtable == NULL)
return FALSE; return false;
memcpy(newtable, drchash->emptyl1, sizeof(drccodeptr *) << drchash->l1bits); memcpy(newtable, m_emptyl1, sizeof(drccodeptr *) << m_l1bits);
drchash->base[mode] = newtable; m_base[mode] = newtable;
} }
/* copy-on-write for the l2 hash table */ // copy-on-write for the l2 hash table
if (drchash->base[mode][l1] == drchash->emptyl2) UINT32 l1 = (pc >> m_l1shift) & m_l1mask;
if (m_base[mode][l1] == m_emptyl2)
{ {
drccodeptr *newtable = (drccodeptr *)drchash->cache->alloc_temporary(sizeof(drccodeptr) << drchash->l2bits); drccodeptr *newtable = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits);
if (newtable == NULL) if (newtable == NULL)
return FALSE; return false;
memcpy(newtable, drchash->emptyl2, sizeof(drccodeptr) << drchash->l2bits); memcpy(newtable, m_emptyl2, sizeof(drccodeptr) << m_l2bits);
drchash->base[mode][l1] = newtable; m_base[mode][l1] = newtable;
} }
/* set the new entry */ // set the new entry
drchash->base[mode][l1][l2] = code; UINT32 l2 = (pc >> m_l2shift) & m_l2mask;
return TRUE; m_base[mode][l1][l2] = code;
return true;
} }
@ -274,118 +195,103 @@ int drchash_set_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc, drccodep
CODE MAP MANAGEMENT CODE MAP MANAGEMENT
***************************************************************************/ ***************************************************************************/
/*------------------------------------------------- //-------------------------------------------------
drcmap_alloc - allocate memory in the cache // drc_map_variables - constructor
for the code mapper (it auto-frees with the //-------------------------------------------------
cache)
-------------------------------------------------*/
drcmap_state *drcmap_alloc(drc_cache *cache, UINT64 uniquevalue) drc_map_variables::drc_map_variables(drc_cache &cache, UINT64 uniquevalue)
: m_cache(cache),
m_uniquevalue(uniquevalue)
{ {
drcmap_state *drcmap; memset(m_mapvalue, 0, sizeof(m_mapvalue));
/* allocate permanent state from the cache */
drcmap = (drcmap_state *)cache->alloc(sizeof(*drcmap));
if (drcmap == NULL)
return NULL;
memset(drcmap, 0, sizeof(*drcmap));
/* remember the cache */
drcmap->cache = cache;
drcmap->tailptr = &drcmap->head;
return drcmap;
} }
/*------------------------------------------------- //-------------------------------------------------
drcmap_block_begin - note the beginning of a // ~drc_map_variables - destructor
block //-------------------------------------------------
-------------------------------------------------*/
void drcmap_block_begin(drcmap_state *drcmap, drcuml_block *block) drc_map_variables::~drc_map_variables()
{ {
/* release any remaining live entries */ // must detach all items from the entry list so that the list object
while (drcmap->head != NULL) // doesn't try to free them on exit
{ m_entry_list.detach_all();
drcmap_entry *entry = drcmap->head;
drcmap->head = entry->next;
drcmap->cache->dealloc(entry, sizeof(*entry));
}
/* reset the tailptr and count */
drcmap->tailptr = &drcmap->head;
drcmap->numvalues = 0;
/* reset the variable values */
memset(drcmap->mapvalue, 0, sizeof(drcmap->mapvalue));
} }
/*------------------------------------------------- //-------------------------------------------------
drcmap_block_end - note the end of a block // block_begin - note the beginning of a block
-------------------------------------------------*/ //-------------------------------------------------
void drcmap_block_end(drcmap_state *drcmap, drcuml_block *block) void drc_map_variables::block_begin(drcuml_block &block)
{ {
UINT32 curvalue[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0] = { 0 }; // release any remaining live entries
UINT8 changed[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0] = { 0 }; map_entry *entry;
drcmap_entry *entry; while ((entry = m_entry_list.detach_head()) != NULL)
drccodeptr lastptr; m_cache.dealloc(entry, sizeof(*entry));
drccodeptr *top;
UINT32 *dest;
/* only process if we have data */ // reset the variable values
if (drcmap->head == NULL) 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; return;
/* begin "code generation" aligned to an 8-byte boundary */ // begin "code generation" aligned to an 8-byte boundary
top = drcmap->cache->begin_codegen(sizeof(UINT64) + sizeof(UINT32) + 2 * sizeof(UINT32) * drcmap->numvalues); drccodeptr *top = m_cache.begin_codegen(sizeof(UINT64) + sizeof(UINT32) + 2 * sizeof(UINT32) * m_entry_list.count());
if (top == NULL) if (top == NULL)
drcuml_block_abort(block); drcuml_block_abort(&block);
dest = (UINT32 *)(((FPTR)*top + 7) & ~7); UINT32 *dest = (UINT32 *)(((FPTR)*top + 7) & ~7);
/* store the cookie first */ // store the cookie first
*(UINT64 *)dest = drcmap->uniquevalue; *(UINT64 *)dest = m_uniquevalue;
dest += 2; dest += 2;
/* get the pointer to the first item and store an initial backwards offset */ // get the pointer to the first item and store an initial backwards offset
lastptr = drcmap->head->codeptr; drccodeptr lastptr = m_entry_list.first()->m_codeptr;
*dest = (drccodeptr)dest - lastptr; *dest = (drccodeptr)dest - lastptr;
dest++; dest++;
/* now iterate over entries and store them */ // now iterate over entries and store them
for (entry = drcmap->head; entry != NULL; entry = entry->next) UINT32 curvalue[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0] = { 0 };
bool changed[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0] = { false };
for (map_entry *entry = m_entry_list.first(); entry != NULL; entry = entry->next())
{ {
/* update the current value of the variable and detect changes */ // update the current value of the variable and detect changes
if (curvalue[entry->mapvar] != entry->newval) if (curvalue[entry->m_mapvar] != entry->m_newval)
{ {
curvalue[entry->mapvar] = entry->newval; curvalue[entry->m_mapvar] = entry->m_newval;
changed[entry->mapvar] = TRUE; changed[entry->m_mapvar] = true;
} }
/* if the next code pointer is different, or if we're at the end, flush changes */ // if the next code pointer is different, or if we're at the end, flush changes
if (entry->next == NULL || entry->next->codeptr != entry->codeptr) if (entry->next() == NULL || entry->next()->m_codeptr != entry->m_codeptr)
{ {
UINT32 codedelta = entry->codeptr - lastptr; // build a mask of changed variables
int numchanged = 0;
UINT32 varmask = 0; UINT32 varmask = 0;
int numchanged; for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
int varnum;
/* build a mask of changed variables */
for (numchanged = varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
if (changed[varnum]) if (changed[varnum])
{ {
changed[varnum] = FALSE; changed[varnum] = false;
varmask |= 1 << varnum; varmask |= 1 << varnum;
numchanged++; numchanged++;
} }
/* if nothing really changed, skip it */ // if nothing really changed, skip it
if (numchanged == 0) if (numchanged == 0)
continue; continue;
/* first word is a code delta plus mask of changed variables */ // first word is a code delta plus mask of changed variables
UINT32 codedelta = entry->m_codeptr - lastptr;
while (codedelta > 0xffff) while (codedelta > 0xffff)
{ {
*dest++ = 0xffff << 16; *dest++ = 0xffff << 16;
@ -393,120 +299,107 @@ void drcmap_block_end(drcmap_state *drcmap, drcuml_block *block)
} }
*dest++ = (codedelta << 16) | (varmask << 4) | numchanged; *dest++ = (codedelta << 16) | (varmask << 4) | numchanged;
/* now output updated variable values */ // now output updated variable values
for (varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++) for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
if ((varmask >> varnum) & 1) if ((varmask >> varnum) & 1)
*dest++ = curvalue[varnum]; *dest++ = curvalue[varnum];
/* remember our lastptr */ // remember our lastptr
lastptr = entry->codeptr; lastptr = entry->m_codeptr;
} }
} }
/* add a terminator */ // add a terminator
*dest++ = 0; *dest++ = 0;
/* complete codegen */ // complete codegen
*top = (drccodeptr)dest; *top = (drccodeptr)dest;
drcmap->cache->end_codegen(); m_cache.end_codegen();
} }
/*------------------------------------------------- //-------------------------------------------------
drcmap_set_value - set a map value for the // set_value - set a map value for the given
given code pointer // code pointer
-------------------------------------------------*/ //-------------------------------------------------
void drcmap_set_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar, UINT32 newvalue) void drc_map_variables::set_value(drccodeptr codebase, UINT32 mapvar, UINT32 newvalue)
{ {
drcmap_entry *entry;
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END); assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
/* if this value isn't different, skip it */ // if this value isn't different, skip it
if (drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0] == newvalue) if (m_mapvalue[mapvar - DRCUML_MAPVAR_M0] == newvalue)
return; return;
/* allocate a new entry and fill it in */ // allocate a new entry and fill it in
entry = (drcmap_entry *)drcmap->cache->alloc(sizeof(*entry)); map_entry *entry = (map_entry *)m_cache.alloc(sizeof(*entry));
entry->next = NULL; entry->m_next = NULL;
entry->codeptr = codebase; entry->m_codeptr = codebase;
entry->mapvar = mapvar - DRCUML_MAPVAR_M0; entry->m_mapvar = mapvar - DRCUML_MAPVAR_M0;
entry->newval = newvalue; entry->m_newval = newvalue;
/* hook us into the end of the list */ // hook us into the end of the list
*drcmap->tailptr = entry; m_entry_list.append(*entry);
drcmap->tailptr = &entry->next;
/* update our state in the table as well */ // update our state in the table as well
drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0] = newvalue; m_mapvalue[mapvar - DRCUML_MAPVAR_M0] = newvalue;
/* and increment the count */
drcmap->numvalues++;
} }
/*------------------------------------------------- //-------------------------------------------------
drcmap_get_value - return a map value for the // get_value - return a map value for the given
given code pointer // code pointer
-------------------------------------------------*/ //-------------------------------------------------
UINT32 drcmap_get_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar) UINT32 drc_map_variables::get_value(drccodeptr codebase, UINT32 mapvar) const
{ {
UINT64 *endscan = (UINT64 *)drcmap->cache->top();
UINT32 varmask = 0x10 << mapvar;
drccodeptr curcode;
UINT32 result = 0;
UINT64 *curscan;
UINT32 *data;
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END); assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
mapvar -= DRCUML_MAPVAR_M0; mapvar -= DRCUML_MAPVAR_M0;
/* get an aligned pointer to start scanning */ // get an aligned pointer to start scanning
curscan = (UINT64 *)(((FPTR)codebase | 7) + 1); UINT64 *curscan = (UINT64 *)(((FPTR)codebase | 7) + 1);
UINT64 *endscan = (UINT64 *)m_cache.top();
/* look for the signature */ // look for the signature
while (curscan < endscan && *curscan++ != drcmap->uniquevalue) ; while (curscan < endscan && *curscan++ != m_uniquevalue) ;
if (curscan >= endscan) if (curscan >= endscan)
return 0; return 0;
/* switch to 32-bit pointers for processing the rest */ // switch to 32-bit pointers for processing the rest
data = (UINT32 *)curscan; UINT32 *data = (UINT32 *)curscan;
/* first get the 32-bit starting offset to the code */ // first get the 32-bit starting offset to the code
curcode = (drccodeptr)data - *data; drccodeptr curcode = (drccodeptr)data - *data;
data++; data++;
/* now loop until we advance past our target */ // now loop until we advance past our target
while (TRUE) UINT32 varmask = 0x10 << mapvar;
UINT32 result = 0;
while (true)
{ {
// a 0 is a terminator
UINT32 controlword = *data++; UINT32 controlword = *data++;
/* a 0 is a terminator */
if (controlword == 0) if (controlword == 0)
break; break;
/* update the codeptr; if this puts us past the end, we're done */ // update the codeptr; if this puts us past the end, we're done
curcode += (controlword >> 16) & 0xffff; curcode += (controlword >> 16) & 0xffff;
if (curcode > codebase) if (curcode > codebase)
break; break;
/* if our mapvar has changed, process this word */ // if our mapvar has changed, process this word
if ((controlword & varmask) != 0) if ((controlword & varmask) != 0)
{ {
// count how many words precede the one we care about
int dataoffs = 0; int dataoffs = 0;
UINT32 skipmask; for (UINT32 skipmask = (controlword & (varmask - 1)) >> 4; skipmask != 0; skipmask = skipmask & (skipmask - 1))
/* count how many words precede the one we care about */
for (skipmask = (controlword & (varmask - 1)) >> 4; skipmask != 0; skipmask = skipmask & (skipmask - 1))
dataoffs++; dataoffs++;
/* fetch the one we want */ // fetch the one we want
result = data[dataoffs]; result = data[dataoffs];
} }
/* low 4 bits contain the total number of words of data */ // low 4 bits contain the total number of words of data
data += controlword & 0x0f; data += controlword & 0x0f;
} }
if (LOG_RECOVER) if (LOG_RECOVER)
@ -514,16 +407,22 @@ UINT32 drcmap_get_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar
return result; return result;
} }
UINT32 drc_map_variables::static_get_value(drc_map_variables &map, drccodeptr codebase, UINT32 mapvar)
{
return map.get_value(codebase, mapvar);
}
/*-------------------------------------------------
drcmap_get_last_value - return the most
recently set map value
-------------------------------------------------*/
UINT32 drcmap_get_last_value(drcmap_state *drcmap, UINT32 mapvar)
//-------------------------------------------------
// get_last_value - return the most recently set
// map value
//-------------------------------------------------
UINT32 drc_map_variables::get_last_value(UINT32 mapvar)
{ {
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END); assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
return drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0]; return m_mapvalue[mapvar - DRCUML_MAPVAR_M0];
} }
@ -532,150 +431,136 @@ UINT32 drcmap_get_last_value(drcmap_state *drcmap, UINT32 mapvar)
LABEL MANAGEMENT LABEL MANAGEMENT
***************************************************************************/ ***************************************************************************/
/*------------------------------------------------- //-------------------------------------------------
drclabel_list_alloc - allocate a label // drc_label_list - constructor
list within the cache (it auto-frees with the //-------------------------------------------------
cache)
-------------------------------------------------*/
drclabel_list *drclabel_list_alloc(drc_cache *cache) drc_label_list::drc_label_list(drc_cache &cache)
: m_cache(cache)
{ {
drclabel_list *list;
/* allocate permanent state from the cache */
list = (drclabel_list *)cache->alloc(sizeof(*list));
if (list == NULL)
return NULL;
memset(list, 0, sizeof(*list));
/* remember the cache */
list->cache = cache;
return list;
} }
/*------------------------------------------------- //-------------------------------------------------
drclabel_block_begin - note the beginning of // ~drc_label_list - destructor
a block //-------------------------------------------------
-------------------------------------------------*/
void drclabel_block_begin(drclabel_list *list, drcuml_block *block) drc_label_list::~drc_label_list()
{ {
/* make sure the label list is clear, but don't fatalerror */ // must detach all items from the entry list so that the list object
label_list_reset(list, FALSE); // doesn't try to free them on exit
m_list.detach_all();
} }
/*------------------------------------------------- //-------------------------------------------------
drclabel_block_end - note the end of a block // block_begin - note the beginning of a block
-------------------------------------------------*/ //-------------------------------------------------
void drclabel_block_end(drclabel_list *list, drcuml_block *block) void drc_label_list::block_begin(drcuml_block &block)
{ {
/* make sure the label list is clear, and fatalerror if we missed anything */ // make sure the label list is clear, but don't fatalerror
label_list_reset(list, TRUE); reset(false);
} }
/*------------------------------------------------- //-------------------------------------------------
drclabel_get_codeptr - find or allocate a new // block_end - note the end of a block
label; returns NULL and requests an OOB //-------------------------------------------------
callback if undefined
-------------------------------------------------*/
drccodeptr drclabel_get_codeptr(drclabel_list *list, drcuml_codelabel label, drclabel_fixup_func fixup, void *param) void drc_label_list::block_end(drcuml_block &block)
{ {
drclabel *curlabel = label_find_or_allocate(list, label); // make sure the label list is clear, and fatalerror if we missed anything
reset(true);
/* if no code pointer, request an OOB callback */
if (curlabel->codeptr == NULL && fixup != NULL)
list->cache->request_oob_codegen(label_oob_callback, curlabel, (void *)fixup, param);
return curlabel->codeptr;
} }
/*------------------------------------------------- //-------------------------------------------------
drclabel_set_codeptr - set the pointer to a new // get_codeptr - find or allocate a new label;
label // returns NULL and requests an OOB callback if
-------------------------------------------------*/ // undefined
//-------------------------------------------------
void drclabel_set_codeptr(drclabel_list *list, drcuml_codelabel label, drccodeptr codeptr) drccodeptr drc_label_list::get_codeptr(drcuml_codelabel label, fixup_func fixup, void *param)
{ {
/* set the code pointer */ label_entry *curlabel = find_or_allocate(label);
drclabel *curlabel = label_find_or_allocate(list, label);
assert(curlabel->codeptr == NULL); // if no code pointer, request an OOB callback
curlabel->codeptr = codeptr; if (curlabel->m_codeptr == NULL && fixup != NULL)
m_cache.request_oob_codegen(oob_callback, curlabel, (void *)fixup, param);
return curlabel->m_codeptr;
} }
//-------------------------------------------------
// set_codeptr - set the pointer to a new label
//-------------------------------------------------
/*************************************************************************** void drc_label_list::set_codeptr(drcuml_codelabel label, drccodeptr codeptr)
LABEL MANAGEMENT
***************************************************************************/
/*-------------------------------------------------
label_list_reset - reset a label
list (add all entries to the free list)
-------------------------------------------------*/
static void label_list_reset(drclabel_list *list, int fatal_on_leftovers)
{ {
/* loop until out of labels */ // set the code pointer
while (list->head != NULL) 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)
{ {
/* remove from the list */ // fatal if we were a leftover
drclabel *label = list->head; if (fatal_on_leftovers && curlabel->m_codeptr == NULL)
list->head = label->next; fatalerror("Label %08X never defined!", curlabel->m_label);
/* fatal if we were a leftover */ // free the label
if (fatal_on_leftovers && label->codeptr == NULL) m_cache.dealloc(curlabel, sizeof(*curlabel));
fatalerror("Label %08X never defined!", label->label);
/* free the label */
list->cache->dealloc(label, sizeof(*label));
} }
} }
/*------------------------------------------------- //-------------------------------------------------
label_find_or_allocate - look up a label and // find_or_allocate - look up a label and
allocate a new one if not found // allocate a new one if not found
-------------------------------------------------*/ //-------------------------------------------------
static drclabel *label_find_or_allocate(drclabel_list *list, drcuml_codelabel label) drc_label_list::label_entry *drc_label_list::find_or_allocate(drcuml_codelabel label)
{ {
drclabel *curlabel; // find the label, or else allocate a new one
label_entry *curlabel;
/* find the label, or else allocate a new one */ for (curlabel = m_list.first(); curlabel != NULL; curlabel = curlabel->next())
for (curlabel = list->head; curlabel != NULL; curlabel = curlabel->next) if (curlabel->m_label == label)
if (curlabel->label == label)
break; break;
/* if none found, allocate */ // if none found, allocate
if (curlabel == NULL) if (curlabel == NULL)
{ {
curlabel = (drclabel *)list->cache->alloc(sizeof(*curlabel)); curlabel = (label_entry *)m_cache.alloc(sizeof(*curlabel));
curlabel->next = list->head; curlabel->m_label = label;
curlabel->label = label; curlabel->m_codeptr = NULL;
curlabel->codeptr = NULL; m_list.append(*curlabel);
list->head = curlabel;
} }
return curlabel; return curlabel;
} }
/*------------------------------------------------- //-------------------------------------------------
label_oob_callback - out-of-band codegen // oob_callback - out-of-band codegen callback
callback for labels // for labels
-------------------------------------------------*/ //-------------------------------------------------
static void label_oob_callback(drccodeptr *codeptr, void *param1, void *param2, void *param3) void drc_label_list::oob_callback(drccodeptr *codeptr, void *param1, void *param2, void *param3)
{ {
drclabel *label = (drclabel *)param1; label_entry *label = (label_entry *)param1;
drclabel_fixup_func callback = (drclabel_fixup_func)param2; fixup_func callback = (fixup_func)param2;
(*callback)(param3, label->codeptr); (*callback)(param3, label->m_codeptr);
} }

View File

@ -22,134 +22,138 @@
TYPE DEFINITIONS TYPE DEFINITIONS
***************************************************************************/ ***************************************************************************/
/* callback function for forward-referenced labels */ // ======================> drc_hash_table
typedef void (*drclabel_fixup_func)(void *parameter, drccodeptr labelcodeptr);
// common hash table management
/* opaque structure representing a managed list of labels */ class drc_hash_table
typedef struct _drclabel_list drclabel_list;
/* opaque structure representing a managed code map */
typedef struct _drcmap_state drcmap_state;
/* information about the hash tables used by the UML and backend */
typedef struct _drchash_state drchash_state;
struct _drchash_state
{ {
drc_cache * cache; /* cache where allocations come from */ public:
int modes; /* number of modes supported */ // construction/destruction
drc_hash_table(drc_cache &cache, UINT32 modes, UINT8 addrbits, UINT8 ignorebits);
// getters
drccodeptr ***base() const { return m_base; }
UINT8 l1bits() const { return m_l1bits; }
UINT8 l2bits() const { return m_l2bits; }
UINT8 l1shift() const { return m_l1shift; }
UINT8 l2shift() const { return m_l2shift; }
offs_t l1mask() const { return m_l1mask; }
offs_t l2mask() const { return m_l2mask; }
bool is_mode_populated(UINT32 mode) const { return m_base[mode] != m_emptyl1; }
// set up and configuration
bool reset();
void set_default_codeptr(drccodeptr code);
drccodeptr nocodeptr; /* pointer to code which will handle missing entries */ // block begin/end
void block_begin(drcuml_block &block, const drcuml_instruction *instlist, UINT32 numinst);
void block_end(drcuml_block &block);
UINT8 l1bits; /* bits worth of entries in l1 hash tables */ // code pointer access
UINT8 l1shift; /* shift to apply to the PC to get the l1 hash entry */ bool set_codeptr(UINT32 mode, UINT32 pc, drccodeptr code);
offs_t l1mask; /* mask to apply after shifting */ drccodeptr get_codeptr(UINT32 mode, UINT32 pc) { assert(mode < m_modes); return m_base[mode][(pc >> m_l1shift) & m_l1mask][(pc >> m_l2shift) & m_l2mask]; }
UINT8 l2bits; /* bits worth of entries in l2 hash tables */ bool code_exists(UINT32 mode, UINT32 pc) { return get_codeptr(mode, pc) != m_nocodeptr; }
UINT8 l2shift; /* shift to apply to the PC to get the l2 hash entry */
offs_t l2mask; /* mask to apply after shifting */
drccodeptr ** emptyl1; /* pointer to empty l1 hash table */ private:
drccodeptr * emptyl2; /* pointer to empty l2 hash table */ // internal state
drc_cache & m_cache; // cache where allocations come from
UINT32 m_modes; // number of modes supported
drccodeptr ** base[1]; /* pointer to the l1 table for each mode */ drccodeptr m_nocodeptr; // pointer to code which will handle missing entries
UINT8 m_l1bits; // bits worth of entries in l1 hash tables
UINT8 m_l2bits; // bits worth of entries in l2 hash tables
UINT8 m_l1shift; // shift to apply to the PC to get the l1 hash entry
UINT8 m_l2shift; // shift to apply to the PC to get the l2 hash entry
offs_t m_l1mask; // mask to apply after shifting
offs_t m_l2mask; // mask to apply after shifting
drccodeptr *** m_base; // pointer to the l1 table for each mode
drccodeptr ** m_emptyl1; // pointer to empty l1 hash table
drccodeptr * m_emptyl2; // pointer to empty l2 hash table
}; };
// ======================> drc_map_variables
/*************************************************************************** // common map variable management
FUNCTION PROTOTYPES class drc_map_variables
***************************************************************************/
/* ----- hash table management ----- */
/* allocate memory in the cache for the hash table tracker (it auto-frees with the cache) */
drchash_state *drchash_alloc(drc_cache *cache, int modes, int addrbits, int ignorebits);
/* flush existing hash tables and create new ones */
int drchash_reset(drchash_state *drchash);
/* note the beginning of a block */
void drchash_block_begin(drchash_state *drchash, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
/* note the end of a block */
void drchash_block_end(drchash_state *drchash, drcuml_block *block);
/* set the default codeptr for any empty hash entries (defaults to NULL) */
void drchash_set_default_codeptr(drchash_state *drchash, drccodeptr code);
/* set the codeptr for the given mode/pc */
int drchash_set_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc, drccodeptr code);
/* ----- code map management ----- */
/* allocate memory in the cache for the code mapper (it auto-frees with the cache) */
drcmap_state *drcmap_alloc(drc_cache *cache, UINT64 uniquevalue);
/* note the beginning of a block */
void drcmap_block_begin(drcmap_state *drcmap, drcuml_block *block);
/* note the end of a block */
void drcmap_block_end(drcmap_state *drcmap, drcuml_block *block);
/* set a map value for the given code pointer */
void drcmap_set_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar, UINT32 newvalue);
/* return a map value for the given code pointer */
UINT32 drcmap_get_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar);
/* return the most recently set map value */
UINT32 drcmap_get_last_value(drcmap_state *drcmap, UINT32 mapvar);
/* ----- label management ----- */
/* allocate a label list within the cache (it auto-frees with the cache) */
drclabel_list *drclabel_list_alloc(drc_cache *cache);
/* note the beginning of a block */
void drclabel_block_begin(drclabel_list *drcmap, drcuml_block *block);
/* note the end of a block */
void drclabel_block_end(drclabel_list *drcmap, drcuml_block *block);
/* find or allocate a new label; returns NULL and requests an OOB callback if undefined */
drccodeptr drclabel_get_codeptr(drclabel_list *list, drcuml_codelabel label, drclabel_fixup_func fixup, void *param);
/* set the pointer to a new label */
void drclabel_set_codeptr(drclabel_list *list, drcuml_codelabel label, drccodeptr codeptr);
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
drchash_get_codeptr - return the codeptr
allocated for the given mode/pc
-------------------------------------------------*/
INLINE drccodeptr drchash_get_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc)
{ {
assert(mode < drchash->modes); public:
return drchash->base[mode][(pc >> drchash->l1shift) & drchash->l1mask][(pc >> drchash->l2shift) & drchash->l2mask]; // construction/destruction
} drc_map_variables(drc_cache &cache, UINT64 uniquevalue);
~drc_map_variables();
// block begin/end
void block_begin(drcuml_block &block);
void block_end(drcuml_block &block);
// get/set values
void set_value(drccodeptr codebase, UINT32 mapvar, UINT32 newvalue);
UINT32 get_value(drccodeptr codebase, UINT32 mapvar) const;
UINT32 get_last_value(UINT32 mapvar);
// static accessors to be called directly by generated code
static UINT32 static_get_value(drc_map_variables &map, drccodeptr codebase, UINT32 mapvar);
private:
// internal state
drc_cache & m_cache; // pointer to the cache
UINT64 m_uniquevalue; // unique value used to find the table
UINT32 m_mapvalue[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0]; // array of current values
// list of entries
struct map_entry
{
map_entry *next() const { return m_next; }
map_entry * m_next; // pointer to next map entry
drccodeptr m_codeptr; // pointer to the relevant code
UINT32 m_mapvar; // map variable id
UINT32 m_newval; // value of the variable starting at codeptr
};
simple_list<map_entry> m_entry_list; // list of entries
};
/*------------------------------------------------- // ======================> drc_label_list
drchash_code_exists - return TRUE if there is
a matching hash entry for the given mode/pc
-------------------------------------------------*/
INLINE int drchash_code_exists(drchash_state *drchash, UINT32 mode, UINT32 pc) // structure holding a live list of labels
class drc_label_list
{ {
return (drchash_get_codeptr(drchash, mode, pc) != drchash->nocodeptr); // callback function for forward-referenced labels
} typedef void (*fixup_func)(void *parameter, drccodeptr labelcodeptr);
public:
// construction/destruction
drc_label_list(drc_cache &cache);
~drc_label_list();
// block begin/end
void block_begin(drcuml_block &block);
void block_end(drcuml_block &block);
// get/set values
drccodeptr get_codeptr(drcuml_codelabel label, fixup_func fixup, void *param);
void set_codeptr(drcuml_codelabel label, drccodeptr codeptr);
private:
struct label_entry
{
label_entry *next() const { return m_next; }
label_entry * m_next; // pointer to next label
drcuml_codelabel m_label; // the label specified
drccodeptr m_codeptr; // pointer to the relevant code
};
// internal helpers
void reset(bool fatal_on_leftovers);
label_entry *find_or_allocate(drcuml_codelabel label);
static void oob_callback(drccodeptr *codeptr, void *param1, void *param2, void *param3);
// internal state
drc_cache & m_cache; // pointer to the cache
simple_list<label_entry> m_list; // head of the live list
};
#endif /* __DRCBEUT_H__ */ #endif /* __DRCBEUT_H__ */

View File

@ -266,9 +266,9 @@ struct _drcbe_state
drcuml_state * drcuml; /* pointer back to our owner */ drcuml_state * drcuml; /* pointer back to our owner */
drc_cache * cache; /* pointer to the cache */ drc_cache * cache; /* pointer to the cache */
drcuml_machine_state state; /* state of the machine */ drcuml_machine_state state; /* state of the machine */
drchash_state * hash; /* hash table state */ drc_hash_table * hash; /* hash table state */
drcmap_state * map; /* code map */ drc_map_variables * map; /* code map */
drclabel_list * labels; /* label list */ drc_label_list * labels; /* label list */
x86_entry_point_func entry; /* entry point */ x86_entry_point_func entry; /* entry point */
x86code * exit; /* exit point */ x86code * exit; /* exit point */
@ -737,22 +737,16 @@ static drcbe_state *drcbex64_alloc(drcuml_state *drcuml, drc_cache *cache, devic
drcbe->debug_log_hashjmp = (x86code *)debug_log_hashjmp; drcbe->debug_log_hashjmp = (x86code *)debug_log_hashjmp;
drcbe->debug_log_hashjmp_fail = (x86code *)debug_log_hashjmp_fail; drcbe->debug_log_hashjmp_fail = (x86code *)debug_log_hashjmp_fail;
} }
drcbe->drcmap_get_value = (x86code *)drcmap_get_value; drcbe->drcmap_get_value = (x86code *)&drc_map_variables::static_get_value;
/* allocate hash tables */ /* allocate hash tables */
drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits); drcbe->hash = auto_alloc(device->machine, drc_hash_table(*cache, modes, addrbits, ignorebits));
if (drcbe->hash == NULL)
return NULL;
/* allocate code map */ /* allocate code map */
drcbe->map = drcmap_alloc(cache, 0); drcbe->map = auto_alloc(device->machine, drc_map_variables(*cache, 0));
if (drcbe->map == NULL)
return NULL;
/* allocate a label tracker */ /* allocate a label tracker */
drcbe->labels = drclabel_list_alloc(cache); drcbe->labels = auto_alloc(device->machine, drc_label_list(*cache));
if (drcbe->labels == NULL)
return NULL;
/* build the opcode table (static but it doesn't hurt to regenerate it) */ /* build the opcode table (static but it doesn't hurt to regenerate it) */
for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++) for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++)
@ -877,8 +871,8 @@ static void drcbex64_reset(drcbe_state *drcbe)
drcbe->cache->end_codegen(); drcbe->cache->end_codegen();
/* reset our hash tables */ /* reset our hash tables */
drchash_reset(drcbe->hash); drcbe->hash->reset();
drchash_set_default_codeptr(drcbe->hash, drcbe->nocode); drcbe->hash->set_default_codeptr(drcbe->nocode);
} }
@ -908,9 +902,9 @@ static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drc
int inum; int inum;
/* tell all of our utility objects that a block is beginning */ /* tell all of our utility objects that a block is beginning */
drchash_block_begin(drcbe->hash, block, instlist, numinst); drcbe->hash->block_begin(*block, instlist, numinst);
drclabel_block_begin(drcbe->labels, block); drcbe->labels->block_begin(*block);
drcmap_block_begin(drcbe->map, block); drcbe->map->block_begin(*block);
/* begin codegen; fail if we can't */ /* begin codegen; fail if we can't */
cachetop = drcbe->cache->begin_codegen(numinst * 8 * 4); cachetop = drcbe->cache->begin_codegen(numinst * 8 * 4);
@ -960,9 +954,9 @@ static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drc
x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drcbe->cache->top()); x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drcbe->cache->top());
/* tell all of our utility objects that the block is finished */ /* tell all of our utility objects that the block is finished */
drchash_block_end(drcbe->hash, block); drcbe->hash->block_end(*block);
drclabel_block_end(drcbe->labels, block); drcbe->labels->block_end(*block);
drcmap_block_end(drcbe->map, block); drcbe->map->block_end(*block);
} }
@ -973,7 +967,7 @@ static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drc
static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc) static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
{ {
return drchash_code_exists(drcbe->hash, mode, pc); return drcbe->hash->code_exists(mode, pc);
} }
@ -3049,7 +3043,7 @@ static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instructi
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
/* register the current pointer for the mode/PC */ /* register the current pointer for the mode/PC */
drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, dst); drcbe->hash->set_codeptr(inst->param[0].value, inst->param[1].value, dst);
return dst; return dst;
} }
@ -3066,7 +3060,7 @@ static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruct
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
/* register the current pointer for the label */ /* register the current pointer for the label */
drclabel_set_codeptr(drcbe->labels, inst->param[0].value, dst); drcbe->labels->set_codeptr(inst->param[0].value, dst);
return dst; return dst;
} }
@ -3100,7 +3094,7 @@ static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
/* set the value of the specified mapvar */ /* set the value of the specified mapvar */
drcmap_set_value(drcbe->map, dst, inst->param[0].value, inst->param[1].value); drcbe->map->set_value(dst, inst->param[0].value, inst->param[1].value);
return dst; return dst;
} }
@ -3212,14 +3206,14 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
emit_mov_r64_m64(&dst, REG_RSP, MABS(drcbe, &drcbe->hashstacksave)); // mov rsp,[hashstacksave] emit_mov_r64_m64(&dst, REG_RSP, MABS(drcbe, &drcbe->hashstacksave)); // mov rsp,[hashstacksave]
/* fixed mode cases */ /* fixed mode cases */
if (modep.type == DRCUML_PTYPE_IMMEDIATE && drcbe->hash->base[modep.value] != drcbe->hash->emptyl1) if (modep.type == DRCUML_PTYPE_IMMEDIATE && drcbe->hash->is_mode_populated(modep.value))
{ {
/* a straight immediate jump is direct, though we need the PC in EAX in case of failure */ /* a straight immediate jump is direct, though we need the PC in EAX in case of failure */
if (pcp.type == DRCUML_PTYPE_IMMEDIATE) if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
{ {
UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask; UINT32 l1val = (pcp.value >> drcbe->hash->l1shift()) & drcbe->hash->l1mask();
UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask; UINT32 l2val = (pcp.value >> drcbe->hash->l2shift()) & drcbe->hash->l2mask();
emit_call_m64(&dst, MABS(drcbe, &drcbe->hash->base[modep.value][l1val][l2val])); emit_call_m64(&dst, MABS(drcbe, &drcbe->hash->base()[modep.value][l1val][l2val]));
// call hash[modep][l1val][l2val] // call hash[modep][l1val][l2val]
} }
@ -3228,11 +3222,11 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
{ {
emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift()); // shr edx,l1shift
emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask() << drcbe->hash->l2shift());// and eax,l2mask << l2shift
emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RBP, REG_RDX, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->hash->base[modep.value][0]))); emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RBP, REG_RDX, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->hash->base()[modep.value][0])));
// mov rdx,hash[modep+edx*8] // mov rdx,hash[modep+edx*8]
emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift, 0)); // call [rdx+rax*shift] emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift(), 0));// call [rdx+rax*shift]
} }
} }
else else
@ -3240,14 +3234,14 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
/* variable mode */ /* variable mode */
int modereg = param_select_register(REG_ECX, &modep, NULL); int modereg = param_select_register(REG_ECX, &modep, NULL);
emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep
emit_mov_r64_m64(&dst, REG_RCX, MBISD(REG_RBP, modereg, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->hash->base[0]))); emit_mov_r64_m64(&dst, REG_RCX, MBISD(REG_RBP, modereg, 8, offset_from_rbp(drcbe, (FPTR)drcbe->hash->base())));
// mov rcx,hash[modereg*8] // mov rcx,hash[modereg*8]
/* fixed PC */ /* fixed PC */
if (pcp.type == DRCUML_PTYPE_IMMEDIATE) if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
{ {
UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask; UINT32 l1val = (pcp.value >> drcbe->hash->l1shift()) & drcbe->hash->l1mask();
UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask; UINT32 l2val = (pcp.value >> drcbe->hash->l2shift()) & drcbe->hash->l2mask();
emit_mov_r64_m64(&dst, REG_RDX, MBD(REG_RCX, l1val*8)); // mov rdx,[rcx+l1val*8] emit_mov_r64_m64(&dst, REG_RDX, MBD(REG_RCX, l1val*8)); // mov rdx,[rcx+l1val*8]
emit_call_m64(&dst, MBD(REG_RDX, l2val*8)); // call [l2val*8] emit_call_m64(&dst, MBD(REG_RDX, l2val*8)); // call [l2val*8]
} }
@ -3257,10 +3251,10 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
{ {
emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift()); // shr edx,l1shift
emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RCX, REG_RDX, 8, 0)); // mov rdx,[rcx+rdx*8] emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RCX, REG_RDX, 8, 0)); // mov rdx,[rcx+rdx*8]
emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask() << drcbe->hash->l2shift());// and eax,l2mask << l2shift
emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift, 0)); // call [rdx+rax*shift] emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift(), 0)); // call [rdx+rax*shift]
} }
} }
@ -3294,7 +3288,7 @@ static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
param_normalize_1(drcbe, inst, &labelp, PTYPE_I); param_normalize_1(drcbe, inst, &labelp, PTYPE_I);
/* look up the jump target and jump there */ /* look up the jump target and jump there */
jmptarget = (x86code *)drclabel_get_codeptr(drcbe->labels, labelp.value, fixup_label, dst); jmptarget = (x86code *)drcbe->labels->get_codeptr(labelp.value, fixup_label, dst);
if (jmptarget == NULL) if (jmptarget == NULL)
jmptarget = dst + 0x7ffffff0; jmptarget = dst + 0x7ffffff0;
if (inst->condition == DRCUML_COND_ALWAYS) if (inst->condition == DRCUML_COND_ALWAYS)

View File

@ -158,9 +158,9 @@ struct _drcbe_state
drcuml_state * drcuml; /* pointer back to our owner */ drcuml_state * drcuml; /* pointer back to our owner */
drc_cache * cache; /* pointer to the cache */ drc_cache * cache; /* pointer to the cache */
drcuml_machine_state state; /* state of the machine */ drcuml_machine_state state; /* state of the machine */
drchash_state * hash; /* hash table state */ drc_hash_table * hash; /* hash table state */
drcmap_state * map; /* code map */ drc_map_variables * map; /* code map */
drclabel_list * labels; /* label list */ drc_label_list * labels; /* label list */
x86_entry_point_func entry; /* entry point */ x86_entry_point_func entry; /* entry point */
x86code * exit; /* exit point */ x86code * exit; /* exit point */
@ -639,19 +639,13 @@ static drcbe_state *drcbex86_alloc(drcuml_state *drcuml, drc_cache *cache, devic
} }
/* allocate hash tables */ /* allocate hash tables */
drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits); drcbe->hash = auto_alloc(device->machine, drc_hash_table(*cache, modes, addrbits, ignorebits));
if (drcbe->hash == NULL)
return NULL;
/* allocate code map */ /* allocate code map */
drcbe->map = drcmap_alloc(cache, 0); drcbe->map = auto_alloc(device->machine, drc_map_variables(*cache, 0));
if (drcbe->map == NULL)
return NULL;
/* allocate a label tracker */ /* allocate a label tracker */
drcbe->labels = drclabel_list_alloc(cache); drcbe->labels = auto_alloc(device->machine, drc_label_list(*cache));
if (drcbe->labels == NULL)
return NULL;
/* build the opcode table (static but it doesn't hurt to regenerate it) */ /* build the opcode table (static but it doesn't hurt to regenerate it) */
for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++) for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++)
@ -854,8 +848,8 @@ static void drcbex86_reset(drcbe_state *drcbe)
drcbe->logged_common = TRUE; drcbe->logged_common = TRUE;
/* reset our hash tables */ /* reset our hash tables */
drchash_reset(drcbe->hash); drcbe->hash->reset();
drchash_set_default_codeptr(drcbe->hash, drcbe->nocode); drcbe->hash->set_default_codeptr(drcbe->nocode);
} }
@ -885,9 +879,9 @@ static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drc
int inum; int inum;
/* tell all of our utility objects that a block is beginning */ /* tell all of our utility objects that a block is beginning */
drchash_block_begin(drcbe->hash, block, instlist, numinst); drcbe->hash->block_begin(*block, instlist, numinst);
drclabel_block_begin(drcbe->labels, block); drcbe->labels->block_begin(*block);
drcmap_block_begin(drcbe->map, block); drcbe->map->block_begin(*block);
/* begin codegen; fail if we can't */ /* begin codegen; fail if we can't */
cachetop = drcbe->cache->begin_codegen(numinst * 8 * 4); cachetop = drcbe->cache->begin_codegen(numinst * 8 * 4);
@ -937,9 +931,9 @@ static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drc
x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drcbe->cache->top()); x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drcbe->cache->top());
/* tell all of our utility objects that the block is finished */ /* tell all of our utility objects that the block is finished */
drchash_block_end(drcbe->hash, block); drcbe->hash->block_end(*block);
drclabel_block_end(drcbe->labels, block); drcbe->labels->block_end(*block);
drcmap_block_end(drcbe->map, block); drcbe->map->block_end(*block);
} }
@ -950,7 +944,7 @@ static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drc
static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc) static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
{ {
return drchash_code_exists(drcbe->hash, mode, pc); return drcbe->hash->code_exists(mode, pc);
} }
@ -3261,7 +3255,7 @@ static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instructi
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
/* register the current pointer for the mode/PC */ /* register the current pointer for the mode/PC */
drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, dst); drcbe->hash->set_codeptr(inst->param[0].value, inst->param[1].value, dst);
reset_last_upper_lower_reg(drcbe); reset_last_upper_lower_reg(drcbe);
return dst; return dst;
} }
@ -3279,7 +3273,7 @@ static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruct
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
/* register the current pointer for the label */ /* register the current pointer for the label */
drclabel_set_codeptr(drcbe->labels, inst->param[0].value, dst); drcbe->labels->set_codeptr(inst->param[0].value, dst);
reset_last_upper_lower_reg(drcbe); reset_last_upper_lower_reg(drcbe);
return dst; return dst;
} }
@ -3314,7 +3308,7 @@ static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruc
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE); assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
/* set the value of the specified mapvar */ /* set the value of the specified mapvar */
drcmap_set_value(drcbe->map, dst, inst->param[0].value, inst->param[1].value); drcbe->map->set_value(dst, inst->param[0].value, inst->param[1].value);
return dst; return dst;
} }
@ -3425,14 +3419,14 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
emit_mov_r32_m32(&dst, REG_ESP, MABS(&drcbe->hashstacksave)); // mov esp,[hashstacksave] emit_mov_r32_m32(&dst, REG_ESP, MABS(&drcbe->hashstacksave)); // mov esp,[hashstacksave]
/* fixed mode cases */ /* fixed mode cases */
if (modep.type == DRCUML_PTYPE_IMMEDIATE && drcbe->hash->base[modep.value] != drcbe->hash->emptyl1) if (modep.type == DRCUML_PTYPE_IMMEDIATE && drcbe->hash->is_mode_populated(modep.value))
{ {
/* a straight immediate jump is direct, though we need the PC in EAX in case of failure */ /* a straight immediate jump is direct, though we need the PC in EAX in case of failure */
if (pcp.type == DRCUML_PTYPE_IMMEDIATE) if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
{ {
UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask; UINT32 l1val = (pcp.value >> drcbe->hash->l1shift()) & drcbe->hash->l1mask();
UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask; UINT32 l2val = (pcp.value >> drcbe->hash->l2shift()) & drcbe->hash->l2mask();
emit_call_m32(&dst, MABS(&drcbe->hash->base[modep.value][l1val][l2val])); // call hash[modep][l1val][l2val] emit_call_m32(&dst, MABS(&drcbe->hash->base()[modep.value][l1val][l2val])); // call hash[modep][l1val][l2val]
} }
/* a fixed mode but variable PC */ /* a fixed mode but variable PC */
@ -3440,11 +3434,11 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
{ {
emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift()); // shr edx,l1shift
emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask() << drcbe->hash->l2shift());// and eax,l2mask << l2shift
emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 4, &drcbe->hash->base[modep.value][0])); emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 4, &drcbe->hash->base()[modep.value][0]));
// mov edx,hash[modep+edx*4] // mov edx,hash[modep+edx*4]
emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift, 0)); // call [edx+eax*shift] emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift(), 0));// call [edx+eax*shift]
} }
} }
else else
@ -3452,13 +3446,13 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
/* variable mode */ /* variable mode */
int modereg = param_select_register(REG_ECX, &modep, NULL); int modereg = param_select_register(REG_ECX, &modep, NULL);
emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep
emit_mov_r32_m32(&dst, REG_ECX, MISD(modereg, 4, &drcbe->hash->base[0])); // mov ecx,hash[modereg*4] emit_mov_r32_m32(&dst, REG_ECX, MISD(modereg, 4, drcbe->hash->base())); // mov ecx,hash[modereg*4]
/* fixed PC */ /* fixed PC */
if (pcp.type == DRCUML_PTYPE_IMMEDIATE) if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
{ {
UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask; UINT32 l1val = (pcp.value >> drcbe->hash->l1shift()) & drcbe->hash->l1mask();
UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask; UINT32 l2val = (pcp.value >> drcbe->hash->l2shift()) & drcbe->hash->l2mask();
emit_mov_r32_m32(&dst, REG_EDX, MBD(REG_ECX, l1val*4)); // mov edx,[ecx+l1val*4] emit_mov_r32_m32(&dst, REG_EDX, MBD(REG_ECX, l1val*4)); // mov edx,[ecx+l1val*4]
emit_call_m32(&dst, MBD(REG_EDX, l2val*4)); // call [l2val*4] emit_call_m32(&dst, MBD(REG_EDX, l2val*4)); // call [l2val*4]
} }
@ -3468,10 +3462,10 @@ static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instru
{ {
emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift()); // shr edx,l1shift
emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_ECX, REG_EDX, 4, 0)); // mov edx,[ecx+edx*4] emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_ECX, REG_EDX, 4, 0)); // mov edx,[ecx+edx*4]
emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask() << drcbe->hash->l2shift());// and eax,l2mask << l2shift
emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift, 0)); // call [edx+eax*shift] emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift(), 0));// call [edx+eax*shift]
} }
} }
@ -3502,7 +3496,7 @@ static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instructio
param_normalize_1(drcbe, inst, &labelp, PTYPE_I); param_normalize_1(drcbe, inst, &labelp, PTYPE_I);
/* look up the jump target and jump there */ /* look up the jump target and jump there */
jmptarget = (x86code *)drclabel_get_codeptr(drcbe->labels, labelp.value, fixup_label, dst); jmptarget = (x86code *)drcbe->labels->get_codeptr(labelp.value, fixup_label, dst);
if (inst->condition == DRCUML_COND_ALWAYS) if (inst->condition == DRCUML_COND_ALWAYS)
emit_jmp(&dst, jmptarget); // jmp target emit_jmp(&dst, jmptarget); // jmp target
else else
@ -3674,7 +3668,7 @@ static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instru
emit_mov_m32_imm(&dst, MBD(REG_ESP, 8), inst->param[1].value); // mov [esp+8],param1 emit_mov_m32_imm(&dst, MBD(REG_ESP, 8), inst->param[1].value); // mov [esp+8],param1
emit_mov_m32_r32(&dst, MBD(REG_ESP, 4), REG_EAX); // mov [esp+4],eax emit_mov_m32_r32(&dst, MBD(REG_ESP, 4), REG_EAX); // mov [esp+4],eax
emit_mov_m32_imm(&dst, MBD(REG_ESP, 0), (FPTR)drcbe->map); // mov [esp],drcbe->map emit_mov_m32_imm(&dst, MBD(REG_ESP, 0), (FPTR)drcbe->map); // mov [esp],drcbe->map
emit_call(&dst, (x86code *)drcmap_get_value); // call drcmap_get_value emit_call(&dst, (x86code *)&drc_map_variables::static_get_value); // call drcmap_get_value
emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
return dst; return dst;