mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
New universal dynamic recompiler system. The central module
is drcuml.c, which defines a universal machine language syntax that can be generated by a frontend recompiler and then retargeted via a generic backend interface to any of a number of different architectures. A disassembler for the UML is also included to allow examination of the generated UML code. Currently supported backend architectures include 32-bit x86, 64-bit x86, and a platform-neutral interpreted C backend that can be used as a fallback for platforms without native support. The C backend also performs additional validation to ensure assumptions are met. Along with the new architecture is a new MIPS III/IV recompiler frontend. This frontend has been rewritten from the old x64-specific recompiler to generate UML opcodes instead. This means that the single recompiler can be used to target multiple backend architectures and should in theory produce identical results across all of them. The old 32-bit and 64-bit MIPS recompilers are now officially retired. The new system provides similar performance (within 5% generally) to the old system and has similar compatibility. The only currently known issues are some problems with the two Gauntlet 3D games.
This commit is contained in:
parent
9b3d9ea3cd
commit
b735b4be6c
14
.gitattributes
vendored
14
.gitattributes
vendored
@ -60,8 +60,20 @@ src/emu/cpu/cp1610/1610dasm.c svneol=native#text/plain
|
||||
src/emu/cpu/cp1610/cp1610.c svneol=native#text/plain
|
||||
src/emu/cpu/cp1610/cp1610.h svneol=native#text/plain
|
||||
src/emu/cpu/cpu.mak svneol=native#text/plain
|
||||
src/emu/cpu/drcbec.c svneol=native#text/plain
|
||||
src/emu/cpu/drcbeut.c svneol=native#text/plain
|
||||
src/emu/cpu/drcbeut.h svneol=native#text/plain
|
||||
src/emu/cpu/drcbex64.c svneol=native#text/plain
|
||||
src/emu/cpu/drcbex86.c svneol=native#text/plain
|
||||
src/emu/cpu/drccache.c svneol=native#text/plain
|
||||
src/emu/cpu/drccache.h svneol=native#text/plain
|
||||
src/emu/cpu/drcfe.c svneol=native#text/plain
|
||||
src/emu/cpu/drcfe.h svneol=native#text/plain
|
||||
src/emu/cpu/drcuml.c svneol=native#text/plain
|
||||
src/emu/cpu/drcuml.h svneol=native#text/plain
|
||||
src/emu/cpu/drcumld.c svneol=native#text/plain
|
||||
src/emu/cpu/drcumld.h svneol=native#text/plain
|
||||
src/emu/cpu/drcumlsh.h svneol=native#text/plain
|
||||
src/emu/cpu/dsp32/dsp32.c svneol=native#text/plain
|
||||
src/emu/cpu/dsp32/dsp32.h svneol=native#text/plain
|
||||
src/emu/cpu/dsp32/dsp32dis.c svneol=native#text/plain
|
||||
@ -262,8 +274,6 @@ src/emu/cpu/minx/minxopcf.h svneol=native#text/plain
|
||||
src/emu/cpu/minx/minxops.h svneol=native#text/plain
|
||||
src/emu/cpu/mips/dismips.c svneol=native#text/plain
|
||||
src/emu/cpu/mips/dismips.mak svneol=native#text/plain
|
||||
src/emu/cpu/mips/mdrc64.c svneol=native#text/plain
|
||||
src/emu/cpu/mips/mdrcold.c svneol=native#text/plain
|
||||
src/emu/cpu/mips/mips3.c svneol=native#text/plain
|
||||
src/emu/cpu/mips/mips3.h svneol=native#text/plain
|
||||
src/emu/cpu/mips/mips3com.c svneol=native#text/plain
|
||||
|
7
makefile
7
makefile
@ -48,6 +48,7 @@ CROSS_BUILD_OSD = $(OSD)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
# specify OS target, which further differentiates
|
||||
# the underlying OS; supported values are:
|
||||
@ -105,8 +106,10 @@ endif
|
||||
# uncomment next line to include the internal profiler
|
||||
# PROFILER = 1
|
||||
|
||||
# uncomment next line to use DRC MIPS3 engine
|
||||
X86_MIPS3_DRC = 1
|
||||
# uncomment the force the universal DRC to always use the C backend
|
||||
# you may need to do this if your target architecture does not have
|
||||
# a native backend
|
||||
# FORCE_DRC_C_BACKEND = 1
|
||||
|
||||
# uncomment next line to use DRC PowerPC engine
|
||||
X86_PPC_DRC = 1
|
||||
|
@ -18,27 +18,59 @@ CPUOBJ = $(EMUOBJ)/cpu
|
||||
# Dynamic recompiler objects
|
||||
#-------------------------------------------------
|
||||
|
||||
DRCOBJ = \
|
||||
$(CPUOBJ)/drcbec.o \
|
||||
$(CPUOBJ)/drcbeut.o \
|
||||
$(CPUOBJ)/drccache.o \
|
||||
$(CPUOBJ)/drcfe.o \
|
||||
$(CPUOBJ)/drcuml.o \
|
||||
$(CPUOBJ)/drcumld.o \
|
||||
|
||||
DRCDEPS = \
|
||||
$(CPUSRC)/drcbeut.h \
|
||||
$(CPUSRC)/drccache.h \
|
||||
$(CPUSRC)/drcfe.h \
|
||||
$(CPUSRC)/drcuml.h \
|
||||
$(CPUSRC)/drcumld.h \
|
||||
$(CPUSRC)/drcumlsh.h \
|
||||
|
||||
# fixme - need to make this work for other target architectures (PPC)
|
||||
|
||||
ifndef FORCE_DRC_C_BACKEND
|
||||
ifdef PTR64
|
||||
|
||||
DRCOBJ = $(CPUOBJ)/x64drc.o $(CPUOBJ)/x86log.o $(CPUOBJ)/drcfe.o
|
||||
DRCOBJ += \
|
||||
$(CPUOBJ)/drcbex64.o \
|
||||
$(CPUOBJ)/x64drc.o \
|
||||
$(CPUOBJ)/x86log.o \
|
||||
|
||||
DRCDEPS = $(CPUSRC)/x86emit.h \
|
||||
$(CPUSRC)/x64drc.c \
|
||||
$(CPUSRC)/x64drc.h \
|
||||
DRCDEPS += \
|
||||
$(CPUSRC)/x86emit.h \
|
||||
$(CPUSRC)/x64drc.c \
|
||||
$(CPUSRC)/x64drc.h \
|
||||
|
||||
$(DRCOBJ): $(DRCDEPS)
|
||||
DEFS += -DNATIVE_DRC=drcbe_x64_be_interface
|
||||
|
||||
else
|
||||
|
||||
DRCOBJ = $(CPUOBJ)/x86drc.o $(CPUOBJ)/x86log.o $(CPUOBJ)/drcfe.o
|
||||
DRCOBJ += \
|
||||
$(CPUOBJ)/drcbex86.o \
|
||||
$(CPUOBJ)/x86drc.o \
|
||||
$(CPUOBJ)/x86log.o \
|
||||
|
||||
DRCDEPS += \
|
||||
$(CPUSRC)/x86emit.h \
|
||||
$(CPUSRC)/x86drc.c \
|
||||
$(CPUSRC)/x86drc.h \
|
||||
|
||||
DEFS += -DNATIVE_DRC=drcbe_x86_be_interface
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
DRCDEPS = $(CPUSRC)/x86emit.h \
|
||||
$(CPUSRC)/x86drc.c \
|
||||
$(CPUSRC)/x86drc.h \
|
||||
|
||||
$(DRCOBJ): $(DRCDEPS)
|
||||
|
||||
endif
|
||||
|
||||
|
||||
#-------------------------------------------------
|
||||
@ -793,23 +825,11 @@ CPUDEFS += -DHAS_RM7000=$(if $(filter RM7000,$(CPUS)),1,0)
|
||||
|
||||
ifneq ($(filter R4600 R4650 R4700 R5000 QED5271 RM7000,$(CPUS)),)
|
||||
OBJDIRS += $(CPUOBJ)/mips
|
||||
CPUOBJS += $(CPUOBJ)/mips/mips3com.o
|
||||
CPUOBJS += $(CPUOBJ)/mips/mips3com.o $(CPUOBJ)/mips/mips3drc.o $(CPUOBJ)/mips/mips3fe.o $(DRCOBJ)
|
||||
DBGOBJS += $(CPUOBJ)/mips/mips3dsm.o
|
||||
|
||||
ifdef X86_MIPS3_DRC
|
||||
CPUOBJS += $(CPUOBJ)/mips/mips3drc.o $(CPUOBJ)/mips/mips3fe.o $(DRCOBJ)
|
||||
else
|
||||
CPUOBJS += $(CPUOBJ)/mips/mips3.o
|
||||
endif
|
||||
endif
|
||||
|
||||
$(CPUOBJ)/mips/mips3.o: $(CPUSRC)/mips/mips3.c \
|
||||
$(CPUSRC)/mips/mips3.h \
|
||||
$(CPUSRC)/mips/mips3com.h
|
||||
|
||||
$(CPUOBJ)/mips/mips3drc.o: $(CPUSRC)/mips/mips3drc.c \
|
||||
$(CPUSRC)/mips/mdrcold.c \
|
||||
$(CPUSRC)/mips/mdrc64.c \
|
||||
$(CPUSRC)/mips/mips3.h \
|
||||
$(CPUSRC)/mips/mips3com.h \
|
||||
$(CPUSRC)/mips/mips3fe.h \
|
||||
|
1806
src/emu/cpu/drcbec.c
Normal file
1806
src/emu/cpu/drcbec.c
Normal file
File diff suppressed because it is too large
Load Diff
673
src/emu/cpu/drcbeut.c
Normal file
673
src/emu/cpu/drcbeut.c
Normal file
@ -0,0 +1,673 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcbeut.c
|
||||
|
||||
Utility functions for dynamic recompiling backends.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "drcbeut.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
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
|
||||
{
|
||||
drccache * 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
|
||||
{
|
||||
drccache * 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
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drchash_alloc - allocate memory in the cache
|
||||
for the hash table tracker (it auto-frees
|
||||
with the cache)
|
||||
-------------------------------------------------*/
|
||||
|
||||
drchash_state *drchash_alloc(drccache *cache, int modes, int addrbits, int ignorebits)
|
||||
{
|
||||
int effaddrbits = addrbits - ignorebits;
|
||||
drchash_state *drchash;
|
||||
|
||||
/* allocate permanent state from the cache */
|
||||
drchash = drccache_memory_alloc(cache, 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
|
||||
create new ones
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drchash_reset(drchash_state *drchash)
|
||||
{
|
||||
int modenum, entry;
|
||||
|
||||
/* allocate an empty l2 hash table */
|
||||
drchash->emptyl2 = drccache_memory_alloc_temporary(drchash->cache, sizeof(drccodeptr) << drchash->l2bits);
|
||||
if (drchash->emptyl2 == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* populate it with pointers to the recompile_exit code */
|
||||
for (entry = 0; entry < (1 << drchash->l2bits); entry++)
|
||||
drchash->emptyl2[entry] = drchash->nocodeptr;
|
||||
|
||||
/* allocate an empty l1 hash table */
|
||||
drchash->emptyl1 = drccache_memory_alloc_temporary(drchash->cache, sizeof(drccodeptr *) << drchash->l1bits);
|
||||
if (drchash->emptyl1 == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* populate it with pointers to the empty l2 table */
|
||||
for (entry = 0; entry < (1 << drchash->l1bits); entry++)
|
||||
drchash->emptyl1[entry] = drchash->emptyl2;
|
||||
|
||||
/* reset the hash tables */
|
||||
for (modenum = 0; modenum < drchash->modes; modenum++)
|
||||
drchash->base[modenum] = drchash->emptyl1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drchash_block_begin - note the beginning of a
|
||||
block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drchash_block_begin(drchash_state *drchash, 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 (inum = 0; inum < numinst; 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 (inst->opcode == DRCUML_OP_HASH)
|
||||
{
|
||||
assert(inst->numparams == 2);
|
||||
assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
|
||||
assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
|
||||
|
||||
/* if we fail to allocate, we must abort the block */
|
||||
if (!drchash_set_codeptr(drchash, inst->param[0].value, inst->param[1].value, NULL))
|
||||
drcuml_block_abort(block);
|
||||
}
|
||||
|
||||
/* 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 we fail to allocate, we must abort the block */
|
||||
drccodeptr code = drchash_get_codeptr(drchash, inst->param[0].value, inst->param[1].value);
|
||||
if (!drchash_set_codeptr(drchash, inst->param[0].value, inst->param[1].value, code))
|
||||
drcuml_block_abort(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drchash_block_end - note the end of a block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drchash_block_end(drchash_state *drchash, drcuml_block *block)
|
||||
{
|
||||
/* nothing to do here, yet */
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drchash_set_default_codeptr - change the
|
||||
default codeptr
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drchash_set_default_codeptr(drchash_state *drchash, drccodeptr nocodeptr)
|
||||
{
|
||||
drccodeptr old = drchash->nocodeptr;
|
||||
int modenum, l1entry, l2entry;
|
||||
|
||||
/* nothing to do if the same */
|
||||
if (old == nocodeptr)
|
||||
return;
|
||||
drchash->nocodeptr = nocodeptr;
|
||||
|
||||
/* update the empty L2 table first */
|
||||
for (l2entry = 0; l2entry < (1 << drchash->l2bits); l2entry++)
|
||||
drchash->emptyl2[l2entry] = nocodeptr;
|
||||
|
||||
/* now scan all existing hashtables for entries */
|
||||
for (modenum = 0; modenum < drchash->modes; modenum++)
|
||||
if (drchash->base[modenum] != drchash->emptyl1)
|
||||
for (l1entry = 0; l1entry < (1 << drchash->l1bits); l1entry++)
|
||||
if (drchash->base[modenum][l1entry] != drchash->emptyl2)
|
||||
for (l2entry = 0; l2entry < (1 << drchash->l2bits); l2entry++)
|
||||
if (drchash->base[modenum][l1entry][l2entry] == old)
|
||||
drchash->base[modenum][l1entry][l2entry] = nocodeptr;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drchash_set_codeptr - set the codeptr for the
|
||||
given mode/pc
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drchash_set_codeptr(drchash_state *drchash, UINT32 mode, UINT32 pc, drccodeptr code)
|
||||
{
|
||||
UINT32 l1 = (pc >> drchash->l1shift) & drchash->l1mask;
|
||||
UINT32 l2 = (pc >> drchash->l2shift) & drchash->l2mask;
|
||||
|
||||
assert(mode < drchash->modes);
|
||||
|
||||
/* copy-on-write for the l1 hash table */
|
||||
if (drchash->base[mode] == drchash->emptyl1)
|
||||
{
|
||||
drccodeptr **newtable = drccache_memory_alloc_temporary(drchash->cache, sizeof(drccodeptr *) << drchash->l1bits);
|
||||
if (newtable == NULL)
|
||||
return FALSE;
|
||||
memcpy(newtable, drchash->emptyl1, sizeof(drccodeptr *) << drchash->l1bits);
|
||||
drchash->base[mode] = newtable;
|
||||
}
|
||||
|
||||
/* copy-on-write for the l2 hash table */
|
||||
if (drchash->base[mode][l1] == drchash->emptyl2)
|
||||
{
|
||||
drccodeptr *newtable = drccache_memory_alloc_temporary(drchash->cache, sizeof(drccodeptr) << drchash->l2bits);
|
||||
if (newtable == NULL)
|
||||
return FALSE;
|
||||
memcpy(newtable, drchash->emptyl2, sizeof(drccodeptr) << drchash->l2bits);
|
||||
drchash->base[mode][l1] = newtable;
|
||||
}
|
||||
|
||||
/* set the new entry */
|
||||
drchash->base[mode][l1][l2] = code;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE MAP MANAGEMENT
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcmap_alloc - allocate memory in the cache
|
||||
for the code mapper (it auto-frees with the
|
||||
cache)
|
||||
-------------------------------------------------*/
|
||||
|
||||
drcmap_state *drcmap_alloc(drccache *cache, UINT64 uniquevalue)
|
||||
{
|
||||
drcmap_state *drcmap;
|
||||
|
||||
/* allocate permanent state from the cache */
|
||||
drcmap = drccache_memory_alloc(cache, 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
|
||||
block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcmap_block_begin(drcmap_state *drcmap, drcuml_block *block)
|
||||
{
|
||||
/* release any remaining live entries */
|
||||
while (drcmap->head != NULL)
|
||||
{
|
||||
drcmap_entry *entry = drcmap->head;
|
||||
drcmap->head = entry->next;
|
||||
drccache_memory_free(drcmap->cache, entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
/* reset the tailptr and count */
|
||||
drcmap->tailptr = &drcmap->head;
|
||||
drcmap->numvalues = 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcmap_block_end - note the end of a block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcmap_block_end(drcmap_state *drcmap, drcuml_block *block)
|
||||
{
|
||||
UINT32 curvalue[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0];
|
||||
UINT8 changed[DRCUML_MAPVAR_END - DRCUML_MAPVAR_M0];
|
||||
drcmap_entry *entry;
|
||||
drccodeptr lastptr;
|
||||
drccodeptr *top;
|
||||
UINT32 *dest;
|
||||
|
||||
/* only process if we have data */
|
||||
if (drcmap->head == NULL)
|
||||
return;
|
||||
|
||||
/* begin "code generation" aligned to an 8-byte boundary */
|
||||
top = drccache_begin_codegen(drcmap->cache, sizeof(UINT64) + sizeof(UINT32) + 2 * sizeof(UINT32) * drcmap->numvalues);
|
||||
if (top == NULL)
|
||||
drcuml_block_abort(block);
|
||||
dest = (UINT32 *)(((FPTR)*top + 7) & ~7);
|
||||
|
||||
/* store the cookie first */
|
||||
*(UINT64 *)dest = drcmap->uniquevalue;
|
||||
dest += 2;
|
||||
|
||||
/* get the pointer to the first item and store an initial backwards offset */
|
||||
lastptr = drcmap->head->codeptr;
|
||||
*dest = (drccodeptr)dest - lastptr;
|
||||
dest++;
|
||||
|
||||
/* reset the current values */
|
||||
memset(curvalue, 0, sizeof(curvalue));
|
||||
memset(changed, 0, sizeof(changed));
|
||||
|
||||
/* now iterate over entries and store them */
|
||||
for (entry = drcmap->head; entry != NULL; entry = entry->next)
|
||||
{
|
||||
/* update the current value of the variable and detect changes */
|
||||
if (curvalue[entry->mapvar] != entry->newval)
|
||||
{
|
||||
curvalue[entry->mapvar] = entry->newval;
|
||||
changed[entry->mapvar] = TRUE;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
UINT32 codedelta = entry->codeptr - lastptr;
|
||||
UINT32 varmask = 0;
|
||||
int numchanged;
|
||||
int varnum;
|
||||
|
||||
/* build a mask of changed variables */
|
||||
for (numchanged = 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 */
|
||||
while (codedelta > 0xffff)
|
||||
{
|
||||
*dest++ = 0xffff << 16;
|
||||
codedelta -= 0xffff;
|
||||
}
|
||||
*dest++ = (codedelta << 16) | (varmask << 4) | numchanged;
|
||||
|
||||
/* now output updated variable values */
|
||||
for (varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++)
|
||||
if ((varmask >> varnum) & 1)
|
||||
*dest++ = curvalue[varnum];
|
||||
|
||||
/* remember our lastptr */
|
||||
lastptr = entry->codeptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* add a terminator */
|
||||
*dest++ = 0;
|
||||
|
||||
/* complete codegen */
|
||||
*top = (drccodeptr)dest;
|
||||
drccache_end_codegen(drcmap->cache);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcmap_set_value - set a map value for the
|
||||
given code pointer
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcmap_set_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar, UINT32 newvalue)
|
||||
{
|
||||
drcmap_entry *entry;
|
||||
|
||||
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
|
||||
|
||||
/* if this value isn't different, skip it */
|
||||
if (drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0] == newvalue)
|
||||
return;
|
||||
|
||||
/* allocate a new entry and fill it in */
|
||||
entry = drccache_memory_alloc(drcmap->cache, sizeof(*entry));
|
||||
entry->next = NULL;
|
||||
entry->codeptr = codebase;
|
||||
entry->mapvar = mapvar - DRCUML_MAPVAR_M0;
|
||||
entry->newval = newvalue;
|
||||
|
||||
/* hook us into the end of the list */
|
||||
*drcmap->tailptr = entry;
|
||||
drcmap->tailptr = &entry->next;
|
||||
|
||||
/* update our state in the table as well */
|
||||
drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0] = newvalue;
|
||||
|
||||
/* and increment the count */
|
||||
drcmap->numvalues++;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcmap_get_value - return a map value for the
|
||||
given code pointer
|
||||
-------------------------------------------------*/
|
||||
|
||||
UINT32 drcmap_get_value(drcmap_state *drcmap, drccodeptr codebase, UINT32 mapvar)
|
||||
{
|
||||
UINT64 *endscan = (UINT64 *)drccache_top(drcmap->cache);
|
||||
UINT32 varmask = 0x10 << mapvar;
|
||||
drccodeptr curcode;
|
||||
UINT32 result = 0;
|
||||
UINT64 *curscan;
|
||||
UINT32 *data;
|
||||
|
||||
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
|
||||
mapvar -= DRCUML_MAPVAR_M0;
|
||||
|
||||
/* get an aligned pointer to start scanning */
|
||||
curscan = (UINT64 *)(((FPTR)codebase | 7) + 1);
|
||||
|
||||
/* look for the signature */
|
||||
while (curscan < endscan && *curscan++ != drcmap->uniquevalue) ;
|
||||
assert(curscan < endscan);
|
||||
if (curscan >= endscan)
|
||||
return 0;
|
||||
|
||||
/* switch to 32-bit pointers for processing the rest */
|
||||
data = (UINT32 *)curscan;
|
||||
|
||||
/* first get the 32-bit starting offset to the code */
|
||||
curcode = (drccodeptr)data - *data;
|
||||
data++;
|
||||
|
||||
/* now loop until we advance past our target */
|
||||
while (TRUE)
|
||||
{
|
||||
UINT32 controlword = *data++;
|
||||
|
||||
/* a 0 is a terminator */
|
||||
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)
|
||||
{
|
||||
int dataoffs = 0;
|
||||
UINT32 skipmask;
|
||||
|
||||
/* count how many words precede the one we care about */
|
||||
for (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;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcmap_get_last_value - return the most
|
||||
recently set map value
|
||||
-------------------------------------------------*/
|
||||
|
||||
UINT32 drcmap_get_last_value(drcmap_state *drcmap, UINT32 mapvar)
|
||||
{
|
||||
assert(mapvar >= DRCUML_MAPVAR_M0 && mapvar < DRCUML_MAPVAR_END);
|
||||
return drcmap->mapvalue[mapvar - DRCUML_MAPVAR_M0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
LABEL MANAGEMENT
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drclabel_list_alloc - allocate a label
|
||||
list within the cache (it auto-frees with the
|
||||
cache)
|
||||
-------------------------------------------------*/
|
||||
|
||||
drclabel_list *drclabel_list_alloc(drccache *cache)
|
||||
{
|
||||
drclabel_list *list;
|
||||
|
||||
/* allocate permanent state from the cache */
|
||||
list = drccache_memory_alloc(cache, 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
|
||||
a block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drclabel_block_begin(drclabel_list *list, drcuml_block *block)
|
||||
{
|
||||
/* make sure the label list is clear, but don't fatalerror */
|
||||
label_list_reset(list, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drclabel_block_end - note the end of a block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drclabel_block_end(drclabel_list *list, drcuml_block *block)
|
||||
{
|
||||
/* make sure the label list is clear, and fatalerror if we missed anything */
|
||||
label_list_reset(list, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drclabel_get_codeptr - 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)
|
||||
{
|
||||
drclabel *curlabel = label_find_or_allocate(list, label);
|
||||
|
||||
/* if no code pointer, request an OOB callback */
|
||||
if (curlabel->codeptr == NULL && fixup != NULL)
|
||||
drccache_request_oob_codegen(list->cache, label_oob_callback, curlabel, fixup, param);
|
||||
|
||||
return curlabel->codeptr;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drclabel_set_codeptr - set the pointer to a new
|
||||
label
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drclabel_set_codeptr(drclabel_list *list, drcuml_codelabel label, drccodeptr codeptr)
|
||||
{
|
||||
/* set the code pointer */
|
||||
drclabel *curlabel = label_find_or_allocate(list, label);
|
||||
assert(curlabel->codeptr == NULL);
|
||||
curlabel->codeptr = 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 */
|
||||
while (list->head != NULL)
|
||||
{
|
||||
/* remove from the list */
|
||||
drclabel *label = list->head;
|
||||
list->head = label->next;
|
||||
|
||||
/* fatal if we were a leftover */
|
||||
if (fatal_on_leftovers && label->codeptr == NULL)
|
||||
fatalerror("Label %08X never defined!", label->label);
|
||||
|
||||
/* free the label */
|
||||
drccache_memory_free(list->cache, label, sizeof(*label));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
label_find_or_allocate - look up a label and
|
||||
allocate a new one if not found
|
||||
-------------------------------------------------*/
|
||||
|
||||
static drclabel *label_find_or_allocate(drclabel_list *list, drcuml_codelabel label)
|
||||
{
|
||||
drclabel *curlabel;
|
||||
|
||||
/* find the label, or else allocate a new one */
|
||||
for (curlabel = list->head; curlabel != NULL; curlabel = curlabel->next)
|
||||
if (curlabel->label == label)
|
||||
break;
|
||||
|
||||
/* if none found, allocate */
|
||||
if (curlabel == NULL)
|
||||
{
|
||||
curlabel = drccache_memory_alloc(list->cache, sizeof(*curlabel));
|
||||
curlabel->next = list->head;
|
||||
curlabel->label = label;
|
||||
curlabel->codeptr = NULL;
|
||||
list->head = curlabel;
|
||||
}
|
||||
|
||||
return curlabel;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
label_oob_callback - out-of-band codegen
|
||||
callback for labels
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void label_oob_callback(drccodeptr *codeptr, void *param1, void *param2, void *param3)
|
||||
{
|
||||
drclabel *label = param1;
|
||||
drclabel_fixup_func callback = param2;
|
||||
|
||||
(*callback)(param3, label->codeptr);
|
||||
}
|
192
src/emu/cpu/drcbeut.h
Normal file
192
src/emu/cpu/drcbeut.h
Normal file
@ -0,0 +1,192 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcbeut.h
|
||||
|
||||
Utility functions for dynamic recompiling backends.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __DRCBEUT_H__
|
||||
#define __DRCBEUT_H__
|
||||
|
||||
#include "drcuml.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* callback function for forward-referenced labels */
|
||||
typedef void (*drclabel_fixup_func)(void *parameter, drccodeptr labelcodeptr);
|
||||
|
||||
|
||||
/* opaque structure representing a managed list of labels */
|
||||
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
|
||||
{
|
||||
drccache * cache; /* cache where allocations come from */
|
||||
int modes; /* number of modes supported */
|
||||
|
||||
drccodeptr nocodeptr; /* pointer to code which will handle missing entries */
|
||||
|
||||
UINT8 l1bits; /* bits worth of entries in l1 hash tables */
|
||||
UINT8 l1shift; /* shift to apply to the PC to get the l1 hash entry */
|
||||
offs_t l1mask; /* mask to apply after shifting */
|
||||
UINT8 l2bits; /* bits worth of entries in l2 hash tables */
|
||||
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 */
|
||||
drccodeptr * emptyl2; /* pointer to empty l2 hash table */
|
||||
|
||||
drccodeptr ** base[1]; /* pointer to the l1 table for each mode */
|
||||
};
|
||||
|
||||
|
||||
/* an integer register, with low/high parts */
|
||||
typedef union _drcuml_ireg drcuml_ireg;
|
||||
union _drcuml_ireg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
UINT32 l,h; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
UINT32 h,l; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
UINT64 d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* an floating-point register, with low/high parts */
|
||||
typedef union _drcuml_freg drcuml_freg;
|
||||
union _drcuml_freg
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
float l,unused; /* 32-bit low, high parts of the register */
|
||||
#else
|
||||
float unused,l; /* 32-bit low, high parts of the register */
|
||||
#endif
|
||||
double d; /* 64-bit full register */
|
||||
};
|
||||
|
||||
|
||||
/* the collected machine state of a system */
|
||||
typedef struct _drcuml_machine_state drcuml_machine_state;
|
||||
struct _drcuml_machine_state
|
||||
{
|
||||
drcuml_ireg r[DRCUML_REG_I_END - DRCUML_REG_I0]; /* integer registers */
|
||||
drcuml_freg f[DRCUML_REG_F_END - DRCUML_REG_F0]; /* floating-point registers */
|
||||
drcuml_ireg exp; /* exception parameter register */
|
||||
UINT8 fmod; /* fmod (floating-point mode) register */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* ----- hash table management ----- */
|
||||
|
||||
/* allocate memory in the cache for the hash table tracker (it auto-frees with the cache) */
|
||||
drchash_state *drchash_alloc(drccache *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(drccache *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(drccache *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);
|
||||
return drchash->base[mode][(pc >> drchash->l1shift) & drchash->l1mask][(pc >> drchash->l2shift) & drchash->l2mask];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
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)
|
||||
{
|
||||
return (drchash_get_codeptr(drchash, mode, pc) != drchash->nocodeptr);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
7680
src/emu/cpu/drcbex64.c
Normal file
7680
src/emu/cpu/drcbex64.c
Normal file
File diff suppressed because it is too large
Load Diff
7418
src/emu/cpu/drcbex86.c
Normal file
7418
src/emu/cpu/drcbex86.c
Normal file
File diff suppressed because it is too large
Load Diff
418
src/emu/cpu/drccache.c
Normal file
418
src/emu/cpu/drccache.c
Normal file
@ -0,0 +1,418 @@
|
||||
/***************************************************************************
|
||||
|
||||
drccache.h
|
||||
|
||||
Universal dynamic recompiler cache management.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "cpuintrf.h"
|
||||
#include "drccache.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/* largest block of code that can be generated at once */
|
||||
#define CODEGEN_MAX_BYTES 65536
|
||||
|
||||
/* minimum alignment, in bytes (must be power of 2) */
|
||||
#define CACHE_ALIGNMENT 8
|
||||
|
||||
/* largest permanent allocation we allow */
|
||||
#define MAX_PERMANENT_ALLOC 1024
|
||||
|
||||
/* size of "near" area at the base of the cache */
|
||||
#define NEAR_CACHE_SIZE 65536
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS
|
||||
***************************************************************************/
|
||||
|
||||
/* ensure that all memory allocated is aligned to an 8-byte boundary */
|
||||
#define ALIGN_PTR_UP(p) ((void *)(((FPTR)(p) + (CACHE_ALIGNMENT - 1)) & ~(CACHE_ALIGNMENT - 1)))
|
||||
#define ALIGN_PTR_DOWN(p) ((void *)((FPTR)(p) & ~(CACHE_ALIGNMENT - 1)))
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* out-of-bounds codegen handlers */
|
||||
typedef struct _oob_handler oob_handler;
|
||||
struct _oob_handler
|
||||
{
|
||||
oob_handler * next; /* next handler */
|
||||
drccache_oob_func callback; /* callback function */
|
||||
void * param1; /* 1st pointer parameter */
|
||||
void * param2; /* 2nd pointer parameter */
|
||||
void * param3; /* 3rd pointer parameter */
|
||||
};
|
||||
|
||||
|
||||
/* a linked list of free items */
|
||||
typedef struct _free_link free_link;
|
||||
struct _free_link
|
||||
{
|
||||
free_link * next; /* pointer to the next guy */
|
||||
};
|
||||
|
||||
|
||||
/* cache state */
|
||||
struct _drccache
|
||||
{
|
||||
/* core parameters */
|
||||
drccodeptr near; /* pointer to the near part of the cache */
|
||||
drccodeptr neartop; /* top of the near part of the cache */
|
||||
drccodeptr base; /* base pointer to the compiler cache */
|
||||
drccodeptr top; /* current top of cache */
|
||||
drccodeptr end; /* end of cache memory */
|
||||
drccodeptr codegen; /* start of generated code */
|
||||
size_t size; /* size of the cache in bytes */
|
||||
|
||||
/* oob management */
|
||||
oob_handler * ooblist; /* list of oob handlers */
|
||||
oob_handler ** oobtail; /* pointer to tail oob pointer */
|
||||
|
||||
/* free lists */
|
||||
free_link * free[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
||||
free_link * nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INITIALIZATION/TEARDOWN
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_alloc - allocate the cache itself
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccache *drccache_alloc(size_t bytes)
|
||||
{
|
||||
drccache cache, *cacheptr;
|
||||
|
||||
assert(bytes >= sizeof(cache) + NEAR_CACHE_SIZE);
|
||||
|
||||
/* build a local structure first */
|
||||
memset(&cache, 0, sizeof(cache));
|
||||
cache.near = osd_alloc_executable(bytes);
|
||||
cache.neartop = cache.near;
|
||||
cache.base = cache.near + NEAR_CACHE_SIZE;
|
||||
cache.top = cache.base;
|
||||
cache.end = cache.near + bytes;
|
||||
cache.size = bytes;
|
||||
|
||||
/* now allocate the cache structure itself from that */
|
||||
cacheptr = drccache_memory_alloc(&cache, sizeof(cache));
|
||||
*cacheptr = cache;
|
||||
|
||||
/* return the allocated result */
|
||||
return cacheptr;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_free - free the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drccache_free(drccache *cache)
|
||||
{
|
||||
/* release the memory; this includes the cache object itself */
|
||||
osd_free_executable(cache->near, cache->size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CACHE INFORMATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_contains_pointer - return true if a
|
||||
pointer is within the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drccache_contains_pointer(drccache *cache, const void *ptr)
|
||||
{
|
||||
return ((const drccodeptr)ptr >= cache->near && (const drccodeptr)ptr < cache->near + cache->size);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_contains_near_pointer - return true
|
||||
if a pointer is within the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drccache_contains_near_pointer(drccache *cache, const void *ptr)
|
||||
{
|
||||
return ((const drccodeptr)ptr >= cache->near && (const drccodeptr)ptr < cache->neartop);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_near - return a pointer to the near
|
||||
part of the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr drccache_near(drccache *cache)
|
||||
{
|
||||
return cache->near;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_base - return a pointer to the base
|
||||
of the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr drccache_base(drccache *cache)
|
||||
{
|
||||
return cache->base;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_top - return the current top of the
|
||||
cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr drccache_top(drccache *cache)
|
||||
{
|
||||
return cache->top;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MEMORY MANAGEMENT
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_flush - flush the cache contents
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drccache_flush(drccache *cache)
|
||||
{
|
||||
/* can't flush in the middle of codegen */
|
||||
assert(cache->codegen == NULL);
|
||||
|
||||
/* just reset the top back to the base and re-seed */
|
||||
cache->top = cache->base;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_memory_alloc - allocate permanent
|
||||
memory from the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
void *drccache_memory_alloc(drccache *cache, size_t bytes)
|
||||
{
|
||||
drccodeptr ptr;
|
||||
|
||||
assert(bytes > 0);
|
||||
|
||||
/* pick first from the free list */
|
||||
if (bytes < MAX_PERMANENT_ALLOC)
|
||||
{
|
||||
free_link **linkptr = &cache->free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||
free_link *link = *linkptr;
|
||||
if (link != NULL)
|
||||
{
|
||||
*linkptr = link->next;
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no space, we just fail */
|
||||
ptr = ALIGN_PTR_DOWN(cache->end - bytes);
|
||||
if (cache->top > ptr)
|
||||
return NULL;
|
||||
|
||||
/* otherwise update the end of the cache */
|
||||
cache->end = ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_memory_alloc_near - allocate
|
||||
permanent memory from the near part of the
|
||||
cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
void *drccache_memory_alloc_near(drccache *cache, size_t bytes)
|
||||
{
|
||||
drccodeptr ptr;
|
||||
|
||||
assert(bytes > 0);
|
||||
|
||||
/* pick first from the free list */
|
||||
if (bytes < MAX_PERMANENT_ALLOC)
|
||||
{
|
||||
free_link **linkptr = &cache->nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||
free_link *link = *linkptr;
|
||||
if (link != NULL)
|
||||
{
|
||||
*linkptr = link->next;
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no space, we just fail */
|
||||
ptr = ALIGN_PTR_UP(cache->neartop);
|
||||
if (ptr + bytes > cache->base)
|
||||
return NULL;
|
||||
|
||||
/* otherwise update the top of the near part of the cache */
|
||||
cache->neartop = ptr + bytes;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_memory_free - release permanent
|
||||
memory allocated from the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drccache_memory_free(drccache *cache, void *memory, size_t bytes)
|
||||
{
|
||||
free_link **linkptr;
|
||||
free_link *link = memory;
|
||||
|
||||
assert(bytes < MAX_PERMANENT_ALLOC);
|
||||
assert(((drccodeptr)memory >= cache->near && (drccodeptr)memory < cache->base) || ((drccodeptr)memory >= cache->end && (drccodeptr)memory < cache->near + cache->size));
|
||||
|
||||
/* determine which free list to add to */
|
||||
if ((drccodeptr)memory < cache->base)
|
||||
linkptr = &cache->nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||
else
|
||||
linkptr = &cache->free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
|
||||
|
||||
/* link is into the free list for our size */
|
||||
link->next = *linkptr;
|
||||
*linkptr = link;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_memory_alloc_temporary - allocate
|
||||
temporary memory from the cache
|
||||
-------------------------------------------------*/
|
||||
|
||||
void *drccache_memory_alloc_temporary(drccache *cache, size_t bytes)
|
||||
{
|
||||
drccodeptr ptr = cache->top;
|
||||
|
||||
/* can't allocate in the middle of codegen */
|
||||
assert(cache->codegen == NULL);
|
||||
|
||||
/* if no space, we just fail */
|
||||
if (ptr + bytes >= cache->end)
|
||||
return NULL;
|
||||
|
||||
/* otherwise, update the cache top */
|
||||
cache->top = ALIGN_PTR_UP(ptr + bytes);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE GENERATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_begin_codegen - begin code
|
||||
generation
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr *drccache_begin_codegen(drccache *cache, UINT32 reserve_bytes)
|
||||
{
|
||||
drccodeptr ptr = cache->top;
|
||||
|
||||
/* can't restart in the middle of codegen */
|
||||
assert(cache->codegen == NULL);
|
||||
assert(cache->ooblist == NULL);
|
||||
|
||||
/* if still no space, we just fail */
|
||||
if (ptr + reserve_bytes >= cache->end)
|
||||
return NULL;
|
||||
|
||||
/* otherwise, return a pointer to the cache top */
|
||||
cache->codegen = cache->top;
|
||||
cache->oobtail = &cache->ooblist;
|
||||
return &cache->top;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_end_codegen - complete code
|
||||
generation
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr drccache_end_codegen(drccache *cache)
|
||||
{
|
||||
drccodeptr result = cache->codegen;
|
||||
|
||||
/* run the OOB handlers */
|
||||
while (cache->ooblist != NULL)
|
||||
{
|
||||
/* remove us from the list */
|
||||
oob_handler *oob = cache->ooblist;
|
||||
cache->ooblist = oob->next;
|
||||
|
||||
/* call the callback */
|
||||
(*oob->callback)(&cache->top, oob->param1, oob->param2, oob->param3);
|
||||
assert(cache->top - cache->codegen < CODEGEN_MAX_BYTES);
|
||||
|
||||
/* release our memory */
|
||||
drccache_memory_free(cache, oob, sizeof(*oob));
|
||||
}
|
||||
|
||||
/* update the cache top */
|
||||
cache->top = ALIGN_PTR_UP(cache->top);
|
||||
cache->codegen = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drccache_request_oob_codegen - request
|
||||
callback for out-of-band codegen
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drccache_request_oob_codegen(drccache *cache, drccache_oob_func callback, void *param1, void *param2, void *param3)
|
||||
{
|
||||
oob_handler *oob;
|
||||
|
||||
assert(cache->codegen != NULL);
|
||||
|
||||
/* pull an item from the free list */
|
||||
oob = drccache_memory_alloc(cache, sizeof(*oob));
|
||||
assert(oob != NULL);
|
||||
|
||||
/* fill it in */
|
||||
oob->next = NULL;
|
||||
oob->callback = callback;
|
||||
oob->param1 = param1;
|
||||
oob->param2 = param2;
|
||||
oob->param3 = param3;
|
||||
|
||||
/* add to the tail */
|
||||
*cache->oobtail = oob;
|
||||
cache->oobtail = &oob->next;
|
||||
}
|
107
src/emu/cpu/drccache.h
Normal file
107
src/emu/cpu/drccache.h
Normal file
@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
|
||||
drccache.h
|
||||
|
||||
Universal dynamic recompiler cache management.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __DRCCACHE_H__
|
||||
#define __DRCCACHE_H__
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS
|
||||
***************************************************************************/
|
||||
|
||||
/* ensure that a given pointer is within the cache boundaries */
|
||||
#define assert_in_cache(c,p) assert(drccache_contains_pointer(c, p))
|
||||
#define assert_in_near_cache(c,p) assert(drccache_contains_near_pointer(c, p))
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* generic code pointer */
|
||||
typedef UINT8 *drccodeptr;
|
||||
|
||||
/* opaque cache state */
|
||||
typedef struct _drccache drccache;
|
||||
|
||||
/* out of band codegen callback */
|
||||
typedef void (*drccache_oob_func)(drccodeptr *codeptr, void *param1, void *param2, void *param3);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* ----- initialization/teardown ----- */
|
||||
|
||||
/* allocate the cache itself */
|
||||
drccache *drccache_alloc(size_t bytes);
|
||||
|
||||
/* free the cache */
|
||||
void drccache_free(drccache *cache);
|
||||
|
||||
|
||||
|
||||
/* ----- cache information ----- */
|
||||
|
||||
/* return true if a pointer is within the cache */
|
||||
int drccache_contains_pointer(drccache *cache, const void *ptr);
|
||||
|
||||
/* return true if a pointer is within the near area of the cache */
|
||||
int drccache_contains_near_pointer(drccache *cache, const void *ptr);
|
||||
|
||||
/* return a pointer to the near part of the cache */
|
||||
drccodeptr drccache_near(drccache *cache);
|
||||
|
||||
/* return a pointer to the base of the cache, which is where code generation starts */
|
||||
drccodeptr drccache_base(drccache *cache);
|
||||
|
||||
/* return the current top of the cache, which is where the next code will be generated */
|
||||
drccodeptr drccache_top(drccache *cache);
|
||||
|
||||
|
||||
|
||||
/* ----- memory management ----- */
|
||||
|
||||
/* flush the cache contents */
|
||||
void drccache_flush(drccache *cache);
|
||||
|
||||
/* allocate permanent memory from the cache */
|
||||
void *drccache_memory_alloc(drccache *cache, size_t bytes);
|
||||
|
||||
/* allocate permanent memory from the near portion of the cache */
|
||||
void *drccache_memory_alloc_near(drccache *cache, size_t bytes);
|
||||
|
||||
/* release permanent memory allocated from the cache */
|
||||
void drccache_memory_free(drccache *cache, void *memory, size_t bytes);
|
||||
|
||||
/* allocate temporary memory from the cache (released on a reset) */
|
||||
void *drccache_memory_alloc_temporary(drccache *cache, size_t bytes);
|
||||
|
||||
|
||||
|
||||
/* ----- code generation ----- */
|
||||
|
||||
/* begin code generation */
|
||||
drccodeptr *drccache_begin_codegen(drccache *cache, UINT32 reserve_bytes);
|
||||
|
||||
/* complete code generation */
|
||||
drccodeptr drccache_end_codegen(drccache *cache);
|
||||
|
||||
/* request callback for out-of-band codegen */
|
||||
void drccache_request_oob_codegen(drccache *cache, drccache_oob_func callback, void *param1, void *param2, void *param3);
|
||||
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@
|
||||
Generic dynamic recompiler frontend structures and utilities.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general use under the MAME license
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
@ -44,7 +44,7 @@ struct _drcfe_state
|
||||
UINT32 window_end; /* code window end offset = startpc + window_end */
|
||||
UINT32 max_sequence; /* maximum instructions to include in a sequence */
|
||||
|
||||
drcfe_describe_func describe; /* callback to describe a single instruction */
|
||||
drcfe_describe_func describe; /* callback to describe a single instruction */
|
||||
void * param; /* parameter for the callback */
|
||||
|
||||
/* CPU parameters */
|
||||
|
@ -5,7 +5,7 @@
|
||||
Generic dynamic recompiler frontend structures and utilities.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general use under the MAME license
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
****************************************************************************
|
||||
@ -34,13 +34,6 @@
|
||||
#ifndef __DRCFE_H__
|
||||
#define __DRCFE_H__
|
||||
|
||||
#ifdef PTR64
|
||||
#include "x64drc.h"
|
||||
#else
|
||||
#include "x86drc.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
@ -159,16 +152,6 @@ struct _drcfe_config
|
||||
drcfe_describe_func describe; /* callback to describe a single instruction */
|
||||
};
|
||||
|
||||
/*
|
||||
for each register:
|
||||
callback to load
|
||||
callback to store
|
||||
pointer to memory
|
||||
if (pointer != NULL)
|
||||
- can return reference to memory for operations
|
||||
else
|
||||
- must always load/store from register
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
858
src/emu/cpu/drcuml.c
Normal file
858
src/emu/cpu/drcuml.c
Normal file
@ -0,0 +1,858 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcuml.c
|
||||
|
||||
Universal machine language for dynamic recompiling CPU cores.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
****************************************************************************
|
||||
|
||||
Future improvements/changes:
|
||||
|
||||
* Write a back-end validator:
|
||||
- checks all combinations of memory/register/immediate on all params
|
||||
- checks behavior of all opcodes
|
||||
|
||||
* Extend registers to 16? Depends on if PPC can use them
|
||||
|
||||
* New instructions?
|
||||
- EXTRACT dst,src,shift,mask
|
||||
dst = (src >> shift) & mask
|
||||
|
||||
- INSERT dst,src,shift,mask
|
||||
dst = (dst & ~mask) | ((src << shift) & mask)
|
||||
|
||||
- VALID opcode_desc,handle,param
|
||||
checksum/compare code referenced by opcode_desc; if not
|
||||
matching, generate exception with handle,param
|
||||
|
||||
- RECALL handle
|
||||
change code at caller to call handle in the future
|
||||
|
||||
* Add interface for getting hints from the backend:
|
||||
- number of direct-mapped integer registers
|
||||
- number of direct-mapped floating point registers
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "drcuml.h"
|
||||
#include "drcumlsh.h"
|
||||
#include "drcumld.h"
|
||||
#include "mame.h"
|
||||
#include "deprecat.h"
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/* opcode validation condition/flag valid bitmasks */
|
||||
#define OV_CONDFLAG_NONE 0x00
|
||||
#define OV_CONDFLAG_COND 0x80
|
||||
#define OV_CONDFLAG_FLAGS 0x1f
|
||||
|
||||
/* opcode validation parameter valid bitmasks */
|
||||
#define OV_PARAM_ALLOWED_NONE (1 << DRCUML_PTYPE_NONE)
|
||||
#define OV_PARAM_ALLOWED_IMM (1 << DRCUML_PTYPE_IMMEDIATE)
|
||||
#define OV_PARAM_ALLOWED_IREG (1 << DRCUML_PTYPE_INT_REGISTER)
|
||||
#define OV_PARAM_ALLOWED_FREG (1 << DRCUML_PTYPE_FLOAT_REGISTER)
|
||||
#define OV_PARAM_ALLOWED_MVAR (1 << DRCUML_PTYPE_MAPVAR)
|
||||
#define OV_PARAM_ALLOWED_MEM (1 << DRCUML_PTYPE_MEMORY)
|
||||
#define OV_PARAM_ALLOWED_NCMEM (OV_PARAM_ALLOWED_MEM | 0x80)
|
||||
#define OV_PARAM_ALLOWED_IMV (OV_PARAM_ALLOWED_IMM | OV_PARAM_ALLOWED_MVAR)
|
||||
#define OV_PARAM_ALLOWED_IRM (OV_PARAM_ALLOWED_IREG | OV_PARAM_ALLOWED_MEM)
|
||||
#define OV_PARAM_ALLOWED_FRM (OV_PARAM_ALLOWED_FREG | OV_PARAM_ALLOWED_MEM)
|
||||
#define OV_PARAM_ALLOWED_IANY (OV_PARAM_ALLOWED_IRM | OV_PARAM_ALLOWED_IMV)
|
||||
#define OV_PARAM_ALLOWED_FANY (OV_PARAM_ALLOWED_FRM)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* structure describing UML generation state */
|
||||
struct _drcuml_state
|
||||
{
|
||||
drccache * cache; /* pointer to the codegen cache */
|
||||
drcuml_block * blocklist; /* list of active blocks */
|
||||
|
||||
const drcbe_interface * beintf; /* backend interface pointer */
|
||||
drcbe_state * bestate; /* pointer to the back-end state */
|
||||
|
||||
drcuml_codehandle * handlelist; /* head of linked list of handles */
|
||||
|
||||
FILE * umllog; /* handle to the UML logfile */
|
||||
};
|
||||
|
||||
|
||||
/* structure describing UML codegen block */
|
||||
struct _drcuml_block
|
||||
{
|
||||
drcuml_state * drcuml; /* pointer back to the owning UML */
|
||||
drcuml_block * next; /* pointer to next block */
|
||||
drcuml_instruction * inst; /* pointer to the instruction list */
|
||||
UINT8 inuse; /* this block is in use */
|
||||
UINT32 maxinst; /* maximum number of instructions */
|
||||
UINT32 nextinst; /* next instruction to fill in the cache */
|
||||
jmp_buf * errorbuf; /* setjmp buffer for deep error handling */
|
||||
};
|
||||
|
||||
|
||||
/* structure describing a global handle */
|
||||
struct _drcuml_codehandle
|
||||
{
|
||||
drccodeptr code; /* pointer to the associated code */
|
||||
char * string; /* pointer to string attached to handle */
|
||||
drcuml_codehandle * next; /* link to next handle in the list */
|
||||
drcuml_state * drcuml; /* pointer to owning object */
|
||||
};
|
||||
|
||||
|
||||
/* structure describing an opcode for validation */
|
||||
typedef struct _drcuml_opcode_valid drcuml_opcode_valid;
|
||||
struct _drcuml_opcode_valid
|
||||
{
|
||||
drcuml_opcode opcode; /* the opcode itself */
|
||||
UINT8 sizes; /* allowed sizes */
|
||||
UINT8 condflags; /* allowed conditions/flags */
|
||||
UINT8 p0types; /* allowed types for parameter 0 */
|
||||
UINT8 p1types; /* allowed types for parameter 1 */
|
||||
UINT8 p2types; /* allowed types for parameter 2 */
|
||||
UINT8 p3types; /* allowed types for parameter 3 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TABLES
|
||||
***************************************************************************/
|
||||
|
||||
/* macro to simplify the table */
|
||||
#define OPVALID_ENTRY_0(op,sizes,condflag) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_1(op,sizes,condflag,p0) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_2(op,sizes,condflag,p0,p1) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_NONE, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_3(op,sizes,condflag,p0,p1,p2) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_NONE },
|
||||
#define OPVALID_ENTRY_4(op,sizes,condflag,p0,p1,p2,p3) { DRCUML_OP_##op, sizes, OV_CONDFLAG_##condflag, OV_PARAM_ALLOWED_##p0, OV_PARAM_ALLOWED_##p1, OV_PARAM_ALLOWED_##p2, OV_PARAM_ALLOWED_##p3 },
|
||||
|
||||
/* opcode validation table */
|
||||
static const drcuml_opcode_valid opcode_valid_list[] =
|
||||
{
|
||||
/* Compile-time opcodes */
|
||||
OPVALID_ENTRY_1(HANDLE, 4, NONE, MEM)
|
||||
OPVALID_ENTRY_2(HASH, 4, NONE, IMV, IMV)
|
||||
OPVALID_ENTRY_1(LABEL, 4, NONE, IMV)
|
||||
OPVALID_ENTRY_1(COMMENT, 4, NONE, NCMEM)
|
||||
OPVALID_ENTRY_2(MAPVAR, 4, NONE, MVAR, IMV)
|
||||
|
||||
/* Control Flow Operations */
|
||||
OPVALID_ENTRY_1(DEBUG, 4, NONE, IANY)
|
||||
OPVALID_ENTRY_1(EXIT, 4, COND, IANY)
|
||||
OPVALID_ENTRY_3(HASHJMP, 4, NONE, IANY, IANY, MEM)
|
||||
OPVALID_ENTRY_1(LABEL, 4, NONE, IMV)
|
||||
OPVALID_ENTRY_1(JMP, 4, COND, IMV)
|
||||
OPVALID_ENTRY_2(EXH, 4, COND, MEM, IANY)
|
||||
OPVALID_ENTRY_1(CALLH, 4, COND, MEM)
|
||||
OPVALID_ENTRY_0(RET, 4, COND)
|
||||
OPVALID_ENTRY_2(CALLC, 4, COND, NCMEM,NCMEM)
|
||||
OPVALID_ENTRY_2(RECOVER, 4, NONE, IRM, MVAR)
|
||||
|
||||
/* Internal Register Operations */
|
||||
OPVALID_ENTRY_1(SETFMOD, 4, NONE, IANY)
|
||||
OPVALID_ENTRY_1(GETFMOD, 4, NONE, IRM)
|
||||
OPVALID_ENTRY_1(GETEXP, 4, NONE, IRM)
|
||||
|
||||
/* Integer Operations */
|
||||
OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(STORE1, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE2, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE4, 4|8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(STORE8, 8, NONE, NCMEM,IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV, IANY)
|
||||
OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV, IANY, IANY)
|
||||
OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV, IANY, IANY, IANY)
|
||||
OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM)
|
||||
OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY)
|
||||
OPVALID_ENTRY_3(ADD, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ADDC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUB, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SUBB, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(CMP, 4|8, FLAGS, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(MULS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVU, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_4(DIVS, 4|8, FLAGS, IRM, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(AND, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_2(TEST, 4|8, FLAGS, IANY, IANY)
|
||||
OPVALID_ENTRY_3(OR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(XOR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHL, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SHR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(SAR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROL, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROLC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(ROR, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
OPVALID_ENTRY_3(RORC, 4|8, FLAGS, IRM, IANY, IANY)
|
||||
|
||||
/* Floating Point Operations */
|
||||
OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, NCMEM,IANY)
|
||||
OPVALID_ENTRY_3(FSTORE, 4|8, NONE, NCMEM,IANY, FANY)
|
||||
OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV, IANY)
|
||||
OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV, IANY, FANY)
|
||||
OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY)
|
||||
OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY)
|
||||
OPVALID_ENTRY_3(FADD, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FSUB, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FCMP, 4|8, FLAGS, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FMUL, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_3(FDIV, 4|8, FLAGS, FRM, FANY, FANY)
|
||||
OPVALID_ENTRY_2(FNEG, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FABS, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FSQRT, 4|8, FLAGS, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRECIP, 4|8, NONE, FRM, FANY)
|
||||
OPVALID_ENTRY_2(FRSQRT, 4|8, NONE, FRM, FANY)
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
/* we presume the existence of a C back-end interface */
|
||||
extern const drcbe_interface drcbe_c_be_interface;
|
||||
|
||||
/* extern a reference to the native DRC interface if it exists */
|
||||
#ifndef NATIVE_DRC
|
||||
#define NATIVE_DRC drcbe_c_be_interface
|
||||
#else
|
||||
extern const drcbe_interface NATIVE_DRC;
|
||||
#endif
|
||||
|
||||
/* table that is built up on first alloc which looks up via opcode */
|
||||
static drcuml_opcode_valid opcode_valid_table[DRCUML_OP_MAX];
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst);
|
||||
#else
|
||||
#define validate_instruction(block, inst) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INITIALIZATION/TEARDOWN
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_alloc - allocate state for the code
|
||||
generator and initialize the back-end
|
||||
-------------------------------------------------*/
|
||||
|
||||
drcuml_state *drcuml_alloc(drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits)
|
||||
{
|
||||
drcuml_state *drcuml;
|
||||
int opnum;
|
||||
|
||||
/* allocate state */
|
||||
drcuml = drccache_memory_alloc(cache, sizeof(*drcuml));
|
||||
if (drcuml == NULL)
|
||||
return NULL;
|
||||
memset(drcuml, 0, sizeof(*drcuml));
|
||||
|
||||
/* initialize the state */
|
||||
drcuml->cache = cache;
|
||||
drcuml->beintf = (flags & DRCUML_OPTION_USE_C) ? &drcbe_c_be_interface : &NATIVE_DRC;
|
||||
|
||||
/* if we're to log, create the logfile */
|
||||
if (flags & DRCUML_OPTION_LOG_UML)
|
||||
drcuml->umllog = fopen("drcuml.asm", "w");
|
||||
|
||||
/* allocate the back-end */
|
||||
drcuml->bestate = (*drcuml->beintf->be_alloc)(drcuml, cache, flags, modes, addrbits, ignorebits);
|
||||
if (drcuml->bestate == NULL)
|
||||
{
|
||||
drcuml_free(drcuml);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* update the valid opcode table */
|
||||
for (opnum = 0; opnum < ARRAY_LENGTH(opcode_valid_list); opnum++)
|
||||
opcode_valid_table[opcode_valid_list[opnum].opcode] = opcode_valid_list[opnum];
|
||||
|
||||
return drcuml;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_reset - reset the state completely,
|
||||
flushing the cache and all information
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_reset(drcuml_state *drcuml)
|
||||
{
|
||||
drcuml_codehandle *handle;
|
||||
jmp_buf errorbuf;
|
||||
|
||||
/* flush the cache */
|
||||
drccache_flush(drcuml->cache);
|
||||
|
||||
/* if we error here, we are screwed */
|
||||
if (setjmp(errorbuf) != 0)
|
||||
fatalerror("Out of cache space in drcuml_reset");
|
||||
|
||||
/* reset all handle code pointers */
|
||||
for (handle = drcuml->handlelist; handle != NULL; handle = handle->next)
|
||||
handle->code = NULL;
|
||||
|
||||
/* call the backend to reset */
|
||||
(*drcuml->beintf->be_reset)(drcuml->bestate);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_free - free state for the code generator
|
||||
and the back-end
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_free(drcuml_state *drcuml)
|
||||
{
|
||||
/* free the back-end */
|
||||
if (drcuml->bestate != NULL)
|
||||
(*drcuml->beintf->be_free)(drcuml->bestate);
|
||||
|
||||
/* free all the blocks */
|
||||
while (drcuml->blocklist != NULL)
|
||||
{
|
||||
drcuml_block *block = drcuml->blocklist;
|
||||
|
||||
/* remove the item from the list */
|
||||
drcuml->blocklist = block->next;
|
||||
|
||||
/* free memory */
|
||||
if (block->inst != NULL)
|
||||
free(block->inst);
|
||||
free(block);
|
||||
}
|
||||
|
||||
/* close any files */
|
||||
if (drcuml->umllog != NULL)
|
||||
fclose(drcuml->umllog);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE BLOCK GENERATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_begin - begin a new code block
|
||||
-------------------------------------------------*/
|
||||
|
||||
drcuml_block *drcuml_block_begin(drcuml_state *drcuml, UINT32 maxinst, jmp_buf *errorbuf)
|
||||
{
|
||||
drcuml_block *bestblock = NULL;
|
||||
drcuml_block *block;
|
||||
|
||||
/* find an inactive block that matches our qualifications */
|
||||
for (block = drcuml->blocklist; block != NULL; block = block->next)
|
||||
if (!block->inuse && block->maxinst >= maxinst && (bestblock == NULL || block->maxinst < bestblock->maxinst))
|
||||
bestblock = block;
|
||||
|
||||
/* if we failed to find one, allocate a new one */
|
||||
if (bestblock == NULL)
|
||||
{
|
||||
/* allocate the block structure itself */
|
||||
bestblock = malloc(sizeof(*bestblock));
|
||||
if (bestblock == NULL)
|
||||
fatalerror("Out of memory allocating block in drcuml_block_begin");
|
||||
memset(bestblock, 0, sizeof(*bestblock));
|
||||
|
||||
/* fill in the structure */
|
||||
bestblock->drcuml = drcuml;
|
||||
bestblock->next = drcuml->blocklist;
|
||||
bestblock->maxinst = maxinst * 3 / 2;
|
||||
bestblock->inst = malloc(sizeof(drcuml_instruction) * bestblock->maxinst);
|
||||
if (bestblock->inst == NULL)
|
||||
fatalerror("Out of memory allocating instruction array in drcuml_block_begin");
|
||||
|
||||
/* hook us into the list */
|
||||
drcuml->blocklist = bestblock;
|
||||
}
|
||||
|
||||
/* set up the block information and return it */
|
||||
bestblock->inuse = TRUE;
|
||||
bestblock->nextinst = 0;
|
||||
bestblock->errorbuf = errorbuf;
|
||||
|
||||
return bestblock;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_append_0 - append an opcode with
|
||||
0 parameters to the block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_append_0(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags)
|
||||
{
|
||||
drcuml_instruction *inst = &block->inst[block->nextinst++];
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* get a pointer to the next instruction */
|
||||
if (block->nextinst > block->maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append");
|
||||
|
||||
/* fill in the instruction */
|
||||
inst->opcode = (UINT8)op;
|
||||
inst->size = size;
|
||||
inst->condflags = condflags;
|
||||
inst->numparams = 0;
|
||||
|
||||
/* validation */
|
||||
validate_instruction(block, inst);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_append_1 - append an opcode with
|
||||
1 parameter to the block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_append_1(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value)
|
||||
{
|
||||
drcuml_instruction *inst = &block->inst[block->nextinst++];
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* get a pointer to the next instruction */
|
||||
if (block->nextinst > block->maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append");
|
||||
|
||||
/* fill in the instruction */
|
||||
inst->opcode = (UINT8)op;
|
||||
inst->size = size;
|
||||
inst->condflags = condflags;
|
||||
inst->numparams = 1;
|
||||
inst->param[0].type = p0type;
|
||||
inst->param[0].value = p0value;
|
||||
|
||||
/* validation */
|
||||
validate_instruction(block, inst);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_append_2 - append an opcode with
|
||||
2 parameters to the block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_append_2(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value)
|
||||
{
|
||||
drcuml_instruction *inst = &block->inst[block->nextinst++];
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* get a pointer to the next instruction */
|
||||
if (block->nextinst > block->maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append");
|
||||
|
||||
/* fill in the instruction */
|
||||
inst->opcode = (UINT8)op;
|
||||
inst->size = size;
|
||||
inst->condflags = condflags;
|
||||
inst->numparams = 2;
|
||||
inst->param[0].type = p0type;
|
||||
inst->param[0].value = p0value;
|
||||
inst->param[1].type = p1type;
|
||||
inst->param[1].value = p1value;
|
||||
|
||||
/* validation */
|
||||
validate_instruction(block, inst);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_append_3 - append an opcode with
|
||||
3 parameters to the block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_append_3(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value, drcuml_ptype p2type, drcuml_pvalue p2value)
|
||||
{
|
||||
drcuml_instruction *inst = &block->inst[block->nextinst++];
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* get a pointer to the next instruction */
|
||||
if (block->nextinst > block->maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append");
|
||||
|
||||
/* fill in the instruction */
|
||||
inst->opcode = (UINT8)op;
|
||||
inst->size = size;
|
||||
inst->condflags = condflags;
|
||||
inst->numparams = 3;
|
||||
inst->param[0].type = p0type;
|
||||
inst->param[0].value = p0value;
|
||||
inst->param[1].type = p1type;
|
||||
inst->param[1].value = p1value;
|
||||
inst->param[2].type = p2type;
|
||||
inst->param[2].value = p2value;
|
||||
|
||||
/* validation */
|
||||
validate_instruction(block, inst);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_append_4 - append an opcode with
|
||||
4 parameters to the block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_append_4(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value, drcuml_ptype p2type, drcuml_pvalue p2value, drcuml_ptype p3type, drcuml_pvalue p3value)
|
||||
{
|
||||
drcuml_instruction *inst = &block->inst[block->nextinst++];
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* get a pointer to the next instruction */
|
||||
if (block->nextinst > block->maxinst)
|
||||
fatalerror("Overran maxinst in drcuml_block_append");
|
||||
|
||||
/* fill in the instruction */
|
||||
inst->opcode = (UINT8)op;
|
||||
inst->size = size;
|
||||
inst->condflags = condflags;
|
||||
inst->numparams = 4;
|
||||
inst->param[0].type = p0type;
|
||||
inst->param[0].value = p0value;
|
||||
inst->param[1].type = p1type;
|
||||
inst->param[1].value = p1value;
|
||||
inst->param[2].type = p2type;
|
||||
inst->param[2].value = p2value;
|
||||
inst->param[3].type = p3type;
|
||||
inst->param[3].value = p3value;
|
||||
|
||||
/* validation */
|
||||
validate_instruction(block, inst);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_end - complete a code block and
|
||||
commit it to the cache via the back-end
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_end(drcuml_block *block)
|
||||
{
|
||||
drcuml_state *drcuml = block->drcuml;
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* if we have a logfile, generate a disassembly of the block */
|
||||
if (drcuml->umllog != NULL)
|
||||
{
|
||||
int instnum;
|
||||
|
||||
/* iterate over instructions and output */
|
||||
for (instnum = 0; instnum < block->nextinst; instnum++)
|
||||
{
|
||||
char dasm[512];
|
||||
drcuml_disasm(&block->inst[instnum], dasm);
|
||||
drcuml_log_printf(drcuml, "%4d: %s\n", instnum, dasm);
|
||||
}
|
||||
drcuml_log_printf(drcuml, "\n\n");
|
||||
fflush(drcuml->umllog);
|
||||
}
|
||||
|
||||
/* generate the code via the back-end */
|
||||
(*drcuml->beintf->be_generate)(drcuml->bestate, block, block->inst, block->nextinst);
|
||||
|
||||
/* block is no longer in use */
|
||||
block->inuse = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_block_abort - abort a code block in
|
||||
progress
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_block_abort(drcuml_block *block)
|
||||
{
|
||||
assert(block->inuse);
|
||||
|
||||
/* block is no longer in use */
|
||||
block->inuse = FALSE;
|
||||
|
||||
/* unwind */
|
||||
longjmp(*block->errorbuf, 1);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_hash_exists - return true if a hash
|
||||
entry exists for the given mode/pc
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drcuml_hash_exists(drcuml_state *drcuml, UINT32 mode, UINT32 pc)
|
||||
{
|
||||
return (*drcuml->beintf->be_hash_exists)(drcuml->bestate, mode, pc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE EXECUTION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_execute - execute at the given PC/mode
|
||||
for the specified cycles
|
||||
-------------------------------------------------*/
|
||||
|
||||
int drcuml_execute(drcuml_state *drcuml, drcuml_codehandle *entry)
|
||||
{
|
||||
return (*drcuml->beintf->be_execute)(drcuml->bestate, entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE HANDLES
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_handle_alloc - allocate a new handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
drcuml_codehandle *drcuml_handle_alloc(drcuml_state *drcuml, const char *name)
|
||||
{
|
||||
drcuml_codehandle *handle;
|
||||
char *string;
|
||||
|
||||
/* allocate space for a copy of the string */
|
||||
string = drccache_memory_alloc(drcuml->cache, strlen(name) + 1);
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
strcpy(string, name);
|
||||
|
||||
/* allocate a new handle info */
|
||||
handle = drccache_memory_alloc_near(drcuml->cache, sizeof(*handle));
|
||||
if (handle == NULL)
|
||||
{
|
||||
drccache_memory_free(drcuml->cache, string, strlen(name) + 1);
|
||||
return NULL;
|
||||
}
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
/* fill in the rest of the info and add to the list of handles */
|
||||
handle->drcuml = drcuml;
|
||||
handle->string = string;
|
||||
handle->next = drcuml->handlelist;
|
||||
drcuml->handlelist = handle;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_handle_set_codeptr - set a codeptr
|
||||
associated with a handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_handle_set_codeptr(drcuml_codehandle *handle, drccodeptr code)
|
||||
{
|
||||
assert(handle->code == NULL);
|
||||
assert_in_cache(handle->drcuml->cache, code);
|
||||
handle->code = code;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_handle_codeptr - get the pointer from
|
||||
a handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr drcuml_handle_codeptr(const drcuml_codehandle *handle)
|
||||
{
|
||||
return handle->code;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_handle_codeptr_addr - get the address
|
||||
of the pointer from a handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
drccodeptr *drcuml_handle_codeptr_addr(drcuml_codehandle *handle)
|
||||
{
|
||||
return &handle->code;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_handle_name - get the name of a handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
const char *drcuml_handle_name(const drcuml_codehandle *handle)
|
||||
{
|
||||
return handle->string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CODE LOGGING
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_log_printf - directly printf to the UML
|
||||
log if generated
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_log_printf(drcuml_state *drcuml, const char *format, ...)
|
||||
{
|
||||
/* if we have a file, print to it */
|
||||
if (drcuml->umllog != NULL)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
/* do the printf */
|
||||
va_start(va, format);
|
||||
vfprintf(drcuml->umllog, format, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_add_comment - attach a comment to the
|
||||
current output location in the specified block
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_add_comment(drcuml_block *block, const char *format, ...)
|
||||
{
|
||||
char buffer[512];
|
||||
char *comment;
|
||||
va_list va;
|
||||
|
||||
assert(block->inuse);
|
||||
|
||||
/* do the printf */
|
||||
va_start(va, format);
|
||||
vsprintf(buffer, format, va);
|
||||
va_end(va);
|
||||
|
||||
/* allocate space in the cache to hold the comment */
|
||||
comment = drccache_memory_alloc_temporary(block->drcuml->cache, strlen(buffer) + 1);
|
||||
if (comment == NULL)
|
||||
return;
|
||||
strcpy(comment, buffer);
|
||||
|
||||
/* add an instruction with a pointer */
|
||||
drcuml_block_append_1(block, DRCUML_OP_COMMENT, 4, DRCUML_COND_ALWAYS, MEM(comment));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
OPCODE VALIDATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
validate_instruction - verify that the
|
||||
instruction created meets all requirements
|
||||
-------------------------------------------------*/
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
static void validate_instruction(drcuml_block *block, const drcuml_instruction *inst)
|
||||
{
|
||||
const drcuml_opcode_valid *opvalid = &opcode_valid_table[inst->opcode];
|
||||
|
||||
/* validate information */
|
||||
assert(inst->opcode != DRCUML_OP_INVALID && inst->opcode < DRCUML_OP_MAX);
|
||||
assert(inst->size == 1 || inst->size == 2 || inst->size == 4 || inst->size == 8);
|
||||
assert((opvalid->sizes & inst->size) != 0);
|
||||
if (inst->numparams > 0)
|
||||
{
|
||||
assert(inst->param[0].type > DRCUML_PTYPE_NONE && inst->param[0].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p0types >> inst->param[0].type) & 1) != 0);
|
||||
if (inst->param[0].type == DRCUML_PTYPE_MEMORY && !(opvalid->p0types & 0x80))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[0].value);
|
||||
}
|
||||
if (inst->numparams > 1)
|
||||
{
|
||||
assert(inst->param[1].type > DRCUML_PTYPE_NONE && inst->param[1].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p1types >> inst->param[1].type) & 1) != 0);
|
||||
if (inst->param[1].type == DRCUML_PTYPE_MEMORY && !(opvalid->p1types & 0x80))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[1].value);
|
||||
}
|
||||
if (inst->numparams > 2)
|
||||
{
|
||||
assert(inst->param[2].type > DRCUML_PTYPE_NONE && inst->param[2].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p2types >> inst->param[2].type) & 1) != 0);
|
||||
if (inst->param[2].type == DRCUML_PTYPE_MEMORY && !(opvalid->p2types & 0x80))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[2].value);
|
||||
}
|
||||
if (inst->numparams > 3)
|
||||
{
|
||||
assert(inst->param[3].type > DRCUML_PTYPE_NONE && inst->param[3].type < DRCUML_PTYPE_MAX);
|
||||
assert(((opvalid->p3types >> inst->param[3].type) & 1) != 0);
|
||||
if (inst->param[3].type == DRCUML_PTYPE_MEMORY && !(opvalid->p3types & 0x80))
|
||||
assert_in_near_cache(block->drcuml->cache, (void *)(FPTR)inst->param[3].value);
|
||||
}
|
||||
}
|
||||
#endif
|
418
src/emu/cpu/drcuml.h
Normal file
418
src/emu/cpu/drcuml.h
Normal file
@ -0,0 +1,418 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcuml.h
|
||||
|
||||
Universal machine language for dynamic recompiling CPU cores.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __DRCUML_H__
|
||||
#define __DRCUML_H__
|
||||
|
||||
#include "memory.h"
|
||||
#include "drccache.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/* these options are passed into drcuml_alloc() and control global behaviors */
|
||||
#define DRCUML_OPTION_USE_C 0x0001 /* always use the C back-end */
|
||||
#define DRCUML_OPTION_LOG_UML 0x0002 /* generate a UML disassembly of each block */
|
||||
#define DRCUML_OPTION_LOG_NATIVE 0x0004 /* tell the back-end to generate a native disassembly of each block */
|
||||
|
||||
|
||||
/* opcode parameter types */
|
||||
enum _drcuml_ptype
|
||||
{
|
||||
DRCUML_PTYPE_NONE = 0,
|
||||
DRCUML_PTYPE_IMMEDIATE,
|
||||
DRCUML_PTYPE_INT_REGISTER,
|
||||
DRCUML_PTYPE_FLOAT_REGISTER,
|
||||
DRCUML_PTYPE_MAPVAR,
|
||||
DRCUML_PTYPE_MEMORY,
|
||||
DRCUML_PTYPE_MAX
|
||||
};
|
||||
typedef enum _drcuml_ptype drcuml_ptype;
|
||||
|
||||
|
||||
/* these define the registers for the UML */
|
||||
enum
|
||||
{
|
||||
DRCUML_REG_INVALID = 0, /* 0 is invalid */
|
||||
|
||||
/* integer registers */
|
||||
DRCUML_REG_I0 = 0x400,
|
||||
DRCUML_REG_I1,
|
||||
DRCUML_REG_I2,
|
||||
DRCUML_REG_I3,
|
||||
DRCUML_REG_I4,
|
||||
DRCUML_REG_I5,
|
||||
DRCUML_REG_I6,
|
||||
DRCUML_REG_I7,
|
||||
DRCUML_REG_I8,
|
||||
DRCUML_REG_I9,
|
||||
DRCUML_REG_I_END,
|
||||
|
||||
/* floating point registers */
|
||||
DRCUML_REG_F0 = 0x800,
|
||||
DRCUML_REG_F1,
|
||||
DRCUML_REG_F2,
|
||||
DRCUML_REG_F3,
|
||||
DRCUML_REG_F4,
|
||||
DRCUML_REG_F5,
|
||||
DRCUML_REG_F6,
|
||||
DRCUML_REG_F7,
|
||||
DRCUML_REG_F8,
|
||||
DRCUML_REG_F9,
|
||||
DRCUML_REG_F_END,
|
||||
|
||||
/* map variables */
|
||||
DRCUML_MAPVAR_M0 = 0xc00,
|
||||
DRCUML_MAPVAR_M1,
|
||||
DRCUML_MAPVAR_M2,
|
||||
DRCUML_MAPVAR_M3,
|
||||
DRCUML_MAPVAR_M4,
|
||||
DRCUML_MAPVAR_M5,
|
||||
DRCUML_MAPVAR_M6,
|
||||
DRCUML_MAPVAR_M7,
|
||||
DRCUML_MAPVAR_M8,
|
||||
DRCUML_MAPVAR_M9,
|
||||
DRCUML_MAPVAR_END
|
||||
};
|
||||
|
||||
|
||||
/* UML flag definitions */
|
||||
enum
|
||||
{
|
||||
DRCUML_FLAG_C = 1, /* carry flag */
|
||||
DRCUML_FLAG_V = 2, /* overflow flag (defined for integer only) */
|
||||
DRCUML_FLAG_Z = 4, /* zero flag */
|
||||
DRCUML_FLAG_S = 8, /* sign flag (defined for integer only) */
|
||||
DRCUML_FLAG_U = 16 /* unordered flag (defined for FP only) */
|
||||
};
|
||||
|
||||
|
||||
/* these define the conditions for the UML */
|
||||
/* note that these are defined such that (condition ^ 1) is always the opposite */
|
||||
/* they are also defined so as not to conflict with the flag bits above */
|
||||
enum
|
||||
{
|
||||
DRCUML_COND_ALWAYS = 0,
|
||||
|
||||
DRCUML_COND_Z = 0x80, /* requires Z */
|
||||
DRCUML_COND_NZ, /* requires Z */
|
||||
DRCUML_COND_S, /* requires S */
|
||||
DRCUML_COND_NS, /* requires S */
|
||||
DRCUML_COND_C, /* requires C */
|
||||
DRCUML_COND_NC, /* requires C */
|
||||
DRCUML_COND_V, /* requires V */
|
||||
DRCUML_COND_NV, /* requires V */
|
||||
DRCUML_COND_U, /* requires U */
|
||||
DRCUML_COND_NU, /* requires U */
|
||||
DRCUML_COND_A, /* requires CZ */
|
||||
DRCUML_COND_BE, /* requires CZ */
|
||||
DRCUML_COND_G, /* requires SVZ */
|
||||
DRCUML_COND_LE, /* requires SVZ */
|
||||
DRCUML_COND_L, /* requires SV */
|
||||
DRCUML_COND_GE, /* requires SV */
|
||||
|
||||
DRCUML_COND_MAX
|
||||
};
|
||||
|
||||
|
||||
/* basic condition code aliases */
|
||||
enum
|
||||
{
|
||||
DRCUML_COND_E = DRCUML_COND_Z,
|
||||
DRCUML_COND_NE = DRCUML_COND_NZ,
|
||||
DRCUML_COND_B = DRCUML_COND_C,
|
||||
DRCUML_COND_AE = DRCUML_COND_NC
|
||||
};
|
||||
|
||||
|
||||
/* floating point modes */
|
||||
enum
|
||||
{
|
||||
DRCUML_FMOD_TRUNC, /* truncate */
|
||||
DRCUML_FMOD_ROUND, /* round */
|
||||
DRCUML_FMOD_CEIL, /* round up */
|
||||
DRCUML_FMOD_FLOOR /* round down */
|
||||
};
|
||||
|
||||
|
||||
/* these define the opcodes for the UML */
|
||||
enum _drcuml_opcode
|
||||
{
|
||||
DRCUML_OP_INVALID,
|
||||
|
||||
/* Compile-time opcodes */
|
||||
DRCUML_OP_HANDLE, /* HANDLE handle */
|
||||
DRCUML_OP_HASH, /* HASH mode,pc */
|
||||
DRCUML_OP_LABEL, /* LABEL imm */
|
||||
DRCUML_OP_COMMENT, /* COMMENT string */
|
||||
DRCUML_OP_MAPVAR, /* MAPVAR mapvar,value */
|
||||
|
||||
/* Control Flow Operations */
|
||||
DRCUML_OP_DEBUG, /* DEBUG pc */
|
||||
DRCUML_OP_EXIT, /* EXIT src1[,c] */
|
||||
DRCUML_OP_HASHJMP, /* HASHJMP mode,pc,handle */
|
||||
DRCUML_OP_JMP, /* JMP imm[,c] */
|
||||
DRCUML_OP_EXH, /* EXH handle,param[,c] */
|
||||
DRCUML_OP_CALLH, /* CALLH handle[,c] */
|
||||
DRCUML_OP_RET, /* RET [c] */
|
||||
DRCUML_OP_CALLC, /* CALLC func,ptr[,c] */
|
||||
DRCUML_OP_RECOVER, /* RECOVER dst,mapvar */
|
||||
|
||||
/* Internal Register Operations */
|
||||
DRCUML_OP_SETFMOD, /* SETFMOD src */
|
||||
DRCUML_OP_GETFMOD, /* GETFMOD dst */
|
||||
DRCUML_OP_GETEXP, /* GETEXP dst,index */
|
||||
|
||||
/* Integer Operations */
|
||||
DRCUML_OP_LOAD1U, /* LOAD1U dst,base,index */
|
||||
DRCUML_OP_LOAD1S, /* LOAD1S dst,base,index */
|
||||
DRCUML_OP_LOAD2U, /* LOAD2U dst,base,index */
|
||||
DRCUML_OP_LOAD2S, /* LOAD2S dst,base,index */
|
||||
DRCUML_OP_LOAD4U, /* LOAD4U dst,base,index */
|
||||
DRCUML_OP_LOAD4S, /* LOAD4S dst,base,index */
|
||||
DRCUML_OP_LOAD8U, /* LOAD8U dst,base,index */
|
||||
DRCUML_OP_STORE1, /* STORE1 base,index,src */
|
||||
DRCUML_OP_STORE2, /* STORE2 base,index,src */
|
||||
DRCUML_OP_STORE4, /* STORE4 base,index,src */
|
||||
DRCUML_OP_STORE8, /* STORE8 base,index,src */
|
||||
DRCUML_OP_READ1U, /* READ1U dst,space,src1 */
|
||||
DRCUML_OP_READ1S, /* READ1S dst,space,src1 */
|
||||
DRCUML_OP_READ2U, /* READ2U dst,space,src1 */
|
||||
DRCUML_OP_READ2S, /* READ2S dst,space,src1 */
|
||||
DRCUML_OP_READ2M, /* READ2M dst,space,src1,mask */
|
||||
DRCUML_OP_READ4U, /* READ4U dst,space,src1 */
|
||||
DRCUML_OP_READ4S, /* READ4S dst,space,src1 */
|
||||
DRCUML_OP_READ4M, /* READ4M dst,space,src1,mask */
|
||||
DRCUML_OP_READ8U, /* READ8U dst,space,src1 */
|
||||
DRCUML_OP_READ8M, /* READ8M dst,space,src1,mask */
|
||||
DRCUML_OP_WRITE1, /* WRITE1 space,dst,src1 */
|
||||
DRCUML_OP_WRITE2, /* WRITE2 space,dst,src1 */
|
||||
DRCUML_OP_WRIT2M, /* WRIT2M space,dst,mask,src1 */
|
||||
DRCUML_OP_WRITE4, /* WRITE4 space,dst,src1 */
|
||||
DRCUML_OP_WRIT4M, /* WRIT4M space,dst,mask,src1 */
|
||||
DRCUML_OP_WRITE8, /* WRITE8 space,dst,src1 */
|
||||
DRCUML_OP_WRIT8M, /* WRIT8M space,dst,mask,src1 */
|
||||
DRCUML_OP_FLAGS, /* FLAGS dst,mask,table */
|
||||
DRCUML_OP_MOV, /* MOV dst,src[,c] */
|
||||
DRCUML_OP_ZEXT1, /* ZEXT1 dst,src */
|
||||
DRCUML_OP_ZEXT2, /* ZEXT2 dst,src */
|
||||
DRCUML_OP_ZEXT4, /* ZEXT4 dst,src */
|
||||
DRCUML_OP_SEXT1, /* SEXT1 dst,src */
|
||||
DRCUML_OP_SEXT2, /* SEXT2 dst,src */
|
||||
DRCUML_OP_SEXT4, /* SEXT4 dst,src */
|
||||
DRCUML_OP_ADD, /* ADD dst,src1,src2[,f] */
|
||||
DRCUML_OP_ADDC, /* ADDC dst,src1,src2[,f] */
|
||||
DRCUML_OP_SUB, /* SUB dst,src1,src2[,f] */
|
||||
DRCUML_OP_SUBB, /* SUBB dst,src1,src2[,f] */
|
||||
DRCUML_OP_CMP, /* CMP src1,src2[,f] */
|
||||
DRCUML_OP_MULU, /* MULU dst,edst,src1,src2[,f] */
|
||||
DRCUML_OP_MULS, /* MULS dst,edst,src1,src2[,f] */
|
||||
DRCUML_OP_DIVU, /* DIVU dst,edst,src1,src2[,f] */
|
||||
DRCUML_OP_DIVS, /* DIVS dst,edst,src1,src2[,f] */
|
||||
DRCUML_OP_AND, /* AND dst,src1,src2[,f] */
|
||||
DRCUML_OP_TEST, /* TEST src1,src2[,f] */
|
||||
DRCUML_OP_OR, /* OR dst,src1,src2[,f] */
|
||||
DRCUML_OP_XOR, /* XOR dst,src1,src2[,f] */
|
||||
DRCUML_OP_SHL, /* SHL dst,src,count[,f] */
|
||||
DRCUML_OP_SHR, /* SHR dst,src,count[,f] */
|
||||
DRCUML_OP_SAR, /* SAR dst,src,count[,f] */
|
||||
DRCUML_OP_ROL, /* ROL dst,src,count[,f] */
|
||||
DRCUML_OP_ROLC, /* ROLC dst,src,count[,f] */
|
||||
DRCUML_OP_ROR, /* ROL dst,src,count[,f] */
|
||||
DRCUML_OP_RORC, /* ROLC dst,src,count[,f] */
|
||||
|
||||
/* Floating Point Operations */
|
||||
DRCUML_OP_FLOAD, /* FLOAD dst,base,index */
|
||||
DRCUML_OP_FSTORE, /* FSTORE base,index,src */
|
||||
DRCUML_OP_FREAD, /* FREAD dst,space,src1 */
|
||||
DRCUML_OP_FWRITE, /* FWRITE space,dst,src1 */
|
||||
DRCUML_OP_FMOV, /* FSMOV dst,src1[,c] */
|
||||
DRCUML_OP_FTOI4, /* FTOI4 dst,src1 */
|
||||
DRCUML_OP_FTOI4T, /* FTOI4T dst,src1 */
|
||||
DRCUML_OP_FTOI4R, /* FTOI4R dst,src1 */
|
||||
DRCUML_OP_FTOI4F, /* FTOI4F dst,src1 */
|
||||
DRCUML_OP_FTOI4C, /* FTOI4C dst,src1 */
|
||||
DRCUML_OP_FTOI8, /* FTOI8 dst,src1 */
|
||||
DRCUML_OP_FTOI8T, /* FTOI8T dst,src1 */
|
||||
DRCUML_OP_FTOI8R, /* FTOI8R dst,src1 */
|
||||
DRCUML_OP_FTOI8F, /* FTOI8F dst,src1 */
|
||||
DRCUML_OP_FTOI8C, /* FTOI8C dst,src1 */
|
||||
DRCUML_OP_FFRFS, /* FFRFS dst,src1 */
|
||||
DRCUML_OP_FFRFD, /* FFRFD dst,src1 */
|
||||
DRCUML_OP_FFRI4, /* FFRI4 dst,src1 */
|
||||
DRCUML_OP_FFRI8, /* FFRI8 dst,src1 */
|
||||
DRCUML_OP_FADD, /* FADD dst,src1,src2 */
|
||||
DRCUML_OP_FSUB, /* FSUB dst,src1,src2 */
|
||||
DRCUML_OP_FCMP, /* FCMP src1,src2 */
|
||||
DRCUML_OP_FMUL, /* FMUL dst,src1,src2 */
|
||||
DRCUML_OP_FDIV, /* FDIV dst,src1,src2 */
|
||||
DRCUML_OP_FNEG, /* FNEG dst,src1 */
|
||||
DRCUML_OP_FABS, /* FABS dst,src1 */
|
||||
DRCUML_OP_FSQRT, /* FSQRT dst,src1 */
|
||||
DRCUML_OP_FRECIP, /* FRECIP dst,src1 */
|
||||
DRCUML_OP_FRSQRT, /* FRSQRT dst,src1 */
|
||||
|
||||
DRCUML_OP_MAX
|
||||
};
|
||||
typedef enum _drcuml_opcode drcuml_opcode;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* represents a reference to a local label in the code */
|
||||
typedef UINT32 drcuml_codelabel;
|
||||
|
||||
/* represents the value of an opcode parameter */
|
||||
typedef UINT64 drcuml_pvalue;
|
||||
|
||||
|
||||
/* opaque structure describing UML generation state */
|
||||
typedef struct _drcuml_state drcuml_state;
|
||||
|
||||
/* opaque structure describing UML codegen block */
|
||||
typedef struct _drcuml_block drcuml_block;
|
||||
|
||||
/* opaque structure describing back-end state */
|
||||
typedef struct _drcbe_state drcbe_state;
|
||||
|
||||
/* opaque structure describing a code handle */
|
||||
typedef struct _drcuml_codehandle drcuml_codehandle;
|
||||
|
||||
|
||||
/* a parameter for a UML instructon is encoded like this */
|
||||
typedef struct _drcuml_parameter drcuml_parameter;
|
||||
struct _drcuml_parameter
|
||||
{
|
||||
drcuml_ptype type; /* parameter type */
|
||||
drcuml_pvalue value; /* parameter value */
|
||||
};
|
||||
|
||||
|
||||
/* a single UML instructon is encoded like this */
|
||||
typedef struct _drcuml_instruction drcuml_instruction;
|
||||
struct _drcuml_instruction
|
||||
{
|
||||
drcuml_opcode opcode; /* opcode */
|
||||
UINT8 condflags; /* condition or flags */
|
||||
UINT8 size; /* operation size */
|
||||
UINT8 numparams; /* number of parameters */
|
||||
drcuml_parameter param[4]; /* up to 4 parameters */
|
||||
};
|
||||
|
||||
|
||||
/* typedefs for back-end callback functions */
|
||||
typedef drcbe_state *(*drcbe_alloc_func)(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
|
||||
typedef void (*drcbe_free_func)(drcbe_state *state);
|
||||
typedef void (*drcbe_reset_func)(drcbe_state *state);
|
||||
typedef int (*drcbe_execute_func)(drcbe_state *state, drcuml_codehandle *entry);
|
||||
typedef void (*drcbe_generate_func)(drcbe_state *state, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
|
||||
typedef int (*drcbe_hash_exists)(drcbe_state *state, UINT32 mode, UINT32 pc);
|
||||
|
||||
|
||||
/* interface structure for a back-end */
|
||||
typedef struct _drcbe_interface drcbe_interface;
|
||||
struct _drcbe_interface
|
||||
{
|
||||
drcbe_alloc_func be_alloc;
|
||||
drcbe_free_func be_free;
|
||||
drcbe_reset_func be_reset;
|
||||
drcbe_execute_func be_execute;
|
||||
drcbe_generate_func be_generate;
|
||||
drcbe_hash_exists be_hash_exists;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* ----- initialization/teardown ----- */
|
||||
|
||||
/* allocate state for the code generator and initialize the back-end */
|
||||
drcuml_state *drcuml_alloc(drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
|
||||
|
||||
/* reset the state completely, flushing the cache and all information */
|
||||
void drcuml_reset(drcuml_state *drcuml);
|
||||
|
||||
/* free state for the code generator and the back-end */
|
||||
void drcuml_free(drcuml_state *drcuml);
|
||||
|
||||
|
||||
|
||||
/* ----- code block generation ----- */
|
||||
|
||||
/* begin a new code block */
|
||||
drcuml_block *drcuml_block_begin(drcuml_state *drcuml, UINT32 maxinst, jmp_buf *errorbuf);
|
||||
|
||||
/* append an opcode to the block, with 0-4 parameters */
|
||||
void drcuml_block_append_0(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags);
|
||||
void drcuml_block_append_1(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value);
|
||||
void drcuml_block_append_2(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value);
|
||||
void drcuml_block_append_3(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value, drcuml_ptype p2type, drcuml_pvalue p2value);
|
||||
void drcuml_block_append_4(drcuml_block *block, drcuml_opcode op, UINT8 size, UINT8 condflags, drcuml_ptype p0type, drcuml_pvalue p0value, drcuml_ptype p1type, drcuml_pvalue p1value, drcuml_ptype p2type, drcuml_pvalue p2value, drcuml_ptype p3type, drcuml_pvalue p3value);
|
||||
|
||||
/* complete a code block and commit it to the cache via the back-end */
|
||||
void drcuml_block_end(drcuml_block *block);
|
||||
|
||||
/* abort a code block in progress due to cache allocation failure */
|
||||
void drcuml_block_abort(drcuml_block *block);
|
||||
|
||||
/* return true if a hash entry exists for the given mode/pc */
|
||||
int drcuml_hash_exists(drcuml_state *drcuml, UINT32 mode, UINT32 pc);
|
||||
|
||||
|
||||
|
||||
/* ----- code execution ----- */
|
||||
|
||||
/* execute at the given PC/mode for the specified cycles */
|
||||
int drcuml_execute(drcuml_state *drcuml, drcuml_codehandle *entry);
|
||||
|
||||
|
||||
|
||||
/* ----- code handles ----- */
|
||||
|
||||
/* allocate a new handle */
|
||||
drcuml_codehandle *drcuml_handle_alloc(drcuml_state *drcuml, const char *name);
|
||||
|
||||
/* set the handle pointer */
|
||||
void drcuml_handle_set_codeptr(drcuml_codehandle *handle, drccodeptr code);
|
||||
|
||||
/* get the pointer from a handle */
|
||||
drccodeptr drcuml_handle_codeptr(const drcuml_codehandle *handle);
|
||||
|
||||
/* get the address of the pointer from a handle */
|
||||
drccodeptr *drcuml_handle_codeptr_addr(drcuml_codehandle *handle);
|
||||
|
||||
/* get the name of a handle */
|
||||
const char *drcuml_handle_name(const drcuml_codehandle *handle);
|
||||
|
||||
|
||||
|
||||
/* ----- code logging ----- */
|
||||
|
||||
/* directly printf to the UML log if generated */
|
||||
void drcuml_log_printf(drcuml_state *state, const char *format, ...) ATTR_PRINTF(2,3);
|
||||
|
||||
/* attach a comment to the current output location in the specified block */
|
||||
void drcuml_add_comment(drcuml_block *block, const char *format, ...) ATTR_PRINTF(2,3);
|
||||
|
||||
|
||||
#endif
|
453
src/emu/cpu/drcumld.c
Normal file
453
src/emu/cpu/drcumld.c
Normal file
@ -0,0 +1,453 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcumld.c
|
||||
|
||||
Universal machine language disassembler.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "drcumld.h"
|
||||
#include "drcumlsh.h"
|
||||
#include "memory.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef char *(*output_function)(char *dest, int size, const drcuml_parameter *param);
|
||||
|
||||
|
||||
typedef struct _drcuml_opdesc drcuml_opdesc;
|
||||
struct _drcuml_opdesc
|
||||
{
|
||||
UINT16 opcode;
|
||||
const char * opstring;
|
||||
output_function param[5];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
static char *output_cond(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_flags(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_flags_cmptest(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_param(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_param_string(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_param_handle(char *dest, int size, const drcuml_parameter *param);
|
||||
static char *output_param_space(char *dest, int size, const drcuml_parameter *param);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TABLES
|
||||
***************************************************************************/
|
||||
|
||||
/* these define the conditions for the UML */
|
||||
static const char *condname[] =
|
||||
{
|
||||
"z", "nz",
|
||||
"s", "ns",
|
||||
"c", "nc",
|
||||
"v", "nv",
|
||||
"u", "nu",
|
||||
"a", "be",
|
||||
"g", "le",
|
||||
"l", "ge"
|
||||
};
|
||||
|
||||
/* the source opcode table */
|
||||
static const drcuml_opdesc opcode_source_table[] =
|
||||
{
|
||||
/* Compile-time opcodes */
|
||||
{ DRCUML_OP_HANDLE, "handle", { output_param_handle } },
|
||||
{ DRCUML_OP_HASH, "hash", { output_param, output_param } },
|
||||
{ DRCUML_OP_LABEL, "label", { output_param } },
|
||||
{ DRCUML_OP_COMMENT, "comment", { output_param_string } },
|
||||
{ DRCUML_OP_MAPVAR, "mapvar", { output_param, output_param } },
|
||||
|
||||
/* Control Flow Operations */
|
||||
{ DRCUML_OP_DEBUG, "debug", { output_param } },
|
||||
{ DRCUML_OP_EXIT, "exit", { output_param, output_cond } },
|
||||
{ DRCUML_OP_HASHJMP, "hashjmp", { output_param, output_param, output_param_handle } },
|
||||
{ DRCUML_OP_JMP, "jmp", { output_param, output_cond } },
|
||||
{ DRCUML_OP_EXH, "exh", { output_param_handle, output_param, output_cond } } ,
|
||||
{ DRCUML_OP_CALLH, "callh", { output_param_handle, output_cond } },
|
||||
{ DRCUML_OP_RET, "ret", { output_cond } },
|
||||
{ DRCUML_OP_CALLC, "callc", { output_param, output_param, output_cond } },
|
||||
{ DRCUML_OP_RECOVER, "recover", { output_param, output_param } },
|
||||
|
||||
/* Internal Register Operations */
|
||||
{ DRCUML_OP_SETFMOD, "setfmod", { output_param } },
|
||||
{ DRCUML_OP_GETFMOD, "getfmod", { output_param } },
|
||||
{ DRCUML_OP_GETEXP, "getexp", { output_param } },
|
||||
|
||||
/* Integer Operations */
|
||||
{ DRCUML_OP_LOAD1U, "!load1u", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD1S, "!load1s", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD2U, "!load2u", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD2S, "!load2s", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD4U, "!load4u", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD4S, "!load4s", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_LOAD8U, "!load8u", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_STORE1, "!store1", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_STORE2, "!store2", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_STORE4, "!store4", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_STORE8, "!store8", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_READ1U, "!read1u", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ1S, "!read1s", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ2U, "!read2u", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ2S, "!read2s", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ2M, "!read2m", { output_param, output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_READ4U, "!read4u", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ4S, "!read4s", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ4M, "!read4m", { output_param, output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_READ8U, "!read8u", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_READ8M, "!read8m", { output_param, output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_WRITE1, "!write1", { output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_WRITE2, "!write2", { output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_WRIT2M, "!writ2m", { output_param_space, output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_WRITE4, "!write4", { output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_WRIT4M, "!writ4m", { output_param_space, output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_WRITE8, "!write8", { output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_WRIT8M, "!writ8m", { output_param_space, output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FLAGS, "!flags", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_MOV, "!mov", { output_param, output_param, output_cond } },
|
||||
{ DRCUML_OP_ZEXT1, "!zext1", { output_param, output_param } },
|
||||
{ DRCUML_OP_ZEXT2, "!zext2", { output_param, output_param } },
|
||||
{ DRCUML_OP_ZEXT4, "!zext4", { output_param, output_param } },
|
||||
{ DRCUML_OP_SEXT1, "!sext1", { output_param, output_param } },
|
||||
{ DRCUML_OP_SEXT2, "!sext2", { output_param, output_param } },
|
||||
{ DRCUML_OP_SEXT4, "!sext4", { output_param, output_param } },
|
||||
{ DRCUML_OP_ADD, "!add", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_ADDC, "!addc", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_SUB, "!sub", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_SUBB, "!subb", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_CMP, "!cmp", { output_param, output_param, output_flags_cmptest } },
|
||||
{ DRCUML_OP_MULU, "!mulu", { output_param, output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_MULS, "!muls", { output_param, output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_DIVU, "!divu", { output_param, output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_DIVS, "!divs", { output_param, output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_AND, "!and", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_TEST, "!test", { output_param, output_param, output_flags_cmptest } },
|
||||
{ DRCUML_OP_OR, "!or", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_XOR, "!xor", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_SHL, "!shl", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_SHR, "!shr", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_SAR, "!sar", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_ROL, "!rol", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_ROLC, "!rolc", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_ROR, "!ror", { output_param, output_param, output_param, output_flags } },
|
||||
{ DRCUML_OP_RORC, "!rorc", { output_param, output_param, output_param, output_flags } },
|
||||
|
||||
/* Floating-Point Operations */
|
||||
{ DRCUML_OP_FLOAD, "f!load", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FSTORE, "f!store", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FREAD, "f!read", { output_param, output_param_space, output_param } },
|
||||
{ DRCUML_OP_FWRITE, "f!write", { output_param_space, output_param, output_param } },
|
||||
{ DRCUML_OP_FMOV, "f!mov", { output_param, output_param, output_cond } },
|
||||
{ DRCUML_OP_FTOI4, "f!toi4", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI4T, "f!toi4t", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI4R, "f!toi4r", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI4F, "f!toi4f", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI4C, "f!toi4c", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI8, "f!toi8", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI8T, "f!toi8t", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI8R, "f!toi8r", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI8F, "f!toi8f", { output_param, output_param } },
|
||||
{ DRCUML_OP_FTOI8C, "f!toi8c", { output_param, output_param } },
|
||||
{ DRCUML_OP_FFRFS, "f!frfs", { output_param, output_param } },
|
||||
{ DRCUML_OP_FFRFD, "f!frfd", { output_param, output_param } },
|
||||
{ DRCUML_OP_FFRI4, "f!fri4", { output_param, output_param } },
|
||||
{ DRCUML_OP_FFRI8, "f!fri8", { output_param, output_param } },
|
||||
{ DRCUML_OP_FADD, "f!add", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FSUB, "f!sub", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FCMP, "f!cmp", { output_param, output_param, output_flags_cmptest } },
|
||||
{ DRCUML_OP_FMUL, "f!mul", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FDIV, "f!div", { output_param, output_param, output_param } },
|
||||
{ DRCUML_OP_FNEG, "f!neg", { output_param, output_param } },
|
||||
{ DRCUML_OP_FABS, "f!abs", { output_param, output_param } },
|
||||
{ DRCUML_OP_FSQRT, "f!sqrt", { output_param, output_param } },
|
||||
{ DRCUML_OP_FRECIP, "f!recip", { output_param, output_param } },
|
||||
{ DRCUML_OP_FRSQRT, "f!rsqrt", { output_param, output_param } },
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
static const drcuml_opdesc *opcode_table[DRCUML_OP_MAX];
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CORE DISASSEMBLER
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
drcuml_disasm - disassemble one instruction
|
||||
-------------------------------------------------*/
|
||||
|
||||
void drcuml_disasm(const drcuml_instruction *inst, char *buffer)
|
||||
{
|
||||
const drcuml_opdesc *opdesc;
|
||||
const char *stringptr;
|
||||
char *dest = buffer;
|
||||
int pnum, iparam = 0;
|
||||
|
||||
/* if this is the first time through, populate the opcode table */
|
||||
if (opcode_table[DRCUML_OP_HASH] == NULL)
|
||||
{
|
||||
int tabledex;
|
||||
|
||||
for (tabledex = 0; tabledex < ARRAY_LENGTH(opcode_source_table); tabledex++)
|
||||
opcode_table[opcode_source_table[tabledex].opcode] = &opcode_source_table[tabledex];
|
||||
}
|
||||
|
||||
/* find the opcode in the list */
|
||||
opdesc = opcode_table[inst->opcode];
|
||||
|
||||
/* NULL means invalid opcode */
|
||||
if (opdesc == NULL)
|
||||
{
|
||||
strcpy(buffer, "???");
|
||||
return;
|
||||
}
|
||||
|
||||
/* start with the opcode itself */
|
||||
stringptr = opdesc->opstring;
|
||||
|
||||
/* insert a prefix for integer operations */
|
||||
if (stringptr[0] == '!')
|
||||
{
|
||||
stringptr++;
|
||||
switch (inst->size)
|
||||
{
|
||||
case 1: *dest++ = 'b'; break;
|
||||
case 2: *dest++ = 'w'; break;
|
||||
case 4: break;
|
||||
case 8: *dest++ = 'd'; break;
|
||||
default: *dest++ = '?'; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert a prefix for floating point operations */
|
||||
if (stringptr[0] == 'f' && stringptr[1] == '!')
|
||||
{
|
||||
*dest++ = *stringptr++;
|
||||
stringptr++;
|
||||
switch (inst->size)
|
||||
{
|
||||
case 4: *dest++ = 's'; break;
|
||||
case 8: *dest++ = 'd'; break;
|
||||
default: *dest++ = '?'; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the rest of the string */
|
||||
dest += sprintf(dest, "%s", stringptr);
|
||||
|
||||
/* iterate over parameters */
|
||||
for (pnum = 0; pnum < ARRAY_LENGTH(opdesc->param); pnum++)
|
||||
{
|
||||
output_function func = opdesc->param[pnum];
|
||||
drcuml_parameter param;
|
||||
|
||||
/* stop when we hit NULL */
|
||||
if (func == NULL)
|
||||
break;
|
||||
|
||||
/* if we are outputting a condition but it's "always", skip it */
|
||||
if (func == output_cond)
|
||||
{
|
||||
if (inst->condflags == DRCUML_COND_ALWAYS)
|
||||
continue;
|
||||
param.value = inst->condflags;
|
||||
}
|
||||
|
||||
/* if we are outputting flags but they are "none", skip it */
|
||||
else if (func == output_flags)
|
||||
{
|
||||
if (inst->condflags == FLAGS_NONE)
|
||||
continue;
|
||||
param.value = inst->condflags;
|
||||
}
|
||||
|
||||
/* if we are outputting test/cmp flags but they are "all", skip it */
|
||||
else if (func == output_flags_cmptest)
|
||||
{
|
||||
if (inst->opcode == DRCUML_OP_CMP && inst->condflags == FLAGS_ALLI)
|
||||
continue;
|
||||
if (inst->opcode == DRCUML_OP_FCMP && inst->condflags == FLAGS_ALLF)
|
||||
continue;
|
||||
if (inst->opcode == DRCUML_OP_TEST && inst->condflags == (FLAGS_S|FLAGS_Z))
|
||||
continue;
|
||||
param.value = inst->condflags;
|
||||
}
|
||||
|
||||
/* otherwise, we are fetching an actual parameter */
|
||||
else
|
||||
param = inst->param[iparam++];
|
||||
|
||||
/* if we are less than 8 characters, pad to 8 */
|
||||
if (dest - buffer < 8)
|
||||
dest += sprintf(dest, "%*s", 8 - (dest - buffer), "");
|
||||
|
||||
/* otherwise, add a comma */
|
||||
else
|
||||
dest += sprintf(dest, ",");
|
||||
|
||||
/* then append the parameter */
|
||||
dest = (*func)(dest, inst->size, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
OUTPUT HELPERS
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_cond - output condition
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_cond(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if (param->value >= DRCUML_COND_Z && param->value < DRCUML_COND_MAX)
|
||||
return dest + sprintf(dest, "%s", condname[param->value - DRCUML_COND_Z]);
|
||||
else
|
||||
return dest + sprintf(dest, "??");
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_flags - output flags
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_flags(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if ((param->value & (DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0)
|
||||
return dest + sprintf(dest, "noflags");
|
||||
if (param->value & DRCUML_FLAG_C)
|
||||
*dest++ = 'C';
|
||||
if (param->value & DRCUML_FLAG_V)
|
||||
*dest++ = 'V';
|
||||
if (param->value & DRCUML_FLAG_Z)
|
||||
*dest++ = 'Z';
|
||||
if (param->value & DRCUML_FLAG_S)
|
||||
*dest++ = 'S';
|
||||
*dest = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_flags_cmptest - output flags
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_flags_cmptest(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if ((param->value & (DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == (DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S))
|
||||
return dest + sprintf(dest, "allflags");
|
||||
return output_flags(dest, size, param);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_param - generic parameter output
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_param(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
UINT64 value;
|
||||
switch (param->type)
|
||||
{
|
||||
case DRCUML_PTYPE_NONE:
|
||||
return dest += sprintf(dest, "<none?>");
|
||||
|
||||
case DRCUML_PTYPE_IMMEDIATE:
|
||||
value = param->value;
|
||||
if (size == 1) value = (UINT8)value;
|
||||
if (size == 2) value = (UINT16)value;
|
||||
if (size == 4) value = (UINT32)value;
|
||||
if ((UINT32)value == value)
|
||||
return dest += sprintf(dest, "$%X", (UINT32)value);
|
||||
else
|
||||
return dest += sprintf(dest, "$%X%08X", (UINT32)(value >> 32), (UINT32)value);
|
||||
|
||||
case DRCUML_PTYPE_MAPVAR:
|
||||
if (param->value >= DRCUML_MAPVAR_M0 && param->value < DRCUML_MAPVAR_END)
|
||||
return dest += sprintf(dest, "m%d", (UINT32)(param->value - DRCUML_MAPVAR_M0));
|
||||
else
|
||||
return dest += sprintf(dest, "m(%X?)", (UINT32)param->value);
|
||||
|
||||
case DRCUML_PTYPE_INT_REGISTER:
|
||||
if (param->value >= DRCUML_REG_I0 && param->value < DRCUML_REG_I_END)
|
||||
return dest += sprintf(dest, "i%d", (UINT32)(param->value - DRCUML_REG_I0));
|
||||
else
|
||||
return dest += sprintf(dest, "i(%X?)", (UINT32)param->value);
|
||||
|
||||
case DRCUML_PTYPE_FLOAT_REGISTER:
|
||||
if (param->value >= DRCUML_REG_F0 && param->value < DRCUML_REG_F_END)
|
||||
return dest += sprintf(dest, "f%d", (UINT32)(param->value - DRCUML_REG_F0));
|
||||
else
|
||||
return dest += sprintf(dest, "f(%X?)", (UINT32)param->value);
|
||||
|
||||
case DRCUML_PTYPE_MEMORY:
|
||||
return dest += sprintf(dest, "[$%p]", (void *)(FPTR)param->value);
|
||||
|
||||
default:
|
||||
return dest += sprintf(dest, "???");
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_param_string - output parameter 0,
|
||||
assuming it is a string
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_param_string(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if (param->type == DRCUML_PTYPE_MEMORY)
|
||||
return dest += sprintf(dest, "%s", (char *)(FPTR)param->value);
|
||||
return output_param(dest, size, param);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_param_handle - output parameter 0,
|
||||
assuming it is a handle
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_param_handle(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if (param->type == DRCUML_PTYPE_MEMORY)
|
||||
return dest += sprintf(dest, "%s", drcuml_handle_name((drcuml_codehandle *)(FPTR)param->value));
|
||||
return output_param(dest, size, param);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
output_param_space - output parameter 0,
|
||||
assuming it is an address space
|
||||
-------------------------------------------------*/
|
||||
|
||||
static char *output_param_space(char *dest, int size, const drcuml_parameter *param)
|
||||
{
|
||||
if (param->type == DRCUML_PTYPE_IMMEDIATE && param->value >= ADDRESS_SPACE_PROGRAM && param->value <= ADDRESS_SPACE_IO)
|
||||
return dest + sprintf(dest, "%s", address_space_names[param->value]);
|
||||
return output_param(dest, size, param);
|
||||
}
|
30
src/emu/cpu/drcumld.h
Normal file
30
src/emu/cpu/drcumld.h
Normal file
@ -0,0 +1,30 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcumld.h
|
||||
|
||||
Universal machine language disassembler.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __DRCUMLD_H__
|
||||
#define __DRCUMLD_H__
|
||||
|
||||
#include "drcuml.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* disassemble one instruction */
|
||||
void drcuml_disasm(const drcuml_instruction *inst, char *buffer);
|
||||
|
||||
|
||||
#endif
|
409
src/emu/cpu/drcumlsh.h
Normal file
409
src/emu/cpu/drcumlsh.h
Normal file
@ -0,0 +1,409 @@
|
||||
/***************************************************************************
|
||||
|
||||
drcumlsh.h
|
||||
|
||||
Shorthand definitions for the universal machine language.
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __DRCUMLSH_H__
|
||||
#define __DRCUMLSH_H__
|
||||
|
||||
#include "drcuml.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
/* shorthand for conditions */
|
||||
#define IF_Z DRCUML_COND_Z
|
||||
#define IF_NZ DRCUML_COND_NZ
|
||||
#define IF_S DRCUML_COND_S
|
||||
#define IF_NS DRCUML_COND_NS
|
||||
#define IF_C DRCUML_COND_C
|
||||
#define IF_NC DRCUML_COND_NC
|
||||
#define IF_V DRCUML_COND_V
|
||||
#define IF_NV DRCUML_COND_NV
|
||||
#define IF_U DRCUML_COND_U
|
||||
#define IF_NU DRCUML_COND_NU
|
||||
#define IF_E DRCUML_COND_E
|
||||
#define IF_NE DRCUML_COND_NE
|
||||
#define IF_A DRCUML_COND_A
|
||||
#define IF_AE DRCUML_COND_AE
|
||||
#define IF_B DRCUML_COND_B
|
||||
#define IF_BE DRCUML_COND_BE
|
||||
#define IF_G DRCUML_COND_G
|
||||
#define IF_GE DRCUML_COND_GE
|
||||
#define IF_L DRCUML_COND_L
|
||||
#define IF_LE DRCUML_COND_LE
|
||||
#define IF_ALWAYS DRCUML_COND_ALWAYS
|
||||
|
||||
/* shorthand for flags */
|
||||
#define FLAGS_ALLI (DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)
|
||||
#define FLAGS_ALLF (DRCUML_FLAG_C | DRCUML_FLAG_Z | DRCUML_FLAG_U)
|
||||
#define FLAGS_NONE (0)
|
||||
|
||||
/* flags needed for condition codes */
|
||||
#define FLAGS_Z (DRCUML_FLAG_Z)
|
||||
#define FLAGS_NZ (DRCUML_FLAG_Z)
|
||||
#define FLAGS_E (DRCUML_FLAG_Z)
|
||||
#define FLAGS_NE (DRCUML_FLAG_Z)
|
||||
#define FLAGS_S (DRCUML_FLAG_S)
|
||||
#define FLAGS_NS (DRCUML_FLAG_S)
|
||||
#define FLAGS_C (DRCUML_FLAG_C)
|
||||
#define FLAGS_NC (DRCUML_FLAG_C)
|
||||
#define FLAGS_V (DRCUML_FLAG_V)
|
||||
#define FLAGS_NV (DRCUML_FLAG_V)
|
||||
#define FLAGS_U (DRCUML_FLAG_U)
|
||||
#define FLAGS_NU (DRCUML_FLAG_U)
|
||||
#define FLAGS_A (DRCUML_FLAG_C | DRCUML_FLAG_Z)
|
||||
#define FLAGS_BE (DRCUML_FLAG_C | DRCUML_FLAG_Z)
|
||||
#define FLAGS_B (DRCUML_FLAG_C)
|
||||
#define FLAGS_AE (DRCUML_FLAG_C)
|
||||
#define FLAGS_G (DRCUML_FLAG_S | DRCUML_FLAG_V | DRCUML_FLAG_Z)
|
||||
#define FLAGS_LE (DRCUML_FLAG_S | DRCUML_FLAG_V | DRCUML_FLAG_Z)
|
||||
#define FLAGS_L (DRCUML_FLAG_S | DRCUML_FLAG_V)
|
||||
#define FLAGS_GE (DRCUML_FLAG_S | DRCUML_FLAG_V)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS
|
||||
***************************************************************************/
|
||||
|
||||
/* macros for wrapping parameters */
|
||||
#define NONE DRCUML_PTYPE_NONE, 0
|
||||
#define IMM(x) DRCUML_PTYPE_IMMEDIATE, (x)
|
||||
#define IREG(x) DRCUML_PTYPE_INT_REGISTER, (DRCUML_REG_I0 + (x))
|
||||
#define FREG(x) DRCUML_PTYPE_FLOAT_REGISTER, (DRCUML_REG_F0 + (x))
|
||||
#define MVAR(x) DRCUML_PTYPE_MAPVAR, (DRCUML_MAPVAR_M0 + (x))
|
||||
#define MEM(x) DRCUML_PTYPE_MEMORY, (FPTR)(x)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/* ----- Compile-time Opcodes ----- */
|
||||
#define UML_HANDLE(block, handle) do { drcuml_block_append_1(block, DRCUML_OP_HANDLE, 4, IF_ALWAYS, MEM(handle)); } while (0)
|
||||
#define UML_HASH(block, mode, pc) do { drcuml_block_append_2(block, DRCUML_OP_HASH, 4, IF_ALWAYS, IMM(mode), IMM(pc)); } while (0)
|
||||
#define UML_LABEL(block, label) do { drcuml_block_append_1(block, DRCUML_OP_LABEL, 4, IF_ALWAYS, IMM(label)); } while (0)
|
||||
#define UML_COMMENT/*(block, format, ...)*/ drcuml_add_comment
|
||||
#define UML_MAPVAR(block, mapvar, value) do { drcuml_block_append_2(block, DRCUML_OP_MAPVAR, 4, IF_ALWAYS, mapvar, IMM(value)); } while (0)
|
||||
|
||||
|
||||
/* ----- Control Flow Operations ----- */
|
||||
#define UML_DEBUG(block, pc) do { drcuml_block_append_1(block, DRCUML_OP_DEBUG, 4, IF_ALWAYS, pc); } while (0)
|
||||
|
||||
#define UML_EXIT(block, param) do { drcuml_block_append_1(block, DRCUML_OP_EXIT, 4, IF_ALWAYS, param); } while (0)
|
||||
#define UML_EXITc(block, cond, param) do { drcuml_block_append_1(block, DRCUML_OP_EXIT, 4, cond, param); } while (0)
|
||||
|
||||
#define UML_HASHJMP(block, mode, pc, handle) do { drcuml_block_append_3(block, DRCUML_OP_HASHJMP, 4, IF_ALWAYS, mode, pc, MEM(handle)); } while (0)
|
||||
|
||||
#define UML_JMP(block, label) do { drcuml_block_append_1(block, DRCUML_OP_JMP, 4, IF_ALWAYS, IMM(label)); } while (0)
|
||||
#define UML_JMPc(block, cond, label) do { drcuml_block_append_1(block, DRCUML_OP_JMP, 4, cond, IMM(label)); } while (0)
|
||||
|
||||
#define UML_JMPH(block, handle) do { drcuml_block_append_1(block, DRCUML_OP_JMPH, 4, IF_ALWAYS, MEM(handle)); } while (0)
|
||||
#define UML_JMPHc(block, cond, handle) do { drcuml_block_append_1(block, DRCUML_OP_JMPH, 4, cond, MEM(handle)); } while (0)
|
||||
#define UML_EXH(block, handle, param) do { drcuml_block_append_2(block, DRCUML_OP_EXH, 4, IF_ALWAYS, MEM(handle), param); } while (0)
|
||||
#define UML_EXHc(block, cond, handle, param) do { drcuml_block_append_2(block, DRCUML_OP_EXH, 4, cond, MEM(handle), param); } while (0)
|
||||
#define UML_CALLH(block, handle) do { drcuml_block_append_1(block, DRCUML_OP_CALLH, 4, IF_ALWAYS, MEM(handle)); } while (0)
|
||||
#define UML_CALLHc(block, cond, handle) do { drcuml_block_append_1(block, DRCUML_OP_CALLH, 4, cond, MEM(handle)); } while (0)
|
||||
#define UML_RET(block) do { drcuml_block_append_0(block, DRCUML_OP_RET, 4, IF_ALWAYS); } while (0)
|
||||
#define UML_RETc(block, cond) do { drcuml_block_append_0(block, DRCUML_OP_RET, 4, cond); } while (0)
|
||||
|
||||
#define UML_CALLC(block, func, ptr) do { drcuml_block_append_2(block, DRCUML_OP_CALLC, 4, IF_ALWAYS, MEM(func), MEM(ptr)); } while (0)
|
||||
#define UML_CALLCc(block, cond, func, ptr) do { drcuml_block_append_2(block, DRCUML_OP_CALLC, 4, cond, MEM(func), MEM(ptr)); } while (0)
|
||||
|
||||
#define UML_RECOVER(block, dst, mapvar) do { drcuml_block_append_2(block, DRCUML_OP_RECOVER, 4, IF_ALWAYS, dst, mapvar); } while (0)
|
||||
|
||||
|
||||
/* ----- Internal Register Operations ----- */
|
||||
#define UML_SETMODE(block, mode) do { drcuml_block_append_1(block, DRCUML_OP_SETMODE, 4, IF_ALWAYS, mode); } while (0)
|
||||
#define UML_GETMODE(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETMODE, 4, IF_ALWAYS, dst); } while (0)
|
||||
#define UML_SETFMOD(block, mode) do { drcuml_block_append_1(block, DRCUML_OP_SETFMOD, 4, IF_ALWAYS, mode); } while (0)
|
||||
#define UML_GETFMOD(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETFMOD, 4, IF_ALWAYS, dst); } while (0)
|
||||
#define UML_SUBICNT(block, delta, param) do { drcuml_block_append_2(block, DRCUML_OP_SUBICNT, 4, IF_ALWAYS, delta, param); } while (0)
|
||||
#define UML_GETEXP(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETEXP, 4, IF_ALWAYS, dst); } while (0)
|
||||
|
||||
|
||||
/* ----- 32-Bit Integer Operations ----- */
|
||||
#define UML_LOAD1U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_LOAD1S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1S, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_LOAD2U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_LOAD2S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2S, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_LOAD4(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
|
||||
#define UML_STORE1(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE1, 4, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
#define UML_STORE2(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE2, 4, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
#define UML_STORE4(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE4, 4, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
|
||||
#define UML_READ1U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_READ1S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1S, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_READ2U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_READ2S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2S, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_READ4(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_READ4M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ4M, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0)
|
||||
|
||||
#define UML_WRITE1(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE1, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_WRITE2(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE2, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_WRITE4(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE4, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_WRIT4M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT4M, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0)
|
||||
|
||||
#define UML_FLAGS(block, dst, mask, table) do { drcuml_block_append_3(block, DRCUML_OP_FLAGS, 4, IF_ALWAYS, dst, IMM(mask), MEM(table)); } while (0)
|
||||
|
||||
#define UML_MOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_MOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 4, cond, dst, src1); } while (0)
|
||||
|
||||
#define UML_ZEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT1, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_ZEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT2, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_SEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT1, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_SEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT2, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_NEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_NEGf(block, dst, src1, flags) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 4, flags, dst, src1); } while (0)
|
||||
|
||||
#define UML_ADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_ADD, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_ADDf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_ADD, 4, flags, dst, src1, src2); } while (0)
|
||||
#define UML_ADDC(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_ADDC, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_ADDCf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_ADDC, 4, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_SUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_SUB, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_SUBf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_SUB, 4, flags, dst, src1, src2); } while (0)
|
||||
#define UML_SUBB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_SUBB, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_SUBBf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_SUBB, 4, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_CMP(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_CMP, 4, FLAGS_ALLI, src1, src2); } while (0)
|
||||
#define UML_CMPf(block, src1, src2, flags) do { drcuml_block_append_2(block, DRCUML_OP_CMP, 4, flags, src1, src2); } while (0)
|
||||
|
||||
#define UML_MULU(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_MULU, 4, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_MULUf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_MULU, 4, flags, dst, edst, src1, src2); } while (0)
|
||||
#define UML_MULS(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_MULS, 4, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_MULSf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_MULS, 4, flags, dst, edst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DIVU(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_DIVU, 4, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DIVUf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_DIVU, 4, flags, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DIVS(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_DIVS, 4, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DIVSf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_DIVS, 4, flags, dst, edst, src1, src2); } while (0)
|
||||
|
||||
#define UML_AND(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_AND, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_ANDf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_AND, 4, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_TEST(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_TEST, 4, FLAGS_S|FLAGS_Z,src1, src2); } while (0)
|
||||
#define UML_TESTf(block, src1, src2, flags) do { drcuml_block_append_2(block, DRCUML_OP_TEST, 4, flags, src1, src2); } while (0)
|
||||
|
||||
#define UML_OR(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_OR, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_ORf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_OR, 4, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_XOR(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_XOR, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_XORf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_XOR, 4, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_SHL(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SHL, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_SHLf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SHL, 4, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_SHR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SHR, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_SHRf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SHR, 4, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_SAR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SAR, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_SARf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SAR, 4, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_ROL(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROL, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_ROLf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROL, 4, flags, dst, src, count); } while (0)
|
||||
#define UML_ROLC(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROLC, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_ROLCf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROLC, 4, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_ROR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROR, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_RORf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROR, 4, flags, dst, src, count); } while (0)
|
||||
#define UML_RORC(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_RORC, 4, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_RORCf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_RORC, 4, flags, dst, src, count); } while (0)
|
||||
|
||||
|
||||
/* ----- 64-Bit Integer Operations ----- */
|
||||
#define UML_DLOAD1U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD1S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD2U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD2S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD4U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD4S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_DLOAD8(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD8U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
|
||||
#define UML_DSTORE1(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE1, 8, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
#define UML_DSTORE2(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE2, 8, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
#define UML_DSTORE4(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE4, 8, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
#define UML_DSTORE8(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE8, 8, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
|
||||
#define UML_DREAD1U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD1S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD2U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD2S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD2M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ2M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0)
|
||||
#define UML_DREAD4U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD4S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD4M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ4M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0)
|
||||
#define UML_DREAD8(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ8U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_DREAD8M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ8M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0)
|
||||
|
||||
#define UML_DWRITE1(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE1, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_DWRITE2(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE2, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_DWRIT2M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT2M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0)
|
||||
#define UML_DWRITE4(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE4, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_DWRIT4M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT4M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0)
|
||||
#define UML_DWRITE8(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE8, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
#define UML_DWRIT8M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT8M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0)
|
||||
|
||||
#define UML_DFLAGS(block, dst, mask, table) do { drcuml_block_append_3(block, DRCUML_OP_FLAGS, 8, IF_ALWAYS, dst, IMM(mask), MEM(table)); } while (0)
|
||||
|
||||
#define UML_DMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_DMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 8, cond, dst, src1); } while (0)
|
||||
|
||||
#define UML_DZEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT1, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_DZEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT2, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_DZEXT4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT4, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_DSEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT1, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_DSEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT2, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_DSEXT4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT4, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_DNEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_DNEGf(block, dst, src1, flags) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 8, flags, dst, src1); } while (0)
|
||||
|
||||
#define UML_DADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_ADD, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DADDf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_ADD, 8, flags, dst, src1, src2); } while (0)
|
||||
#define UML_DADDC(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_ADDC, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DADDCf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_ADDC, 8, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DSUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_SUB, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DSUBf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_SUB, 8, flags, dst, src1, src2); } while (0)
|
||||
#define UML_DSUBB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_SUBB, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DSUBBf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_SUBB, 8, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DCMP(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_CMP, 8, FLAGS_ALLI, src1, src2); } while (0)
|
||||
#define UML_DCMPf(block, src1, src2, flags) do { drcuml_block_append_2(block, DRCUML_OP_CMP, 8, flags, src1, src2); } while (0)
|
||||
|
||||
#define UML_DMULU(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_MULU, 8, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DMULUf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_MULU, 8, flags, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DMULS(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_MULS, 8, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DMULSf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_MULS, 8, flags, dst, edst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DDIVU(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_DIVU, 8, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DDIVUf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_DIVU, 8, flags, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DDIVS(block, dst, edst, src1, src2) do { drcuml_block_append_4(block, DRCUML_OP_DIVS, 8, FLAGS_NONE, dst, edst, src1, src2); } while (0)
|
||||
#define UML_DDIVSf(block, dst, edst, src1, src2, flags) do { drcuml_block_append_4(block, DRCUML_OP_DIVS, 8, flags, dst, edst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DAND(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_AND, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DANDf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_AND, 8, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DTEST(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_TEST, 8, FLAGS_S|FLAGS_Z,src1, src2); } while (0)
|
||||
#define UML_DTESTf(block, src1, src2, flags) do { drcuml_block_append_2(block, DRCUML_OP_TEST, 8, flags, src1, src2); } while (0)
|
||||
|
||||
#define UML_DOR(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_OR, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DORf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_OR, 8, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DXOR(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_XOR, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_DXORf(block, dst, src1, src2, flags) do { drcuml_block_append_3(block, DRCUML_OP_XOR, 8, flags, dst, src1, src2); } while (0)
|
||||
|
||||
#define UML_DSHL(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SHL, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DSHLf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SHL, 8, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_DSHR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SHR, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DSHRf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SHR, 8, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_DSAR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_SAR, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DSARf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_SAR, 8, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_DROL(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROL, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DROLf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROL, 8, flags, dst, src, count); } while (0)
|
||||
#define UML_DROLC(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROLC, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DROLCf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROLC, 8, flags, dst, src, count); } while (0)
|
||||
|
||||
#define UML_DROR(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_ROR, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DRORf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_ROR, 8, flags, dst, src, count); } while (0)
|
||||
#define UML_DRORC(block, dst, src, count) do { drcuml_block_append_3(block, DRCUML_OP_RORC, 8, FLAGS_NONE, dst, src, count); } while (0)
|
||||
#define UML_DRORCf(block, dst, src, count, flags) do { drcuml_block_append_3(block, DRCUML_OP_RORC, 8, flags, dst, src, count); } while (0)
|
||||
|
||||
|
||||
/* ----- 32-bit Floating Point Arithmetic Operations ----- */
|
||||
#define UML_FSLOAD(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_FLOAD, 4, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_FSSTORE(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_FSTORE, 4, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
|
||||
#define UML_FSREAD(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_FSWRITE(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
|
||||
#define UML_FSMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 4, cond, dst, src1); } while (0)
|
||||
|
||||
#define UML_FSTOI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI4T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4T, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI4R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4R, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI4C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4C, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI4F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4F, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI8T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8T, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI8R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8R, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI8C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8C, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSTOI8F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8F, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_FSFRFD(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRFD, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSFRI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI4, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FSFRI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI8, 4, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_FSADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FADD, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FSSUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FSUB, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FSCMP(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_FCMP, 4, FLAGS_ALLF, src1, src2); } while (0)
|
||||
#define UML_FSMUL(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FMUL, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FSDIV(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FDIV, 4, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FSNEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FNEG, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FSABS(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FABS, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FSSQRT(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FSQRT, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FSRECIP(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FRECIP, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FSRSQRT(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FRSQRT, 4, FLAGS_NONE, dst, src1); } while (0)
|
||||
|
||||
|
||||
/* ----- 64-bit Floating Point Arithmetic Operations ----- */
|
||||
#define UML_FDLOAD(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_FLOAD, 8, IF_ALWAYS, dst, MEM(base), index); } while (0)
|
||||
#define UML_FDSTORE(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_FSTORE, 8, IF_ALWAYS, MEM(base), index, src1); } while (0)
|
||||
|
||||
#define UML_FDREAD(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0)
|
||||
#define UML_FDWRITE(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0)
|
||||
|
||||
#define UML_FDMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 8, cond, dst, src1); } while (0)
|
||||
|
||||
#define UML_FDTOI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI4T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4T, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI4R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4R, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI4C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4C, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI4F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4F, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI8T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8T, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI8R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8R, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI8C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8C, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDTOI8F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8F, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_FDFRFS(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRFS, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDFRI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI4, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
#define UML_FDFRI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI8, 8, IF_ALWAYS, dst, src1); } while (0)
|
||||
|
||||
#define UML_FDADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FADD, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FDSUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FSUB, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FDCMP(block, src1, src2) do { drcuml_block_append_2(block, DRCUML_OP_FCMP, 8, FLAGS_ALLF, src1, src2); } while (0)
|
||||
#define UML_FDMUL(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FMUL, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FDDIV(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FDIV, 8, FLAGS_NONE, dst, src1, src2); } while (0)
|
||||
#define UML_FDNEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FNEG, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FDABS(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FABS, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FDSQRT(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FSQRT, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FDRECIP(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FRECIP, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
#define UML_FDRSQRT(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FRSQRT, 8, FLAGS_NONE, dst, src1); } while (0)
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "debugger.h"
|
||||
#include "deprecat.h"
|
||||
#include "mips3com.h"
|
||||
|
||||
|
||||
@ -1779,12 +1780,12 @@ int mips3_execute(int cycles)
|
||||
break;
|
||||
case 0x20: /* ADD */
|
||||
if (ENABLE_OVERFLOWS && RSVAL32 > ~RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1);
|
||||
else RDVAL64 = (INT32)(RSVAL32 + RTVAL32);
|
||||
else if (RDREG) RDVAL64 = (INT32)(RSVAL32 + RTVAL32);
|
||||
break;
|
||||
case 0x21: /* ADDU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 + RTVAL32); break;
|
||||
case 0x22: /* SUB */
|
||||
if (ENABLE_OVERFLOWS && RSVAL32 < RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1);
|
||||
else RDVAL64 = (INT32)(RSVAL32 - RTVAL32);
|
||||
else if (RDREG) RDVAL64 = (INT32)(RSVAL32 - RTVAL32);
|
||||
break;
|
||||
case 0x23: /* SUBU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 - RTVAL32); break;
|
||||
case 0x24: /* AND */ if (RDREG) RDVAL64 = RSVAL64 & RTVAL64; break;
|
||||
@ -1795,12 +1796,12 @@ int mips3_execute(int cycles)
|
||||
case 0x2b: /* SLTU */ if (RDREG) RDVAL64 = (UINT64)RSVAL64 < (UINT64)RTVAL64; break;
|
||||
case 0x2c: /* DADD */
|
||||
if (ENABLE_OVERFLOWS && RSVAL64 > ~RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1);
|
||||
else RDVAL64 = RSVAL64 + RTVAL64;
|
||||
else if (RDREG) RDVAL64 = RSVAL64 + RTVAL64;
|
||||
break;
|
||||
case 0x2d: /* DADDU */ if (RDREG) RDVAL64 = RSVAL64 + RTVAL64; break;
|
||||
case 0x2e: /* DSUB */
|
||||
if (ENABLE_OVERFLOWS && RSVAL64 < RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1);
|
||||
else RDVAL64 = RSVAL64 - RTVAL64;
|
||||
else if (RDREG) RDVAL64 = RSVAL64 - RTVAL64;
|
||||
break;
|
||||
case 0x2f: /* DSUBU */ if (RDREG) RDVAL64 = RSVAL64 - RTVAL64; break;
|
||||
case 0x30: /* TGE */ if ((INT64)RSVAL64 >= (INT64)RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break;
|
||||
|
@ -54,37 +54,102 @@ enum
|
||||
MIPS3_HI,
|
||||
MIPS3_LO,
|
||||
MIPS3_FPR0,
|
||||
MIPS3_FPS0,
|
||||
MIPS3_FPD0,
|
||||
MIPS3_FPR1,
|
||||
MIPS3_FPS1,
|
||||
MIPS3_FPD1,
|
||||
MIPS3_FPR2,
|
||||
MIPS3_FPS2,
|
||||
MIPS3_FPD2,
|
||||
MIPS3_FPR3,
|
||||
MIPS3_FPS3,
|
||||
MIPS3_FPD3,
|
||||
MIPS3_FPR4,
|
||||
MIPS3_FPS4,
|
||||
MIPS3_FPD4,
|
||||
MIPS3_FPR5,
|
||||
MIPS3_FPS5,
|
||||
MIPS3_FPD5,
|
||||
MIPS3_FPR6,
|
||||
MIPS3_FPS6,
|
||||
MIPS3_FPD6,
|
||||
MIPS3_FPR7,
|
||||
MIPS3_FPS7,
|
||||
MIPS3_FPD7,
|
||||
MIPS3_FPR8,
|
||||
MIPS3_FPS8,
|
||||
MIPS3_FPD8,
|
||||
MIPS3_FPR9,
|
||||
MIPS3_FPS9,
|
||||
MIPS3_FPD9,
|
||||
MIPS3_FPR10,
|
||||
MIPS3_FPS10,
|
||||
MIPS3_FPD10,
|
||||
MIPS3_FPR11,
|
||||
MIPS3_FPS11,
|
||||
MIPS3_FPD11,
|
||||
MIPS3_FPR12,
|
||||
MIPS3_FPS12,
|
||||
MIPS3_FPD12,
|
||||
MIPS3_FPR13,
|
||||
MIPS3_FPS13,
|
||||
MIPS3_FPD13,
|
||||
MIPS3_FPR14,
|
||||
MIPS3_FPS14,
|
||||
MIPS3_FPD14,
|
||||
MIPS3_FPR15,
|
||||
MIPS3_FPS15,
|
||||
MIPS3_FPD15,
|
||||
MIPS3_FPR16,
|
||||
MIPS3_FPS16,
|
||||
MIPS3_FPD16,
|
||||
MIPS3_FPR17,
|
||||
MIPS3_FPS17,
|
||||
MIPS3_FPD17,
|
||||
MIPS3_FPR18,
|
||||
MIPS3_FPS18,
|
||||
MIPS3_FPD18,
|
||||
MIPS3_FPR19,
|
||||
MIPS3_FPS19,
|
||||
MIPS3_FPD19,
|
||||
MIPS3_FPR20,
|
||||
MIPS3_FPS20,
|
||||
MIPS3_FPD20,
|
||||
MIPS3_FPR21,
|
||||
MIPS3_FPS21,
|
||||
MIPS3_FPD21,
|
||||
MIPS3_FPR22,
|
||||
MIPS3_FPS22,
|
||||
MIPS3_FPD22,
|
||||
MIPS3_FPR23,
|
||||
MIPS3_FPS23,
|
||||
MIPS3_FPD23,
|
||||
MIPS3_FPR24,
|
||||
MIPS3_FPS24,
|
||||
MIPS3_FPD24,
|
||||
MIPS3_FPR25,
|
||||
MIPS3_FPS25,
|
||||
MIPS3_FPD25,
|
||||
MIPS3_FPR26,
|
||||
MIPS3_FPS26,
|
||||
MIPS3_FPD26,
|
||||
MIPS3_FPR27,
|
||||
MIPS3_FPS27,
|
||||
MIPS3_FPD27,
|
||||
MIPS3_FPR28,
|
||||
MIPS3_FPS28,
|
||||
MIPS3_FPD28,
|
||||
MIPS3_FPR29,
|
||||
MIPS3_FPS29,
|
||||
MIPS3_FPD29,
|
||||
MIPS3_FPR30,
|
||||
MIPS3_FPS30,
|
||||
MIPS3_FPD30,
|
||||
MIPS3_FPR31,
|
||||
MIPS3_FPS31,
|
||||
MIPS3_FPD31,
|
||||
MIPS3_CCR1_31,
|
||||
MIPS3_SR,
|
||||
MIPS3_EPC,
|
||||
MIPS3_CAUSE,
|
||||
|
@ -171,12 +171,14 @@ void mips3com_update_cycle_counting(mips3_state *mips)
|
||||
{
|
||||
UINT32 count = (activecpu_gettotalcycles() - mips->count_zero_time) / 2;
|
||||
UINT32 compare = mips->cpr[0][COP0_Compare];
|
||||
UINT32 cyclesleft = compare - count;
|
||||
attotime newtime = ATTOTIME_IN_CYCLES(((INT64)cyclesleft * 2), cpu_getactivecpu());
|
||||
timer_adjust_oneshot(mips->compare_int_timer, newtime, cpu_getactivecpu());
|
||||
if (compare > count)
|
||||
{
|
||||
attotime newtime = ATTOTIME_IN_CYCLES(((INT64)(compare - count) * 2), cpu_getactivecpu());
|
||||
timer_adjust_oneshot(mips->compare_int_timer, newtime, cpu_getactivecpu());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
timer_adjust_oneshot(mips->compare_int_timer, attotime_never, cpu_getactivecpu());
|
||||
timer_adjust_oneshot(mips->compare_int_timer, attotime_never, cpu_getactivecpu());
|
||||
}
|
||||
|
||||
|
||||
@ -665,38 +667,104 @@ void mips3com_get_info(mips3_state *mips, UINT32 state, cpuinfo *info)
|
||||
case CPUINFO_STR_REGISTER + MIPS3_HI: sprintf(info->s, "HI: %08X%08X", (UINT32)(mips->r[REG_HI] >> 32), (UINT32)mips->r[REG_HI]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_LO: sprintf(info->s, "LO: %08X%08X", (UINT32)(mips->r[REG_LO] >> 32), (UINT32)mips->r[REG_LO]); break;
|
||||
|
||||
case CPUINFO_STR_REGISTER + MIPS3_CCR1_31: sprintf(info->s, "CCR31:%08X", (UINT32)mips->ccr[1][0]); break;
|
||||
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR0: sprintf(info->s, "FPR0: %08X%08X", (UINT32)(mips->cpr[1][0] >> 32), (UINT32)mips->cpr[1][0]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS0: sprintf(info->s, "FPS0: !%16g", *(float *)&mips->cpr[1][0]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD0: sprintf(info->s, "FPD0: !%16g", *(double *)&mips->cpr[1][0]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR1: sprintf(info->s, "FPR1: %08X%08X", (UINT32)(mips->cpr[1][1] >> 32), (UINT32)mips->cpr[1][1]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS1: sprintf(info->s, "FPS1: !%16g", *(float *)&mips->cpr[1][1]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD1: sprintf(info->s, "FPD1: !%16g", *(double *)&mips->cpr[1][1]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR2: sprintf(info->s, "FPR2: %08X%08X", (UINT32)(mips->cpr[1][2] >> 32), (UINT32)mips->cpr[1][2]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS2: sprintf(info->s, "FPS2: !%16g", *(float *)&mips->cpr[1][2]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD2: sprintf(info->s, "FPD2: !%16g", *(double *)&mips->cpr[1][2]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR3: sprintf(info->s, "FPR3: %08X%08X", (UINT32)(mips->cpr[1][3] >> 32), (UINT32)mips->cpr[1][3]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS3: sprintf(info->s, "FPS3: !%16g", *(float *)&mips->cpr[1][3]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD3: sprintf(info->s, "FPD3: !%16g", *(double *)&mips->cpr[1][3]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR4: sprintf(info->s, "FPR4: %08X%08X", (UINT32)(mips->cpr[1][4] >> 32), (UINT32)mips->cpr[1][4]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS4: sprintf(info->s, "FPS4: !%16g", *(float *)&mips->cpr[1][4]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD4: sprintf(info->s, "FPD4: !%16g", *(double *)&mips->cpr[1][4]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR5: sprintf(info->s, "FPR5: %08X%08X", (UINT32)(mips->cpr[1][5] >> 32), (UINT32)mips->cpr[1][5]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS5: sprintf(info->s, "FPS5: !%16g", *(float *)&mips->cpr[1][5]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD5: sprintf(info->s, "FPD5: !%16g", *(double *)&mips->cpr[1][5]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR6: sprintf(info->s, "FPR6: %08X%08X", (UINT32)(mips->cpr[1][6] >> 32), (UINT32)mips->cpr[1][6]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS6: sprintf(info->s, "FPS6: !%16g", *(float *)&mips->cpr[1][6]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD6: sprintf(info->s, "FPD6: !%16g", *(double *)&mips->cpr[1][6]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR7: sprintf(info->s, "FPR7: %08X%08X", (UINT32)(mips->cpr[1][7] >> 32), (UINT32)mips->cpr[1][7]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS7: sprintf(info->s, "FPS7: !%16g", *(float *)&mips->cpr[1][7]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD7: sprintf(info->s, "FPD7: !%16g", *(double *)&mips->cpr[1][7]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR8: sprintf(info->s, "FPR8: %08X%08X", (UINT32)(mips->cpr[1][8] >> 32), (UINT32)mips->cpr[1][8]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS8: sprintf(info->s, "FPS8: !%16g", *(float *)&mips->cpr[1][8]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD8: sprintf(info->s, "FPD8: !%16g", *(double *)&mips->cpr[1][8]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR9: sprintf(info->s, "FPR9: %08X%08X", (UINT32)(mips->cpr[1][9] >> 32), (UINT32)mips->cpr[1][9]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS9: sprintf(info->s, "FPS9: !%16g", *(float *)&mips->cpr[1][9]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD9: sprintf(info->s, "FPD9: !%16g", *(double *)&mips->cpr[1][9]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR10: sprintf(info->s, "FPR10:%08X%08X", (UINT32)(mips->cpr[1][10] >> 32), (UINT32)mips->cpr[1][10]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS10: sprintf(info->s, "FPS10:!%16g", *(float *)&mips->cpr[1][10]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD10: sprintf(info->s, "FPD10:!%16g", *(double *)&mips->cpr[1][10]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR11: sprintf(info->s, "FPR11:%08X%08X", (UINT32)(mips->cpr[1][11] >> 32), (UINT32)mips->cpr[1][11]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS11: sprintf(info->s, "FPS11:!%16g", *(float *)&mips->cpr[1][11]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD11: sprintf(info->s, "FPD11:!%16g", *(double *)&mips->cpr[1][11]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR12: sprintf(info->s, "FPR12:%08X%08X", (UINT32)(mips->cpr[1][12] >> 32), (UINT32)mips->cpr[1][12]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS12: sprintf(info->s, "FPS12:!%16g", *(float *)&mips->cpr[1][12]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD12: sprintf(info->s, "FPD12:!%16g", *(double *)&mips->cpr[1][12]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR13: sprintf(info->s, "FPR13:%08X%08X", (UINT32)(mips->cpr[1][13] >> 32), (UINT32)mips->cpr[1][13]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS13: sprintf(info->s, "FPS13:!%16g", *(float *)&mips->cpr[1][13]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD13: sprintf(info->s, "FPD13:!%16g", *(double *)&mips->cpr[1][13]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR14: sprintf(info->s, "FPR14:%08X%08X", (UINT32)(mips->cpr[1][14] >> 32), (UINT32)mips->cpr[1][14]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS14: sprintf(info->s, "FPS14:!%16g", *(float *)&mips->cpr[1][14]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD14: sprintf(info->s, "FPD14:!%16g", *(double *)&mips->cpr[1][14]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR15: sprintf(info->s, "FPR15:%08X%08X", (UINT32)(mips->cpr[1][15] >> 32), (UINT32)mips->cpr[1][15]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS15: sprintf(info->s, "FPS15:!%16g", *(float *)&mips->cpr[1][15]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD15: sprintf(info->s, "FPD15:!%16g", *(double *)&mips->cpr[1][15]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR16: sprintf(info->s, "FPR16:%08X%08X", (UINT32)(mips->cpr[1][16] >> 32), (UINT32)mips->cpr[1][16]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS16: sprintf(info->s, "FPS16:!%16g", *(float *)&mips->cpr[1][16]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD16: sprintf(info->s, "FPD16:!%16g", *(double *)&mips->cpr[1][16]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR17: sprintf(info->s, "FPR17:%08X%08X", (UINT32)(mips->cpr[1][17] >> 32), (UINT32)mips->cpr[1][17]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS17: sprintf(info->s, "FPS17:!%16g", *(float *)&mips->cpr[1][17]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD17: sprintf(info->s, "FPD17:!%16g", *(double *)&mips->cpr[1][17]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR18: sprintf(info->s, "FPR18:%08X%08X", (UINT32)(mips->cpr[1][18] >> 32), (UINT32)mips->cpr[1][18]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS18: sprintf(info->s, "FPS18:!%16g", *(float *)&mips->cpr[1][18]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD18: sprintf(info->s, "FPD18:!%16g", *(double *)&mips->cpr[1][18]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR19: sprintf(info->s, "FPR19:%08X%08X", (UINT32)(mips->cpr[1][19] >> 32), (UINT32)mips->cpr[1][19]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS19: sprintf(info->s, "FPS19:!%16g", *(float *)&mips->cpr[1][19]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD19: sprintf(info->s, "FPD19:!%16g", *(double *)&mips->cpr[1][19]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR20: sprintf(info->s, "FPR20:%08X%08X", (UINT32)(mips->cpr[1][20] >> 32), (UINT32)mips->cpr[1][20]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS20: sprintf(info->s, "FPS20:!%16g", *(float *)&mips->cpr[1][20]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD20: sprintf(info->s, "FPD20:!%16g", *(double *)&mips->cpr[1][20]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR21: sprintf(info->s, "FPR21:%08X%08X", (UINT32)(mips->cpr[1][21] >> 32), (UINT32)mips->cpr[1][21]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS21: sprintf(info->s, "FPS21:!%16g", *(float *)&mips->cpr[1][21]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD21: sprintf(info->s, "FPD21:!%16g", *(double *)&mips->cpr[1][21]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR22: sprintf(info->s, "FPR22:%08X%08X", (UINT32)(mips->cpr[1][22] >> 32), (UINT32)mips->cpr[1][22]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS22: sprintf(info->s, "FPS22:!%16g", *(float *)&mips->cpr[1][22]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD22: sprintf(info->s, "FPD22:!%16g", *(double *)&mips->cpr[1][22]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR23: sprintf(info->s, "FPR23:%08X%08X", (UINT32)(mips->cpr[1][23] >> 32), (UINT32)mips->cpr[1][23]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS23: sprintf(info->s, "FPS23:!%16g", *(float *)&mips->cpr[1][23]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD23: sprintf(info->s, "FPD23:!%16g", *(double *)&mips->cpr[1][23]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR24: sprintf(info->s, "FPR24:%08X%08X", (UINT32)(mips->cpr[1][24] >> 32), (UINT32)mips->cpr[1][24]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS24: sprintf(info->s, "FPS24:!%16g", *(float *)&mips->cpr[1][24]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD24: sprintf(info->s, "FPD24:!%16g", *(double *)&mips->cpr[1][24]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR25: sprintf(info->s, "FPR25:%08X%08X", (UINT32)(mips->cpr[1][25] >> 32), (UINT32)mips->cpr[1][25]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS25: sprintf(info->s, "FPS25:!%16g", *(float *)&mips->cpr[1][25]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD25: sprintf(info->s, "FPD25:!%16g", *(double *)&mips->cpr[1][25]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR26: sprintf(info->s, "FPR26:%08X%08X", (UINT32)(mips->cpr[1][26] >> 32), (UINT32)mips->cpr[1][26]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS26: sprintf(info->s, "FPS26:!%16g", *(float *)&mips->cpr[1][26]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD26: sprintf(info->s, "FPD26:!%16g", *(double *)&mips->cpr[1][26]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR27: sprintf(info->s, "FPR27:%08X%08X", (UINT32)(mips->cpr[1][27] >> 32), (UINT32)mips->cpr[1][27]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS27: sprintf(info->s, "FPS27:!%16g", *(float *)&mips->cpr[1][27]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD27: sprintf(info->s, "FPD27:!%16g", *(double *)&mips->cpr[1][27]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR28: sprintf(info->s, "FPR28:%08X%08X", (UINT32)(mips->cpr[1][28] >> 32), (UINT32)mips->cpr[1][28]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS28: sprintf(info->s, "FPS28:!%16g", *(float *)&mips->cpr[1][28]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD28: sprintf(info->s, "FPD28:!%16g", *(double *)&mips->cpr[1][28]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR29: sprintf(info->s, "FPR29:%08X%08X", (UINT32)(mips->cpr[1][29] >> 32), (UINT32)mips->cpr[1][29]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS29: sprintf(info->s, "FPS29:!%16g", *(float *)&mips->cpr[1][29]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD29: sprintf(info->s, "FPD29:!%16g", *(double *)&mips->cpr[1][29]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR30: sprintf(info->s, "FPR30:%08X%08X", (UINT32)(mips->cpr[1][30] >> 32), (UINT32)mips->cpr[1][30]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS30: sprintf(info->s, "FPS30:!%16g", *(float *)&mips->cpr[1][30]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD30: sprintf(info->s, "FPD30:!%16g", *(double *)&mips->cpr[1][30]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPR31: sprintf(info->s, "FPR31:%08X%08X", (UINT32)(mips->cpr[1][31] >> 32), (UINT32)mips->cpr[1][31]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPS31: sprintf(info->s, "FPS31:!%16g", *(float *)&mips->cpr[1][31]); break;
|
||||
case CPUINFO_STR_REGISTER + MIPS3_FPD31: sprintf(info->s, "FPD31:!%16g", *(double *)&mips->cpr[1][31]); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -353,7 +353,7 @@ unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op)
|
||||
sprintf(buffer, "nop");
|
||||
else
|
||||
sprintf(buffer, "sll %s,%s,%d", reg[rd], reg[rt], shift); break;
|
||||
case 0x01: sprintf(buffer, "mov%c %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', reg[rd], reg[rt], (op >> 18) & 7); break;
|
||||
case 0x01: sprintf(buffer, "mov%c %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', reg[rd], reg[rs], (op >> 18) & 7); break;
|
||||
case 0x02: sprintf(buffer, "srl %s,%s,%d", reg[rd], reg[rt], shift); break;
|
||||
case 0x03: sprintf(buffer, "sra %s,%s,%d", reg[rd], reg[rt], shift); break;
|
||||
case 0x04: sprintf(buffer, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break;
|
||||
|
@ -5,7 +5,7 @@
|
||||
Front-end for MIPS3 recompiler
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general use under the MAME license
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
@ -465,6 +465,13 @@ static int describe_instruction_cop0(mips3_state *mips, UINT32 op, opcode_desc *
|
||||
{
|
||||
case 0x00: /* MFCz */
|
||||
case 0x01: /* DMFCz */
|
||||
if (RDREG == COP0_Count)
|
||||
desc->cycles += MIPS3_COUNT_READ_CYCLES;
|
||||
if (RDREG == COP0_Cause)
|
||||
desc->cycles += MIPS3_CAUSE_READ_CYCLES;
|
||||
desc->gpr.modified |= REGFLAG_R(RTREG);
|
||||
return TRUE;
|
||||
|
||||
case 0x02: /* CFCz */
|
||||
desc->gpr.modified |= REGFLAG_R(RTREG);
|
||||
return TRUE;
|
||||
|
@ -5,7 +5,7 @@
|
||||
Front-end for MIPS3 recompiler
|
||||
|
||||
Copyright Aaron Giles
|
||||
Released for general use under the MAME license
|
||||
Released for general non-commercial use under the MAME license
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
|
||||
***************************************************************************/
|
||||
|
@ -7,6 +7,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "debugger.h"
|
||||
#include "deprecat.h"
|
||||
#include "r3000.h"
|
||||
|
||||
|
||||
|
@ -1608,6 +1608,25 @@ INLINE void emit_jecxz(x86code **emitptr, x86code *target)
|
||||
resolve_link(&target, &link);
|
||||
}
|
||||
|
||||
#ifdef PTR64
|
||||
|
||||
INLINE void emit_jrcxz_link(x86code **emitptr, emit_link *linkinfo)
|
||||
{
|
||||
emit_op_simple(emitptr, OP_JrCXZ_Jb, OP_64BIT);
|
||||
emit_byte(emitptr, 0);
|
||||
linkinfo->target = *emitptr;
|
||||
linkinfo->size = 1;
|
||||
}
|
||||
|
||||
INLINE void emit_jrcxz(x86code **emitptr, x86code *target)
|
||||
{
|
||||
emit_link link;
|
||||
emit_jrcxz_link(emitptr, &link);
|
||||
resolve_link(&target, &link);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
emit_call/jmp_*
|
||||
@ -2753,6 +2772,26 @@ INLINE void emit_stmxcsr_m32(x86code **emitptr, DECLARE_MEMPARAMS) { emit_op_mod
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MISC SSE EMITTERS
|
||||
***************************************************************************/
|
||||
|
||||
INLINE void emit_movd_r128_r32(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Vd_Ed, OP_32BIT, dreg, sreg); }
|
||||
INLINE void emit_movd_r128_m32(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVD_Vd_Ed, OP_32BIT, dreg, MEMPARAMS); }
|
||||
INLINE void emit_movd_r32_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Ed_Vd, OP_32BIT, sreg, dreg); }
|
||||
INLINE void emit_movd_m32_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVD_Ed_Vd, OP_32BIT, sreg, MEMPARAMS); }
|
||||
|
||||
#ifdef PTR64
|
||||
|
||||
INLINE void emit_movq_r128_r64(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Vd_Ed, OP_64BIT, dreg, sreg); }
|
||||
INLINE void emit_movq_r128_m64(x86code **emitptr, UINT8 dreg, DECLARE_MEMPARAMS) { emit_op_modrm_mem(emitptr, OP_MOVD_Vd_Ed, OP_64BIT, dreg, MEMPARAMS); }
|
||||
INLINE void emit_movq_r64_r128(x86code **emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Ed_Vd, OP_64BIT, sreg, dreg); }
|
||||
INLINE void emit_movq_m64_r128(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVD_Ed_Vd, OP_64BIT, sreg, MEMPARAMS); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
SSE SCALAR SINGLE EMITTERS
|
||||
***************************************************************************/
|
||||
|
@ -3686,7 +3686,7 @@ static void voodoo_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mas
|
||||
}
|
||||
|
||||
/* modify the offset based on the mem_mask */
|
||||
if (mem_mask)
|
||||
if (mem_mask != 0xffffffff)
|
||||
{
|
||||
if (!ACCESSING_BITS_16_31)
|
||||
offset |= 0x80000000;
|
||||
@ -3860,6 +3860,9 @@ static UINT32 register_r(voodoo_state *v, offs_t offset)
|
||||
|
||||
/* return the current scanline for now */
|
||||
case vRetrace:
|
||||
|
||||
/* eat some cycles since people like polling here */
|
||||
activecpu_eat_cycles(10);
|
||||
result = video_screen_get_vpos(v->screen);
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user